Reputation: 217
We are trying to let users import picture from their albums(UIImagePickerController
) and also we are scaling/resizing down images that are greater than 8 megapixels(iPhone standard).
But every time the app crashes with Connection to assetsd was interrupted or assetsd died
and Received memory warning
warnings after or before importing picture.At times Received memory warning
warning pops up when still looking for picture to import in UIImagePickerController
.
Specially on iPhone 4S this is worse, please help us in optimising our code so that it runs without warnings and crashes on older devices like iPhone 4S or iPad 2.
Let us know if we are doing anything wrong in scaling/resizing down image using CoreGraphics.(Because this is where huge memory is used).
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *selectedImage=[info objectForKey:UIImagePickerControllerOriginalImage];
if(UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
else
{
[popoverController dismissPopoverAnimated:YES];
[self popoverControllerDidDismissPopover:popoverController];
}
// COMPRESSING IMAGE
NSData *selectedImageData=UIImageJPEGRepresentation(selectedImage, 0.1);
UIImage *selectedImageFromData=[UIImage imageWithData:selectedImageData];
// IMAGE ASPECT RATIO
CGFloat originalWidth=selectedImageFromData.size.width;
CGFloat originalHeight=selectedImageFromData.size.height;
CGFloat myWidth=2048;
CGFloat myHeight=2048;
CGFloat widthRatio=myWidth/originalWidth;
CGFloat heightRatio=myHeight/originalHeight;
CGFloat dynamicWidth=heightRatio*originalWidth;
CGFloat dynamicHeight=widthRatio*originalHeight;
//SCALING UIIMAGE MORE THAN 8 MEGAPIXELS
if (((selectedImageFromData.size.width>3264) && (selectedImageFromData.size.height>2448)) || ((selectedImageFromData.size.height>3264) && (selectedImageFromData.size.width>2448)))
{
// DATA FROM UIIMAGE TO CORE GRAPHICS
CGImageRef CoreGraphicsImage=selectedImageFromData.CGImage;
CGColorSpaceRef colorSpace = CGImageGetColorSpace(CoreGraphicsImage);
CGBitmapInfo bitmapInfo=CGImageGetBitmapInfo(CoreGraphicsImage);
CGImageGetBitsPerComponent(CoreGraphicsImage);
// RESIZING WIDTH OF THE IMAGE
if (originalWidth>originalHeight)
{
CGContextRef context=CGBitmapContextCreate(NULL, myWidth, dynamicHeight, CGImageGetBitsPerComponent(CoreGraphicsImage), CGImageGetBytesPerRow(CoreGraphicsImage), colorSpace, bitmapInfo);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextDrawImage(context, CGRectMake(0, 0, myWidth, dynamicHeight), CoreGraphicsImage);
CGImageRef CGscaledImage=CGBitmapContextCreateImage(context);
UIImage *CGLastimage = [UIImage imageWithCGImage: CGscaledImage];
NSLog(@"%f",CGLastimage.size.width);
NSLog(@"%f",CGLastimage.size.height);
VisualEffectImageVIew.image=CGLastimage;
BackgroundImageView.image=CGLastimage;
ForegroundImageView.image=CGLastimage;
}
//RESIZING HEIGHT OF THE IMAGE
if (originalHeight>originalWidth)
{
CGContextRef context=CGBitmapContextCreate(NULL, dynamicWidth, myHeight, CGImageGetBitsPerComponent(CoreGraphicsImage), CGImageGetBytesPerRow(CoreGraphicsImage), colorSpace, bitmapInfo);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGContextDrawImage(context, CGRectMake(0, 0, dynamicWidth, myHeight), CoreGraphicsImage);
CGImageRef CGscaledImage=CGBitmapContextCreateImage(context);
UIImage *CGLastimage = [UIImage imageWithCGImage: CGscaledImage];
NSLog(@"%f",CGLastimage.size.width);
NSLog(@"%f",CGLastimage.size.height);
VisualEffectImageVIew.image=CGLastimage;
BackgroundImageView.image=CGLastimage;
ForegroundImageView.image=CGLastimage;
}
}
else
{
NSLog(@" HEIGHT %f",selectedImageFromData.size.height);
NSLog(@" WIDTH %f",selectedImageFromData.size.width);
VisualEffectImageVIew.image=selectedImageFromData;
BackgroundImageView.image=selectedImageFromData;
ForegroundImageView.image=selectedImageFromData;
}
}
Memory Report
when scrolling in UIImagePickerController
https://i.sstatic.net/qxx62.png
when scaling/resizing UIImage
https://i.sstatic.net/ELCA6.png
Upvotes: 4
Views: 7570
Reputation: 6804
Two points.
First, you are not releasing the objects you create -- you are leaking huge amounts of memory. Regardless of whether you are using ARC, you must call CGContextRelease or CGImageRelease as appropriate for every CGCreate call.
Second, if you just want to resize, using coregraphics is overkill, use UIKit instead. In the code I use below, note the use of @autorelease to ensure that objects are cleaned up by ARC as soon as the context ends
- (UIImage *)fitImage:(UIImage *)image scaledToFillSize:(CGSize)size {
// do not upscale
@autoreleasepool {
if( image.size.width <= size.width && image.size.height <= size.height )
return image;
CGFloat scale = MIN(size.width/image.size.width, size.height/image.size.height);
CGFloat width = image.size.width * scale;
CGFloat height = image.size.height * scale;
CGRect imageRect;
// center image
if( scale != 1.0 ) { // avoid divide by zero?
if( size.width/image.size.width < size.height/image.size.height ) {
// height needs to be centered
imageRect = CGRectMake(0, (size.height-height)/2, width, height);
} else {
// width needs to be centered
imageRect = CGRectMake((size.width-width)/2, 0, width, height);
}
}
UIGraphicsBeginImageContextWithOptions(size, YES, 0);
[[UIColor CollageBorderUIColor] setFill]; // otherwise it's ugly black fill
UIRectFill(CGRectMake(0, 0, size.width, size.height));
[image drawInRect:imageRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
}
Upvotes: 4