2

I was trying to rotate an UIImage of 2448x3264 taken with the camera. When I do, the memory spikes 120Mb approximately, for more or less 3/4 seconds and then returns to its normal state. The problem is that, in devices with less memory(for instance, ipod touch), the app crashes. Even if it doesn't, I don't think it should use that much memory for one image. Iphone 5 is also lagged when this happens.

According to a comment in this answer, the size in bytes of the decompressed memory after using UIGraphicsGetCurrentContext() should be width * height * CGImageGetBitsPerComponent(image.CGImage) / 8 bytes, so the image should occupy 8Mb, not 120.

Any idea why this happens and how to fix it?

Here's the UIImage caterogy method to return a rotated image:

- (UIImage *)imageRotatedByDegrees:(CGFloat)degrees {
    CGFloat radian = (CGFloat) (degrees * (M_PI/ 180.0f));
    CGSize rotatedSize = [self rotatedImageSize:degrees];

    // Create the bitmap context
    UIGraphicsBeginImageContextWithOptions(rotatedSize, NO, 0);
    CGContextRef bitmap = UIGraphicsGetCurrentContext();

    CGPoint contextCenter = CGPointMake(rotatedSize.width/2.0f, 
rotatedSize.height/2.0f);
    CGContextTranslateCTM(bitmap, contextCenter.x, contextCenter.y);

    //   // Rotate the image context
    CGContextRotateCTM(bitmap, radian);
    // Now, draw the rotated/scaled image into the context
    [self drawInRect:CGRectMake(-self.size.width/2.0f, -
self.size.height/2.0f, self.size.width, self.size.height)];

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

Here's proof from instruments that the raster data is what's causing the peak in memory, just when the rotate method is executed:

Instruments proof

Community
  • 1
  • 1
damfinkel
  • 21
  • 1

1 Answers1

0

Several remarks:

  • 2448x3264x(say 4 bytes/pixel) is about 30 megabytes.
  • Don't rotate it. If it's going on screen, you can use a view's transform property. If it's going into a file and the rotation is one of the 8 exif orientations, write metadata that says which way is up. Likewise if it is coming from a file, use Image I/O and ask the CGImageSourceRef to generate an oriented thumbnail the size you need to put it on-screen. (Hint use kCGImageSourceThumbnailMaxPixelSize and kCGImageSourceCreateThumbnailWithTransform.) For arbitrary angles you can use a CoreImage filter that will rotate the image and downsample to the size you need for the screen (on the GPU). Likewise, you can use vImage to do the same thing on the CPU (hint vImageAffineWarpCG_ARGB8888). vImage is very fast and it will give you much better resampling than core graphics. And so forth...if it hurts, don't do it.
  • You should pause before you spend time converting from angles into rotation matrices. For example if your angle is 90 degrees, the matrix you want is [0 1 -1 0 0 0] exactly and your resampling code will be happier with that than the approximate result you compute. The rotation matrix is [cos(t) sin(t) -sin(t) cos(t) 0 0]. Clients likely can already pass in the cosine and sine directly.
Mustang
  • 363
  • 2
  • 9