Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

xArtx

macrumors 6502a
Original poster
Mar 30, 2012
764
1
Hi Guys,
I have this working fine to rotate an image at arbitrary angles,
except when it is called enough times, I get low memory warnings,
followed by App crash.
THe function originally had a release or autorelease statement in it
that had to be removed for an ARC project.

Code:
- (CGImageRef)CGImageRotatedByAngle:(CGImageRef)imgRef angle:(CGFloat)angle
{
    
    CGFloat angleInRadians = angle * (M_PI / 180);
    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);
    
    CGRect imgRect = CGRectMake(0, 0, width, height);
    CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
    CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGContextRef bmContext = CGBitmapContextCreate(NULL,
                                                   rotatedRect.size.width,
                                                   rotatedRect.size.height,
                                                   8,
                                                   0,
                                                   colorSpace,
                                                   kCGImageAlphaPremultipliedFirst);
    CGContextSetAllowsAntialiasing(bmContext, YES);
    CGContextSetShouldAntialias(bmContext, YES);
    CGContextSetInterpolationQuality(bmContext, kCGInterpolationHigh);
    CGColorSpaceRelease(colorSpace);
    CGContextTranslateCTM(bmContext,
                          +(rotatedRect.size.width/2),
                          +(rotatedRect.size.height/2));
    CGContextRotateCTM(bmContext, angleInRadians);
    CGContextTranslateCTM(bmContext,
                          -(rotatedRect.size.width/2),
                          -(rotatedRect.size.height/2));
    CGContextDrawImage(bmContext, CGRectMake(0, 0,
                                             rotatedRect.size.width,
                                             rotatedRect.size.height),
                       imgRef);
    
    rotatedImage = CGBitmapContextCreateImage(bmContext);
    CFRelease(bmContext);
      
    return rotatedImage;
}

Called with this:

Code:
CGImageRef imageRef = [self CGImageRotatedByAngle:[oldImage CGImage] angle:rotation];
rotImage = [UIImage imageWithCGImage: imageRef];

Any ideas as to why this is happening?
As I said, it does work for a while to rotate an image a few times.
I keep changing the angle of rotation, but am only writing the result back to
rotImage, not creating a bunch of new image objects.
Cheers, Art.
 
My knowledge of CoreGraphics is rather limited but the Discussion for CGBitmapContextCreateImage states:
The CGImage object returned by this function is created by a copy operation. Subsequent changes to the bitmap graphics context do not affect the contents of the returned image. In some cases the copy operation actually follows copy-on-write semantics, so that the actual physical copy of the bits occur only if the underlying data in the bitmap graphics context is modified. As a consequence, you may want to use the resulting image and release it before you perform additional drawing into the bitmap graphics context. In this way, you can avoid the actual physical copy of the data.

I think you may need to use CGImageRelease at some point but I'm not sure where. Perhaps have your method create and return a UIImage instead so that you can call imageWithCGImage: and then CGImageRelease before the method ends.
 
Hi Guys,
I have this working fine to rotate an image at arbitrary angles,
except when it is called enough times, I get low memory warnings,
followed by App crash.
THe function originally had a release or autorelease statement in it
that had to be removed for an ARC project.

Code:
- (CGImageRef)CGImageRotatedByAngle:(CGImageRef)imgRef angle:(CGFloat)angle
{
    
    CGFloat angleInRadians = angle * (M_PI / 180);
    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);
    
    CGRect imgRect = CGRectMake(0, 0, width, height);
    CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
    CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    CGContextRef bmContext = CGBitmapContextCreate(NULL,
                                                   rotatedRect.size.width,
                                                   rotatedRect.size.height,
                                                   8,
                                                   0,
                                                   colorSpace,
                                                   kCGImageAlphaPremultipliedFirst);
    CGContextSetAllowsAntialiasing(bmContext, YES);
    CGContextSetShouldAntialias(bmContext, YES);
    CGContextSetInterpolationQuality(bmContext, kCGInterpolationHigh);
    CGColorSpaceRelease(colorSpace);
    CGContextTranslateCTM(bmContext,
                          +(rotatedRect.size.width/2),
                          +(rotatedRect.size.height/2));
    CGContextRotateCTM(bmContext, angleInRadians);
    CGContextTranslateCTM(bmContext,
                          -(rotatedRect.size.width/2),
                          -(rotatedRect.size.height/2));
    CGContextDrawImage(bmContext, CGRectMake(0, 0,
                                             rotatedRect.size.width,
                                             rotatedRect.size.height),
                       imgRef);
    
    rotatedImage = CGBitmapContextCreateImage(bmContext);
    CFRelease(bmContext);
      
    return rotatedImage;
}

Called with this:

Code:
CGImageRef imageRef = [self CGImageRotatedByAngle:[oldImage CGImage] angle:rotation];
rotImage = [UIImage imageWithCGImage: imageRef];

Any ideas as to why this is happening?
As I said, it does work for a while to rotate an image a few times.
I keep changing the angle of rotation, but am only writing the result back to
rotImage, not creating a bunch of new image objects.
Cheers, Art.

As Dejo says, you need to release the CFImage once you are done with it:


Code:
CGImageRef imageRef = [self CGImageRotatedByAngle:[oldImage CGImage] angle:rotation];
rotImage = [UIImage imageWithCGImage: imageRef];
CGImageRelease(imageRef);


ARC does not manage Core Foundation objects for you. Your method CGImageRotatedByAngle should really be renamed to have the word create in it's name. I'd suggest CGCreateImageRoatedByAngle:

Then it will be more apparent that the method follows the Core Foundation "Create Rule"
 
Thanks, I'll give it a shot :)

Just a curiosity... How much memory does your App get?
If you kept allocating memory, your App would crash,
but iOS doesn't.
I wonder if the initial allocation of RAM is expanded by iOS if you allocate more memory at runtime.
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.