3

I have this code to rotate CGImage:

- (CGImageRef)rotateCGImageRef:(CGImageRef)imageRef toOrientation:(UIImageOrientation)orientation
{
    CGRect             bnds = CGRectZero;
    CGImageRef         copy = nil;
    CGContextRef       ctxt = nil;
    CGRect             rect = CGRectZero;
    CGAffineTransform  tran = CGAffineTransformIdentity;

    @autoreleasepool {
        bnds.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;
        rect.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;

        switch (orientation)
        {
            case UIImageOrientationUp:
                return imageRef;

            case UIImageOrientationUpMirrored:
                tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                break;

            case UIImageOrientationDown:
                tran = CGAffineTransformMakeTranslation(rect.size.width, rect.size.height);
                tran = CGAffineTransformRotate(tran, degreesToRadians(180.0));
                break;

            case UIImageOrientationDownMirrored:
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
                tran = CGAffineTransformScale(tran, 1.0, -1.0);
                break;

            case UIImageOrientationLeft:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
                tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
                break;

            case UIImageOrientationLeftMirrored:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(rect.size.height, rect.size.width);
                tran = CGAffineTransformScale(tran, -1.0, 1.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
                break;

            case UIImageOrientationRight:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
                break;

            case UIImageOrientationRightMirrored:
                bnds.size = swapWidthAndHeight(bnds.size);
                tran = CGAffineTransformMakeScale(-1.0, 1.0);
                tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
                break;

            default:
                // orientation value supplied is invalid
                assert(false);
                return nil;
        }

        UIGraphicsBeginImageContext(bnds.size);
        ctxt = UIGraphicsGetCurrentContext();

        switch (orientation)
        {
            case UIImageOrientationLeft:
            case UIImageOrientationLeftMirrored:
            case UIImageOrientationRight:
            case UIImageOrientationRightMirrored:
                CGContextScaleCTM(ctxt, -1.0, 1.0);
                CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
                break;

            default:
                CGContextScaleCTM(ctxt, 1.0, -1.0);
                CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
                break;
        }

        CGContextConcatCTM(ctxt, tran);
        CGContextDrawImage(ctxt, rect, imageRef);

        //copy = UIGraphicsGetImageFromCurrentImageContext();
        copy = CGBitmapContextCreateImage(ctxt);
        UIGraphicsEndImageContext();
    }
    return copy;
}

But Analyzer says it has leak: memory leak

I cannot release copy object cos I method is returning it.

What is actually leaking?

EDIT: Here is the final code converted to C function:

CGImageRef CreateRotatedImage(CGImageRef imageRef, UIImageOrientation orientation)
{
    CGRect             bnds = CGRectZero;
    CGImageRef         copy = nil;
    CGContextRef       ctxt = nil;
    CGRect             rect = CGRectZero;
    CGAffineTransform  tran = CGAffineTransformIdentity;

    bnds.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;
    rect.size = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); //self.size;

    switch (orientation)
    {
        case UIImageOrientationUp:
            return imageRef;

        case UIImageOrientationUpMirrored:
            tran = CGAffineTransformMakeTranslation(rect.size.width, 0.0);
            tran = CGAffineTransformScale(tran, -1.0, 1.0);
            break;

        case UIImageOrientationDown:
            tran = CGAffineTransformMakeTranslation(rect.size.width, rect.size.height);
            tran = CGAffineTransformRotate(tran, degreesToRadians(180.0));
            break;

        case UIImageOrientationDownMirrored:
            tran = CGAffineTransformMakeTranslation(0.0, rect.size.height);
            tran = CGAffineTransformScale(tran, 1.0, -1.0);
            break;

        case UIImageOrientationLeft:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(0.0, rect.size.width);
            tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
            break;

        case UIImageOrientationLeftMirrored:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(rect.size.height, rect.size.width);
            tran = CGAffineTransformScale(tran, -1.0, 1.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(-90.0));
            break;

        case UIImageOrientationRight:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeTranslation(rect.size.height, 0.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
            break;

        case UIImageOrientationRightMirrored:
            bnds.size = swapWidthAndHeight(bnds.size);
            tran = CGAffineTransformMakeScale(-1.0, 1.0);
            tran = CGAffineTransformRotate(tran, degreesToRadians(90.0));
            break;

        default:
            // orientation value supplied is invalid
            assert(false);
            return nil;
    }

    UIGraphicsBeginImageContext(bnds.size);
    ctxt = UIGraphicsGetCurrentContext();

    switch (orientation)
    {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            CGContextScaleCTM(ctxt, -1.0, 1.0);
            CGContextTranslateCTM(ctxt, -rect.size.height, 0.0);
            break;

        default:
            CGContextScaleCTM(ctxt, 1.0, -1.0);
            CGContextTranslateCTM(ctxt, 0.0, -rect.size.height);
            break;
    }

    CGContextConcatCTM(ctxt, tran);
    CGContextDrawImage(ctxt, rect, imageRef);

    //copy = UIGraphicsGetImageFromCurrentImageContext();
    copy = CGBitmapContextCreateImage(ctxt);
    UIGraphicsEndImageContext();
    return copy;
}

Call to this C function:

imageRef = CreateRotatedImage(imageRef, UIImageOrientationRight);
Borut Tomazin
  • 8,041
  • 11
  • 78
  • 91

3 Answers3

2

I think your problem is that you are returning a CGImageRef from an Obj-C method. CGImageRef is a typedef to a C-struct pointer, not a NSObject and thus it cannot be autoreleased.

I would consider two options - convert the method into a C function or put the returned value into a NSObject (e.g. UIImage).

EDIT:

CGImageRef CreateRotatedImage(CGImageRef imageRef, UIImageOrientation toOrientation) {
    [... your code ...]
}

Call:

CGImageRef rotatedImage = CreateRotatedImage(image, orientation);
Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • Second option is not good cos I am passing in CGImage and also expect to get back CGImage and not UIImage. About first option I don't really know how to create C function and how to call it...? – Borut Tomazin Feb 22 '12 at 12:47
  • You should definitely learn how to it :) In your code, you are calling C functions 20 times already. Edited the answer. – Sulthan Feb 22 '12 at 12:57
0

You have to free your CGImageRef copy. CFType should know how to handle release and autorelease. Try this:

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

First, you have to cast it to an Objective-C pointer. Successively, you cast it back to CGImageRef. See this answer: https://stackoverflow.com/a/7061168/656036

Community
  • 1
  • 1
fscheidl
  • 2,281
  • 3
  • 19
  • 33
0

You should read into what the analyzer is saying: it is a potential leak. Analyzer will not tell you if this is really a leak or not, to get that information you need to run the Leaks tool from the instruments.

Analyzer correctly warns you that you return a value that you will have to release yourself.

In your receiving function, just call

CGImageRelease(img);

After your are done with the CGImageRef.

Bartosz Ciechanowski
  • 10,293
  • 5
  • 45
  • 60
Peter Sarnowski
  • 11,900
  • 5
  • 36
  • 33