使用太多内存来减少图像尺寸......有没有办法使用更少的内存来做到这一点?

Posted

技术标签:

【中文标题】使用太多内存来减少图像尺寸......有没有办法使用更少的内存来做到这一点?【英文标题】:Reducing image dimensions using too much memory... is there a way to do that using less memory? 【发布时间】:2013-11-08 11:45:37 【问题描述】:

我有一个使用相机拍照的应用程序。拍完照片后,我会缩小来自相机的图像尺寸。

运行缩小图片大小的方法,内存使用峰值从21MB到61MB,有时接近69MB!

我已将@autoreleasepool 添加到此过程中涉及的每个方法中。情况有所改善,但没有我预期的那么好。我不希望缩小图像时内存使用量会跳跃 3 次,特别是因为正在生成的新图像更小。

这些是我尝试过的方法:

- (UIImage*)reduceImage:(UIImage *)image toSize:(CGSize)size 

    @autoreleasepool 
        UIGraphicsBeginImageContext(size);

        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(context, 0.0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);

        CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, size.width, size.height), image.CGImage);

        UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

        UIGraphicsEndImageContext();

        return scaledImage;

    

还有

- (UIImage *)reduceImage:(UIImage *)image toSize:(CGSize)size 

    @autoreleasepool 
        UIGraphicsBeginImageContext(size);

        [image drawInRect:rect];
        UIImage * result =  UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        return result;
    

这两者完全没有区别。

注意:原始图像为 3264x2448 像素 x 4 字节/像素 = 32MB,最终图像为 1136x640,即 2.9MB...将两个数字相加得到 35MB,而不是 70!

有没有办法在不使内存使用高峰达到平流层的情况下减小图像的大小?谢谢。

顺便说一句,出于好奇:有没有办法在不使用 Quartz 的情况下减小图像尺寸?

【问题讨论】:

我注意到,由于 ios7 的内存消耗比使用图像之前要高得多。 Apple-dev-forums 中有其他人抱怨它,但没有解决方案.. 我相信,当将最初压缩且未编码的图像绘制到上下文中时,将图像解压缩并解码到“原始像素缓冲区”中,这似乎是合理的。这必然需要内存。现在的问题是,如何摆脱包含像素数据的内部缓冲区,除非绘制图像,否则不需要这些数据。当然,在释放 UIImage 对象之前,您需要将缩放后的图像写入磁盘。 好的,但是原始图像是 3264 x 2448 像素 x 4 字节/像素 = 32MB,最终图像是 1136x640,即 2.9MB... 将两个数字相加得到 35MB,而不是70! UIImage 缓存内部缓冲区。只有在内存不足的情况下,系统才可能决定“清除”缓存的缓冲区。这在“幕后”透明地发生。我不知道有什么方法可以控制UIImage 的这种行为。 NSImage 有一个 recache 方法。 @peko 完全正确。不是内存问题吗? 【参考方案1】:

答案是here

使用 CoreGraphics 并减少 30~40% 的内存。

    #import <ImageIO/ImageIO.h>
   -(UIImage*) resizedImageToRect:(CGRect) thumbRect

    CGImageRef          imageRef = [inImage CGImage];
    CGImageAlphaInfo    alphaInfo = CGImageGetAlphaInfo(imageRef);

    // There's a wierdness with kCGImageAlphaNone and CGBitmapContextCreate
    // see Supported Pixel Formats in the Quartz 2D Programming Guide
    // Creating a Bitmap Graphics Context section
    // only RGB 8 bit images with alpha of kCGImageAlphaNoneSkipFirst, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedFirst,
    // and kCGImageAlphaPremultipliedLast, with a few other oddball image kinds are supported
    // The images on input here are likely to be png or jpeg files
    if (alphaInfo == kCGImageAlphaNone)
        alphaInfo = kCGImageAlphaNoneSkipLast;

    // Build a bitmap context that's the size of the thumbRect
    CGContextRef bitmap = CGBitmapContextCreate(
                                                NULL,
                                                thumbRect.size.width,       // width
                                                thumbRect.size.height,      // height
                                                CGImageGetBitsPerComponent(imageRef),   // really needs to always be 8
                                                4 * thumbRect.size.width,   // rowbytes
                                                CGImageGetColorSpace(imageRef),
                                                alphaInfo
                                                );

    // Draw into the context, this scales the image
    CGContextDrawImage(bitmap, thumbRect, imageRef);

    // Get an image from the context and a UIImage
    CGImageRef  ref = CGBitmapContextCreateImage(bitmap);
    UIImage*    result = [UIImage imageWithCGImage:ref];

    CGContextRelease(bitmap);   // ok if NULL
    CGImageRelease(ref);

    return result;

作为类别添加到 UIImage。

【讨论】:

以上是关于使用太多内存来减少图像尺寸......有没有办法使用更少的内存来做到这一点?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法使用几何阅读器将我的 SwiftUI 图像的宽度定义为相对于屏幕尺寸?

使用 imagemagick 减少图像宽度和高度而不模糊

读取和写入大图像

通过使用另一个支持层减少 UILabel 的内存

使用巨大(6000+ 宽)图像调整 GD 图像大小(带 CI)

应用程序尺寸太大,因为图像太多