使用CGImageCreate调整图像大小以减少内存使用量

时间:2014-03-04 03:49:52

标签: ios objective-c core-graphics core-image

有时图像非常大(从互联网上下载),所以我需要调整它们的大小,但不想导致内存问题,这意味着我不想将所有图像数据加载到内存中并在内存中调整大小存储器中。

我正在调查调整图像大小的方法,监控他们的记忆用法。具体而言,CGContextDrawImageCGImageSourceCreateThumbnailAtIndexCGImageCreateCGDataProviderRef

现在,在CGImageCreateCGDataProviderRef一起使用时遇到了一些问题,我的代码是这样的:

//This method read the data from filePath, resize the image and write the resized data to the destPath
- (void)resizeImageFileUsingCGImageCreate:(NSString*)filePath toDestPath:(NSString*)destPath {

    CGFloat factor = 0.2;
    CGSize originalSize = [self sizeOfImageAtURL:[[NSURL alloc] initFileURLWithPath:filePath]];
    CGSize destSize = CGSizeMake((NSUInteger)(originalSize.width * factor), (NSUInteger)(originalSize.height * factor));



    UIImage *srcImage = [UIImage imageWithContentsOfFile:filePath];
    CGImageRef srcImgRef = srcImage.CGImage;
    NSData *data = [NSData dataWithContentsOfFile:filePath];
    CFDataRef cfData = (__bridge_retained CFDataRef)data;
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(cfData);
    CFRelease(cfData);

    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(srcImgRef);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    CGImageRef imageRef = CGImageCreate(destSize.width, destSize.height, 8, 32, 4 * destSize.width, colorSpace, bitmapInfo, dataProvider, NULL, NO, 0);

    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colorSpace);
    UIImage *image = nil;
    if (imageRef != NULL) {
        image = [[UIImage alloc] initWithCGImage:imageRef];
        CGImageRelease(imageRef);
        //Why UIImageJPEGRepresentation(image, 0.5) returns nil?
        [UIImageJPEGRepresentation(image, 0.5) writeToFile:destPath atomically:YES];


    }


}

在代码的最后一行,UIImageJPEGRepresentation(image, 0.5)总是返回nil,这让我很奇怪。您能帮我指出使用CGImageCreate CGDataProviderRef调整图片大小的正确方法吗?非常感谢!

2 个答案:

答案 0 :(得分:2)

我不会直接回答您的问题,而是会向您展示我认为更好的方法:使用ImageIO框架。

#import <ImageIO/ImageIO.h>

以下是从磁盘加载缩小版图像的方法(imageSource是NSURL; scalemaxwmaxh必须事先设置为您想要的比例和最大尺寸:

CGImageSourceRef src = 
    CGImageSourceCreateWithURL((__bridge CFURLRef)imageSource, nil);
NSDictionary* d = @{
    (id)kCGImageSourceShouldAllowFloat: (id)kCFBooleanTrue,
    (id)kCGImageSourceCreateThumbnailWithTransform: (id)kCFBooleanTrue,
    (id)kCGImageSourceCreateThumbnailFromImageAlways: (id)kCFBooleanTrue,
    (id)kCGImageSourceThumbnailMaxPixelSize: @((int)(maxw > maxh ? maxw : maxh))
};
CGImageRef imref = 
    CGImageSourceCreateThumbnailAtIndex(src, 0, (__bridge CFDictionaryRef)d);
if (NULL != src)
    CFRelease(src);
UIImage* im = 
    [UIImage imageWithCGImage:imref scale:scale orientation:UIImageOrientationUp];
if (NULL != imref)
    CFRelease(imref);

关于这段代码的好处是我们永远不会在内存中保存大图像;永远不会加载。我们最终得到了一个更小的UIImage,我们准备在我们的界面中使用它。

如果您拥有的是来自互联网的NSData,而您尚未将其保存到磁盘,那么要创建图像源,请使用:

src = CGImageSourceCreateWithData((__bridge CFDataRef)imageSource, nil);

但实际上,如果图像很大,您应该使用下载任务,以便整个图像在内存中永远,但在到达时保存到磁盘。

答案 1 :(得分:0)

而不是这样做:

    [UIImageJPEGRepresentation(image, 0.5) writeToFile:destPath atomically:YES];

你应该这样做:

NSData *imageData = UIImageJPEGRepresentation(image, 0.5);
if(imageData) 
{
    NSError *error = nil;
    BOOL success = [imageData writeToFile:destPath options:NSDataWritingAtomic error:&error];
    if(NO == success)
    {
        NSLog(@"couldn't write image data to file %@ because of error %@", destPath, error)
    }
}

在我的代码版本中,我将图像数据放入NSData对象,然后在写入图像数据失败时打印出错误。