2

Has anyone else come across this problem? I am resizing images pretty often with an NSTimer. After using Instruments it does not show any memory leaks but my objectalloc just continues to climb. It points directly to CGBitmapContextCreateImage.

Anyone know of a solution? or Even possible ideas?

-(UIImage *) resizedImage:(UIImage *)inImage : (CGRect)thumbRect : (double)interpolationQuality
{
    CGImageRef          imageRef = [inImage CGImage];
    CGImageAlphaInfo    alphaInfo = CGImageGetAlphaInfo(imageRef);

    if (alphaInfo == kCGImageAlphaNone)
        alphaInfo = kCGImageAlphaNoneSkipLast;

    // Build a bitmap context that's the size of the thumbRect
    CGContextRef bitmap = CGBitmapContextCreate(
                    NULL,
                    thumbRect.size.width,
                    thumbRect.size.height,      
                    CGImageGetBitsPerComponent(imageRef),
                    4 * thumbRect.size.width,   
                    CGImageGetColorSpace(imageRef),
                    alphaInfo
                    );

    // Draw into the context, this scales the image
    CGContextSetInterpolationQuality(bitmap, interpolationQuality);
    CGContextDrawImage(bitmap, thumbRect, imageRef);

    // Get an image from the context and a UIImage
    CGImageRef  ref = CGBitmapContextCreateImage(bitmap);
    UIImage*    result = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);   // ok if NULL
    CGImageRelease(ref);

    return [result autorelease];
}
bbullis21
  • 741
  • 3
  • 9
  • 21

5 Answers5

1

Should you be releasing imageRef?

CGImageRelease(imageRef);
Tony
  • 18,776
  • 31
  • 129
  • 193
0

Ok, the problem here is that we are defining the return from CGBitmapContextCreateImage as CGImageRef, it should be CGImage. The reason your allocations (im assuming malloc) are perpetually increasing is becuase the CGImage itself is never getting released. Try the below code. Also, there is no need to autorelease the result since it is never 'Alloc'd.

After you make the changes run in insturments with allocation again, this time you will hopefully not see an continual increase in the live bytes.

I typed this on PC so there may be a syntax error if you drop it into XCode; however, this should do the trick.

 // Get an image from the context and a UIImage     
CGImage  cgImage = CGBitmapContextCreateImage(bitmap);     
UIImage*    result = [UIImage imageWithCGImage:cgImage];      
CGContextRelease(bitmap);   // ok if NULL     
CGImageRelease(cgImage);      
return result; 
CaseyB
  • 325
  • 2
  • 7
  • CGBitmapContextCreateImage returns a CGImageRef, not a CGImage. A CGImageRef is just a typedef of CGImage*. The above code won't compile, and if it was corrected so that CGBitmapContextCreateImage returns a CGImageRef (CGImage*), you would be releasing the CGImageRef. The answer is incorrect. You should consider removing it. – Gene Z. Ragan Aug 25 '17 at 19:36
0

Just a sanity check: are you releasing the return UIImage -- normally i would expect a function that allocating a new object (in this case a UIImage) to have create in the name?

Perhaps you want

return [result autorelease]

?

olliej
  • 35,755
  • 9
  • 58
  • 55
  • I actualy just added that line to my code a couple minutes ago, That didn't make a difference either. The CGBitmapContextCreate is murdering my objectalloc – bbullis21 Sep 16 '09 at 08:47
0

Why not use the simpler UIGraphicsBeginImageContext?

@implementation UIImage(ResizeExtension)
- (UIImage *)resizedImageWithSize:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)interpolationQuality;
@end
@implementation UIImage(ResizeExtension)
- (UIImage *)resizedImageWithSize:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)interpolationQuality
{
    UIGraphicsBeginImageContext(newSize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetInterpolationQuality(context, interpolationQuality);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return result;
}

@end

Also, this will return an image retained by the current autorelease pool; if you are creating many of these images in a loop, allocate and drain an NSAutoreleasePool manually.

rpetrich
  • 32,196
  • 6
  • 66
  • 89
  • UIImage isn't technically thread-safe either (although it usually works) – rpetrich Sep 16 '09 at 10:04
  • Thanks for the tips, but drawInRect doesn't provide the same InterpolationQuality affect. This is what I was basically doing, calling my above resizeImage script to shrink an image to a small resolution with a high InterpolationQuality, and then resizing it back to normal. The end result is a Photoshop like Gaussian blurred image. I have been searching for days to understand why CGBitmapContextCreate builds up the objectalloc. Thank you for your tips, I'm gonna keep working with your snippet to see if I can get the same end result. You know of any other possible way? – bbullis21 Sep 16 '09 at 11:20
  • I wasn't aware CGContextSetInterpolationQuality doesn't affect drawInRect. You can swap out the drawInRect call with CGContextDrawImage, but you may have to call CGContextScaleCTM to get the coordinate system to match up. – rpetrich Sep 16 '09 at 12:05
  • Thanks for the ideas of using CGContextDrawImage, I gave it a shot and still the affect is different for some reason. Not sure why exactly. This is ObjectAlloc build up is really killing my production time on this project. – bbullis21 Sep 17 '09 at 02:18
0

If you're using garbage collection, use CFMakeCollectable(posterFrame). If you're using traditional memory management, it's very straightforward:

return (CGImageRef)[(id)posterFrame autorelease];

You cast the CFTypeRef (in this case, a CGImageRef) to an Objective-C object pointer, send it the -autorelease message, and then cast the result back to CGImageRef. This pattern works for (almost) any type that's compatible with CFRetain() and CFRelease().

rbbtsn0w
  • 75
  • 11