1

I have an app using the camera to take pictures. As soon as the picture is taken, I reduce the size of the image coming from the camera.

Running the method for reducing the size of the image, makes the memory usage peaks from 21 MB to 61 MB, sometimes near 69MB!

I have added @autoreleasepool to every method involved in this process. Things improved a little bit, but not as much as I expected. I don't expect the memory usage jump 3 times when reducing an image, specially because the new image being produced is smaller.

These are the methods I have tried:

- (UIImage*)reduceImage:(UIImage *)image toSize:(CGSize)size {

    @autoreleasepool {
        UIGraphicsBeginImageContext(size);

        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(context, 0.0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);

        CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), image.CGImage);

        UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        return scaledImage;

    }
}

and also

- (UIImage *)reduceImage:(UIImage *)image toSize:(CGSize)size {

    @autoreleasepool {
        UIGraphicsBeginImageContext(size);

        [image drawInRect:rect];
        UIImage * result =  UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return result;
    }
}

no difference at all between these two.

NOTE: the original image is 3264x2448 pixels x 4 bytes/pixel = 32MB and the final image is 1136x640, that is 2.9MB... sum both numbers and you get 35MB, not 70!

Is there a way to reduce the size of the image without making the memory usage peak to stratosphere? thanks.

BTW and out of curiosity: is there a way to reduce an image dimension without using Quartz?

Duck
  • 34,902
  • 47
  • 248
  • 470
  • i noticed that since ios7 memory consumption is much higher then before when you work with images. there are some other people complaining about it in the apple-dev-forums but no solution.. – peko Nov 08 '13 at 11:56
  • I believe, it seems reasonable, that when drawing an image, which is initially compressed and not encoded, into a context will uncompress and decode the image into the "raw pixel buffer". This will necessarily require memory. The question is now, how to get rid of the internal buffer which contains the pixel data, which are not required unless the image is drawn. Of course, you need to write the scaled image to disk before you free the UIImage object. – CouchDeveloper Nov 08 '13 at 11:59
  • ok, the but the original image is 3264 x 2448 pixels x 4 bytes/pixel = 32MB and the final image is 1136x640, that is 2.9MB... sum both numbers and you get 35MB, not 70! – Duck Nov 08 '13 at 12:06
  • UIImage caches internal buffers. Only in low memory situations the system may decide to "purge" the cached buffers. This happens transparently "under the hood". I'm not aware of a way to control this behavior for `UIImage`. `NSImage` has a `recache` method. – CouchDeveloper Nov 08 '13 at 12:09
  • Tip: in a test, you may scale a large number of images in a loop and watch the system memory. It would be interesting so see how the system handles this "low memory situations". (ensure you dispatch to the main thread in every iteration in the loop) – CouchDeveloper Nov 08 '13 at 12:12
  • ok, but lets forget for a moment if a device is able to handle with it or not. My question stands: is there a way to reduce the image size dimensions by another method without using quartz? – Duck Nov 08 '13 at 12:16
  • I vaguely remember a technique which partitions the original image, then scales each partition, and then composes the target image. It's in the Apple samples somewhere. (You might even improve on the original sample, by leveraging multiple CPUs, and improve performance ... ) – CouchDeveloper Nov 08 '13 at 12:21
  • @CouchDeveloper that example was for images that are to big to be processed without consuming all the memory. – peko Nov 08 '13 at 12:24
  • 1
    @peko exactly. Wasn't memory the problem? – CouchDeveloper Nov 08 '13 at 12:24
  • @CouchDeveloper yeah but problem here is not that the file is to big to be processed – peko Nov 08 '13 at 12:42

1 Answers1

0

The answer is here

Uses CoreGraphics and uses 30~40% less memory.

    #import <ImageIO/ImageIO.h>
   -(UIImage*) resizedImageToRect:(CGRect) thumbRect
{
    CGImageRef          imageRef = [inImage CGImage];
    CGImageAlphaInfo    alphaInfo = CGImageGetAlphaInfo(imageRef);

    // There's a wierdness with kCGImageAlphaNone and CGBitmapContextCreate
    // see Supported Pixel Formats in the Quartz 2D Programming Guide
    // Creating a Bitmap Graphics Context section
    // only RGB 8 bit images with alpha of kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst,
    // and kCGImageAlphaPremultipliedLast, with a few other oddball image kinds are supported
    // The images on input here are likely to be png or jpeg files
    if (alphaInfo == kCGImageAlphaNone)
        alphaInfo = kCGImageAlphaNoneSkipLast;

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

    // Draw into the context, this scales the image
    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;
}

added as a category to UIImage.

Community
  • 1
  • 1
Duck
  • 34,902
  • 47
  • 248
  • 470