Reputation: 3431
I use this piece of code to scale and rotate images taken with the photo camera. When I use this I can see a huge memory peak. Something like 20 MB. When I use the instruments I can see that this line:
CGContextDrawImage(ctxt, orig, self.CGImage);
holds 20 MB. Is this normal for full resolution photos? The iPhone 4S can handle it. but older devices crashes because of this code.
After I rescale the image I need it in NSData, so I use the UIImageJPEGRepresentation() method. This together makes the memory peak even higher. It goes to 70 MB in memory usage for several seconds.
And yes, I did read almost all the iOS camera related question about memory usage. But no answer out there.
// WBImage.mm -- extra UIImage methods
// by allen brunson march 29 2009
#include "WBImage.h"
static inline CGFloat degreesToRadians(CGFloat degrees)
{
return M_PI * (degrees / 180.0);
}
static inline CGSize swapWidthAndHeight(CGSize size)
{
CGFloat swap = size.width;
size.width = size.height;
size.height = swap;
return size;
}
@implementation UIImage (WBImage)
// rotate an image to any 90-degree orientation, with or without mirroring.
// original code by kevin lohman, heavily modified by yours truly.
// http://blog.logichigh.com/2008/06/05/uiimage-fix/
-(UIImage*)rotate:(UIImageOrientation)orient
{
CGRect bnds = CGRectZero;
UIImage* copy = nil;
CGContextRef ctxt = nil;
CGRect rect = CGRectZero;
CGAffineTransform tran = CGAffineTransformIdentity;
bnds.size = self.size;
rect.size = self.size;
switch (orient)
{
case UIImageOrientationUp:
return self;
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(rect.size);
ctxt = UIGraphicsGetCurrentContext();
switch (orient)
{
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, bnds, self.CGImage);
copy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return copy;
}
-(UIImage*)rotateAndScaleFromCameraWithMaxSize:(CGFloat)maxSize
{
UIImage* imag = self;
imag = [imag rotate:imag.imageOrientation];
imag = [imag scaleWithMaxSize:maxSize];
return imag;
}
-(UIImage*)scaleWithMaxSize:(CGFloat)maxSize
{
return [self scaleWithMaxSize:maxSize quality:kCGInterpolationHigh];
}
-(UIImage*)scaleWithMaxSize:(CGFloat)maxSize
quality:(CGInterpolationQuality)quality
{
CGRect bnds = CGRectZero;
UIImage* copy = nil;
CGContextRef ctxt = nil;
CGRect orig = CGRectZero;
CGFloat rtio = 0.0;
CGFloat scal = 1.0;
bnds.size = self.size;
orig.size = self.size;
rtio = orig.size.width / orig.size.height;
if ((orig.size.width <= maxSize) && (orig.size.height <= maxSize))
{
return self;
}
if (rtio > 1.0)
{
bnds.size.width = maxSize;
bnds.size.height = maxSize / rtio;
}
else
{
bnds.size.width = maxSize * rtio;
bnds.size.height = maxSize;
}
UIGraphicsBeginImageContext(bnds.size);
ctxt = UIGraphicsGetCurrentContext();
scal = bnds.size.width / orig.size.width;
CGContextSetInterpolationQuality(ctxt, quality);
CGContextScaleCTM(ctxt, scal, -scal);
CGContextTranslateCTM(ctxt, 0.0, -orig.size.height);
CGContextDrawImage(ctxt, orig, self.CGImage);
copy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return copy;
}
@end
Upvotes: 4
Views: 3284
Reputation: 3431
I ended up using imageIO, less memory!
-(UIImage *)resizeImageToMaxDimension: (float) dimension withPaht: (NSString *)path
{
NSURL *imageUrl = [NSURL fileURLWithPath:path];
CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef)imageUrl, NULL);
NSDictionary *thumbnailOptions = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, kCGImageSourceCreateThumbnailWithTransform,
kCFBooleanTrue, kCGImageSourceCreateThumbnailFromImageAlways,
[NSNumber numberWithFloat:dimension], kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, (__bridge CFDictionaryRef)thumbnailOptions);
UIImage *resizedImage = [UIImage imageWithCGImage:thumbnail];
CFRelease(thumbnail);
CFRelease(imageSource);
return resizedImage;
}
Upvotes: 3
Reputation: 14834
Insert this at the end of your methods and before the return copy;
:
CGContextRelease(ctxt);
Upvotes: 0
Reputation: 26383
that's correct it comes from the picture that you shot with your camera, older devices use cameras with less resolution, that means that images taken with an iPhone 3g are smaller in resolution (thus size) respect the one that you have on your iPhone4s. Images are usually compressed but when they open up in memory for some sort of operation they must be decompresses, the size that they need is really bigger that the one in a file, because is the number_of_pixel_in_row*number_of_pixel_in_height*byte_for_pixel
if I remember well.
Bye,
Andrea
Upvotes: 1