2012-02-21 2 views
4

Я использую этот кусок кода для масштабирования и поворота изображений, сделанных с помощью фотокамеры. Когда я использую это, я вижу огромный пик памяти. Что-то вроде 20 МБ. Когда я использую инструменты, я вижу, что эта строка:Огромный пик памяти - CGContextDrawImage

CGContextDrawImage (ctxt, orig, self.CGImage);

имеет 20 МБ. Это нормально для фотографий с полным разрешением? IPhone 4S может справиться с этим. но из-за этого кода происходит сбой старых устройств.

После того, как я перемасштабирую изображение, мне это нужно в NSData, поэтому я использую метод UIImageJPEGRepresentation(). Это вместе делает пик памяти еще выше. Он занимает до 70 МБ в памяти в течение нескольких секунд.

И да, я прочитал почти все вопросы, связанные с 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

1


, что правильно это происходит от картины, что вы выстрел с камерой, более старые устройства используют камеры с меньшим разрешением, что означает, что снимки, сделанные с iPhone 3g меньше в разрешении (таким образом, размер) уважать тот, который у вас есть на вашем iPhone4s. Изображения обычно сжимаются, но когда они открываются в памяти для какой-то операции, они должны быть распаковываются, размер, который им нужен, действительно больше, чем тот, что есть в файле, потому что есть number_of_pixel_in_row*number_of_pixel_in_height*byte_for_pixel, если я хорошо помню.
Bye, Andrea

+0

благодарит за ваш ответ. Но есть ли решение сократить использование памяти. Вы упомянули компрессию, может быть, вы можете указать мне в правильном направлении. – Melvin

+0

Сжатие работает с файлом, когда вы выполняете операции над изображением, которое необходимо его распаковать. Я все еще не понял, если вы столкнулись с крахом или нет. Я предлагаю вам прочитать эту статью [link] (http://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/), а также загрузить образец кода LargeImageDownsizing с сайта Apple. Ciao – Andrea

+0

Возможно, одним из решений может быть отображение памяти изображений в файл с помощью функции mmap unix, но это может быть довольно сложно и, возможно, слишком медленным. – Andrea

0

Вставьте это в конце ваших методов и перед return copy;:

CGContextRelease(ctxt); 
+0

Я пробовал это только сейчас, но кажется, что он не имеет никакого эффекта. Я использую ARC, поэтому, возможно, ARC позаботится об этом. – Melvin

+1

ARC не позаботится о «старых» объектах Core Foundation – Andrea

Смежные вопросы