CIImage (TIFFRepresentation) memory leak
-
Hi,
I'm applying a Core Image filter to an image in a NSImageView
subclass. The drawing works fine, except it leaks memory, not sure
why. This is my drawRect method. Anything wrong with it? Thanks.
- (void) drawRect:(NSRect)rect
{
[[self image] setFlipped:YES];
CIImage *image = [CIImage imageWithData:[[self image] TIFFRepresentation]];
if (image !=nil) {
CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
[filter setDefaults];
[filter setValue: image forKey: @"inputImage"];
[filter setValue: [NSNumber numberWithFloat:0.7] forKey: @"inputRadius"];
image = [filter valueForKey: @"outputImage"];
filter = [CIFilter filterWithName:@"CIPerspectiveTransform"];
[filter setDefaults];
[filter setValue: image forKey: @"inputImage"];
[filter setValue:[CIVector vectorWithX:NSMinX(rect) Y:NSMinY(rect) +
bLeft ] forKey:@"inputBottomLeft"];
[filter setValue:[CIVector vectorWithX:NSMaxX(rect) Y:NSMinY(rect) +
bRight ] forKey:@"inputBottomRight"];
[filter setValue:[CIVector vectorWithX:NSMinX(rect) Y:NSMaxY(rect) +
tLeft ] forKey:@"inputTopLeft"];
[filter setValue:[CIVector vectorWithX:NSMaxX(rect) Y:NSMaxY(rect) +
tRight ] forKey:@"inputTopRight"];
image = [filter valueForKey: @"outputImage"];
CGRect cg;
CIContext *context = [[NSGraphicsContext currentContext] CIContext];
cg = CGRectMake(NSMinX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect));
[context drawImage:image
atPoint:cg.origin
fromRect:cg];
}
} -
I narrowed this down by removing the filters, and the leak is still
there. And what a leak! Everytime I draw the view the memory usage
increases with the size of the drawn image. Yet this exact same code
is used in the Core Image Programming Guide. So I figure it's a bug in
Core Image. But how can I avoid it?
- (void) drawRect:(NSRect)rect
{
CIImage *image = [CIImage imageWithData:[[self image]
TIFFRepresentation]];
if (image !=nil) {
CGRect cg;
CIContext *context = [[NSGraphicsContext
currentContext] CIContext];
cg = CGRectMake(NSMinX(rect), NSMinY(rect),
NSWidth(rect), NSHeight(rect));
[context drawImage:image
atPoint:cg.origin
fromRect:cg];
}
}
On Mon, Mar 10, 2008 at 5:33 PM, <slasktrattenator...> wrote:
> Hi,
>
> I'm applying a Core Image filter to an image in a NSImageView
> subclass. The drawing works fine, except it leaks memory, not sure
> why. This is my drawRect method. Anything wrong with it? Thanks.
>
>
> - (void) drawRect:(NSRect)rect
> {
>
> [[self image] setFlipped:YES];
> CIImage *image = [CIImage imageWithData:[[self image] TIFFRepresentation]];
> if (image !=nil) {
> CIFilter *filter = [CIFilter filterWithName:@"CIGaussianBlur"];
> [filter setDefaults];
> [filter setValue: image forKey: @"inputImage"];
> [filter setValue: [NSNumber numberWithFloat:0.7] forKey: @"inputRadius"];
> image = [filter valueForKey: @"outputImage"];
>
> filter = [CIFilter filterWithName:@"CIPerspectiveTransform"];
> [filter setDefaults];
> [filter setValue: image forKey: @"inputImage"];
> [filter setValue:[CIVector vectorWithX:NSMinX(rect) Y:NSMinY(rect) +
> bLeft ] forKey:@"inputBottomLeft"];
> [filter setValue:[CIVector vectorWithX:NSMaxX(rect) Y:NSMinY(rect) +
> bRight ] forKey:@"inputBottomRight"];
> [filter setValue:[CIVector vectorWithX:NSMinX(rect) Y:NSMaxY(rect) +
> tLeft ] forKey:@"inputTopLeft"];
> [filter setValue:[CIVector vectorWithX:NSMaxX(rect) Y:NSMaxY(rect) +
> tRight ] forKey:@"inputTopRight"];
> image = [filter valueForKey: @"outputImage"];
>
> CGRect cg;
> CIContext *context = [[NSGraphicsContext currentContext] CIContext];
> cg = CGRectMake(NSMinX(rect), NSMinY(rect), NSWidth(rect), NSHeight(rect));
> [context drawImage:image
> atPoint:cg.origin
> fromRect:cg];
>
> }
> }
>
-
If all the code you're using is present, it looks to me like you're not releasing the object pointed at by image; the object returned by imageWithData is not an auto-released object.
> I narrowed this down by removing the filters, and the leak is still
> there. And what a leak! Everytime I draw the view the memory usage
> increases with the size of the drawn image. Yet this exact same code
> is used in the Core Image Programming Guide. So I figure it's a bug in
> Core Image. But how can I avoid it?
>
>
> - (void) drawRect:(NSRect)rect
> {
> CIImage *image = [CIImage imageWithData:[[self image]
> TIFFRepresentation]];
> if (image !=nil) {
>
> CGRect cg;
> CIContext *context = [[NSGraphicsContext
> currentContext] CIContext];
> cg = CGRectMake(NSMinX(rect), NSMinY(rect),
> NSWidth(rect), NSHeight(rect));
> [context drawImage:image
> atPoint:cg.origin
> fromRect:cg];
>
> }
> }
>
> On Mon, Mar 10, 2008 at 5:33 PM, <slasktrattenator...> wrote:
>> Hi,
>>
>> I'm applying a Core Image filter to an image in a NSImageView
>> subclass. The drawing works fine, except it leaks memory, not sure
>> why. This is my drawRect method. Anything wrong with it? Thanks.
>>
>>
>> - (void) drawRect:(NSRect)rect
>> {
>>
>> [[self image] setFlipped:YES];
>> CIImage *image = [CIImage imageWithData:[[self image]
> TIFFRepresentation]];
>> if (image !=nil) {
>> CIFilter *filter = [CIFilter
> filterWithName:@"CIGaussianBlur"];
>> [filter setDefaults];
>> [filter setValue: image forKey: @"inputImage"];
>> [filter setValue: [NSNumber numberWithFloat:0.7] forKey:
> @"inputRadius"];
>> image = [filter valueForKey: @"outputImage"];
>>
>> filter = [CIFilter
> filterWithName:@"CIPerspectiveTransform"];
>> [filter setDefaults];
>> [filter setValue: image forKey: @"inputImage"];
>> [filter setValue:[CIVector vectorWithX:NSMinX(rect)
> Y:NSMinY(rect) +
>> bLeft ] forKey:@"inputBottomLeft"];
>> [filter setValue:[CIVector vectorWithX:NSMaxX(rect)
> Y:NSMinY(rect) +
>> bRight ] forKey:@"inputBottomRight"];
>> [filter setValue:[CIVector vectorWithX:NSMinX(rect)
> Y:NSMaxY(rect) +
>> tLeft ] forKey:@"inputTopLeft"];
>> [filter setValue:[CIVector vectorWithX:NSMaxX(rect)
> Y:NSMaxY(rect) +
>> tRight ] forKey:@"inputTopRight"];
>> image = [filter valueForKey: @"outputImage"];
>>
>> CGRect cg;
>> CIContext *context = [[NSGraphicsContext currentContext]
> CIContext];
>> cg = CGRectMake(NSMinX(rect), NSMinY(rect), NSWidth(rect),
> NSHeight(rect));
>> [context drawImage:image
>> atPoint:cg.origin
>> fromRect:cg];
>>
>> }
>> }
>>
-
On Mar 10, 2008, at 1:21 PM, Gary L. Wade wrote:
> If all the code you're using is present, it looks to me like you're
> not releasing the object pointed at by image; the object returned by
> imageWithData is not an auto-released object.
It's not? Why not? I thought convenience methods like that did not
transfer ownership to the caller. Isn't the convention that the method
should say alloc, new or copy to signify the granting of ownership?
--Brady -
Oh really? Hm... *looks away in shame*. That makes me feel kind of
stupid. I was under the impression it was an autoreleased object as
there is no "init", "copy" or "new" in it's name, and the docs don't
mention anything about the user being responsible for releasing it.
How are you supposed to know this?
Anyway, releasing the object seems to get rid of the leak, but after
releasing it I cannot get the view to update it's content. I set a new
image in the view, I can see the drawRect method is being called, the
new CIImage is being created, but it's not being drawn, the view just
keeps showing the first image... :-/
What am I missing?
On Mon, Mar 10, 2008 at 9:21 PM, Gary L. Wade
<garywade...> wrote:
> If all the code you're using is present, it looks to me like you're not releasing the object pointed at by image; the object returned by imageWithData is not an auto-released object.
>
>
>
>> I narrowed this down by removing the filters, and the leak is still
>> there. And what a leak! Everytime I draw the view the memory usage
>> increases with the size of the drawn image. Yet this exact same code
>> is used in the Core Image Programming Guide. So I figure it's a bug in
>> Core Image. But how can I avoid it?
>>
>>
>> - (void) drawRect:(NSRect)rect
>> {
>> CIImage *image = [CIImage imageWithData:[[self image]
>> TIFFRepresentation]];
>> if (image !=nil) {
>>
>> CGRect cg;
>> CIContext *context = [[NSGraphicsContext
>> currentContext] CIContext];
>> cg = CGRectMake(NSMinX(rect), NSMinY(rect),
>> NSWidth(rect), NSHeight(rect));
>> [context drawImage:image
>> atPoint:cg.origin
>> fromRect:cg];
>>
>> }
>> }
>>
>> On Mon, Mar 10, 2008 at 5:33 PM, <slasktrattenator...> wrote:
>>> Hi,
>>>
>>> I'm applying a Core Image filter to an image in a NSImageView
>>> subclass. The drawing works fine, except it leaks memory, not sure
>>> why. This is my drawRect method. Anything wrong with it? Thanks.
>>>
>>>
>>> - (void) drawRect:(NSRect)rect
>>> {
>>>
>>> [[self image] setFlipped:YES];
>>> CIImage *image = [CIImage imageWithData:[[self image]
>> TIFFRepresentation]];
>>> if (image !=nil) {
>>> CIFilter *filter = [CIFilter
>> filterWithName:@"CIGaussianBlur"];
>>> [filter setDefaults];
>>> [filter setValue: image forKey: @"inputImage"];
>>> [filter setValue: [NSNumber numberWithFloat:0.7] forKey:
>> @"inputRadius"];
>>> image = [filter valueForKey: @"outputImage"];
>>>
>>> filter = [CIFilter
>> filterWithName:@"CIPerspectiveTransform"];
>>> [filter setDefaults];
>>> [filter setValue: image forKey: @"inputImage"];
>>> [filter setValue:[CIVector vectorWithX:NSMinX(rect)
>> Y:NSMinY(rect) +
>>> bLeft ] forKey:@"inputBottomLeft"];
>>> [filter setValue:[CIVector vectorWithX:NSMaxX(rect)
>> Y:NSMinY(rect) +
>>> bRight ] forKey:@"inputBottomRight"];
>>> [filter setValue:[CIVector vectorWithX:NSMinX(rect)
>> Y:NSMaxY(rect) +
>>> tLeft ] forKey:@"inputTopLeft"];
>>> [filter setValue:[CIVector vectorWithX:NSMaxX(rect)
>> Y:NSMaxY(rect) +
>>> tRight ] forKey:@"inputTopRight"];
>>> image = [filter valueForKey: @"outputImage"];
>>>
>>> CGRect cg;
>>> CIContext *context = [[NSGraphicsContext currentContext]
>> CIContext];
>>> cg = CGRectMake(NSMinX(rect), NSMinY(rect), NSWidth(rect),
>> NSHeight(rect));
>>> [context drawImage:image
>>> atPoint:cg.origin
>>> fromRect:cg];
>>>
>>> }
>>> }
>>>
>
-
"If all the code you're using is present, it looks to
me like you're not releasing the object pointed at by
image; the object returned by imageWithData is not an
auto-released object."
I just checked documentation
(http://developer.apple.com/documentation/GraphicsImaging/Reference/QuartzCo
reFramework/Classes/CIImage_Class/Reference/Reference.html#//apple_ref/occ/
clm/CIImage/imageWithData:)
and it does not mention that a convenience method
+imageWithData: would return a retained object. And
there is -initWithData: which I think implies that as
with other Cocoa and similar frameworks based on ObjC
+somethingWithSometingOther: returns an autoreleased
instance while -initWithSomethingOther: is an
initializer returning non-autoreleased instance. If
this is different for CIImage it should be mentioned
in the docs.
Gorazd
Looking for the perfect gift? Give the gift of Flickr!
http://www.flickr.com/gift/ -
On 11/03/2008, at 6:03 AM, <slasktrattenator...> wrote:
> I narrowed this down by removing the filters, and the leak is still
> there. And what a leak! Everytime I draw the view the memory usage
> increases with the size of the drawn image. Yet this exact same code
> is used in the Core Image Programming Guide. So I figure it's a bug in
> Core Image. But how can I avoid it?
I had problems with this too, and I use a workaround I found somewhere
where you render to a CGImageRef in the context of the current window.
Here's a dump of the code:
//theImage is an existing NSImage
CIImage *outputImage = [CIImage imageWithData:[theImage
TIFFRepresentation]];
//to draw the image processed by Core Image, we need to draw into an
on-screen graphics context
//this works around a bug in CIImage where drawing in off-screen
graphics contexts causes a huge memory leak
//get the current window's graphics context so that we have an on-
screen context
//usually we would use any view's window but generically you can just
ask for the main window
CIContext *ciContext = [[[NSApp mainWindow] graphicsContext] CIContext];
if(ciContext == nil)
{
NSLog(@"The CIContext of the main window could not be accessed.
Bailing out of the image creation process.");
return;
}
CGAffineTransform transform;
transform = CGAffineTransformMakeTranslation(0.0,[outputImage
extent].size.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
outputImage = [outputImage imageByApplyingTransform:transform];
//render the CIIimage into a CGImageRef in the on-screen context
CGImageRef cgImage = [ciContext createCGImage:outputImage fromRect:
[outputImage extent]];
// Draw the CGImageRef into the current context
if (cgImage != NULL)
{
CGContextDrawImage ([[NSGraphicsContext currentContext]
graphicsPort], [outputImage extent], cgImage);
CGImageRelease (cgImage);
}
HTH
--
Rob Keniger -
Thanks a bunch! That worked great. No more leaking.
On Tue, Mar 11, 2008 at 4:46 AM, Rob Keniger <rob...> wrote:
> I had problems with this too, and I use a workaround I found somewhere
> where you render to a CGImageRef in the context of the current window.
> Here's a dump of the code:
>
> //theImage is an existing NSImage
> CIImage *outputImage = [CIImage imageWithData:[theImage
> TIFFRepresentation]];
>
> //to draw the image processed by Core Image, we need to draw into an
> on-screen graphics context
> //this works around a bug in CIImage where drawing in off-screen
> graphics contexts causes a huge memory leak
>
> //get the current window's graphics context so that we have an on-
> screen context
> //usually we would use any view's window but generically you can just
> ask for the main window
> CIContext *ciContext = [[[NSApp mainWindow] graphicsContext] CIContext];
> if(ciContext == nil)
> {
> NSLog(@"The CIContext of the main window could not be accessed.
> Bailing out of the image creation process.");
> return;
> }
>
> CGAffineTransform transform;
> transform = CGAffineTransformMakeTranslation(0.0,[outputImage
> extent].size.height);
> transform = CGAffineTransformScale(transform, 1.0, -1.0);
> outputImage = [outputImage imageByApplyingTransform:transform];
>
> //render the CIIimage into a CGImageRef in the on-screen context
> CGImageRef cgImage = [ciContext createCGImage:outputImage fromRect:
> [outputImage extent]];
> // Draw the CGImageRef into the current context
> if (cgImage != NULL)
> {
> CGContextDrawImage ([[NSGraphicsContext currentContext]
> graphicsPort], [outputImage extent], cgImage);
> CGImageRelease (cgImage);
> }
>
> HTH
>
> --
> Rob Keniger
>



