2012-02-21 114 views
4

我使用這段代碼來縮放和旋轉使用照片相機拍攝的圖像。當我使用這個時,我可以看到一個巨大的記憶峯值。像20 MB。當我使用這些工具時,我可以看到這一行:巨大的內存峯值 - CGContextDrawImage

CGContextDrawImage(ctxt,orig,self.CGImage);

包含20 MB。這是正常的全分辨率的照片? iPhone 4S可以處理它。但由於此代碼,較舊的設備崩潰。

我重新調整圖像後,我需要它在NSData中,所以我使用UIImageJPEGRepresentation()方法。這一起使記憶峯值更高。它在內存使用上達到70 MB,持續幾秒鐘。

是的,我讀了幾乎所有關於內存使用情況的iOS相機相關問題。但沒有答案。

// 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 

回答

2

我結束了使用ImageIO的,更少的內存!

-(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; 

} 
+0

謝謝!這幫了很多忙。 – timthetoolman 2012-06-30 06:14:45

1


這是正確的它來自你拍攝的相機照片,舊的設備使用相機的分辨率較低,這意味着用的iPhone 3G拍攝的圖像的分辨率(因而大小)尊重一個你在iPhone4s上。圖像通常是壓縮的,但是當它們在內存中打開以進行某種操作時,它們必須進行解壓縮,它們需要的大小實際上大於文件中的大小,因爲如果我記得好的話,就是number_of_pixel_in_row*number_of_pixel_in_height*byte_for_pixel
再見, 安德烈

+0

感謝您的回答。但有沒有解決方案來減少內存使用量。你提到壓縮,也許你可以指出我的方向。 – Melvin 2012-02-21 18:22:14

+0

壓縮對文件起作用,當您對需要解壓縮的圖像執行操作時。如果您遇到崩潰,我仍不明白。我建議你閱讀這篇文章[鏈接](http://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/),並從Apple站點下載示例代碼LargeImageDownsizing。 Ciao – Andrea 2012-02-22 08:44:03

+0

也許有一種解決方案可以使用mmap unix函數將映像文件映射到文件上,但這可能相當困難並且可能很慢。 – Andrea 2012-02-22 10:48:24

0

插入這個在你的方法結束和return copy;前:

CGContextRelease(ctxt); 
+0

我剛纔試過,但它似乎沒有任何效果。我正在使用ARC,因此ARC可能正在處理此問題。 – Melvin 2012-02-21 18:20:45

+1

ARC不會關心「舊」核心基礎對象 – Andrea 2012-02-22 08:38:48