【问题标题】:Compress images to reduce file size压缩图像以减小文件大小
【发布时间】:2013-09-11 23:35:57
【问题描述】:

我正在构建一个应用程序,让用户可以拍照或从 iPhone 上的库中选择一张照片并将其上传到 Parse 后端。

我面临的问题是关于文件的大小。

我已了解 Facebook、Twitter、Instagram 和 Google 等大公司在分辨率和文件大小方面的做法,但我无法接近。

我确信他们拥有最好的代码和工具来做到这一点,但我很乐意使用 iOS 常规流程尽可能好地实现它。

这就是我现在正在做的事情:

- (UIImage *)normalResImageForAsset:(ALAsset*)asset
{
    // Convert ALAsset to UIImage
    UIImage *image = [self highResImageForAsset:asset];

    // Determine output size
    CGFloat maxSize = 1024.0f;
    CGFloat width = image.size.width;
    CGFloat height = image.size.height;
    CGFloat newWidth = width;
    CGFloat newHeight = height;

    // If any side exceeds the maximun size, reduce the greater side to 1200px and proportionately the other one
    if (width > maxSize || height > maxSize) {
        if (width > height) {
            newWidth = maxSize;
            newHeight = (height*maxSize)/width;
        } else {
            newHeight = maxSize;
            newWidth = (width*maxSize)/height;
        }
    }

    // Resize the image
    CGSize newSize = CGSizeMake(newWidth, newHeight);
    UIGraphicsBeginImageContext(newSize);
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Set maximun compression in order to decrease file size and enable faster uploads & downloads
    NSData *imageData = UIImageJPEGRepresentation(newImage, 0.0f);
    UIImage *processedImage = [UIImage imageWithData:imageData];

    return processedImage;
}

我正在尝试将 1024px 设为允许的最大尺寸(均具有 ot 高度)以在此处开始一些限制,然后我正在应用最大压缩以减小尺寸。

这种方法可以将图像大小减少大约 50%,而不会真正损坏 JPEG,但仍然很多。特别是如果照片是用手机的相机拍摄并上传的。处理后的图像仍然很容易有 1MB 大小,这太大了。

我猜我可能遗漏了一些有用的步骤或使用了错误的技术。

任何反馈都将不胜感激。

【问题讨论】:

  • 我想知道从 UIImage 到 NSData 再回到 UIImage 的往返过程。你在初始化一个新的 UIImage 之前检查了 [imageData length] 吗?也许你想从这个函数中返回编码后的 NSData 对象,这样你就可以将字节数组上传到服务器。
  • 允许用户选择图像大小,并在需要时警告他们要上传的数据大小。
  • @Wain 但是OP是对的,在1024x768px,完全压缩的jpeg图像不应该占用1MB。
  • 我正在使用 Aviary 照片编辑器并遵循文档示例,这是向他们传递数据的方式。也许不是唯一的方法,但这可以解释我为什么要往返。使用 PNG 文件时,压缩按预期工作,但 JPEG 可能已经太压缩而无法像这样工作。

标签: ios compression jpeg image-size


【解决方案1】:

我遇到了类似的问题,我还认为压缩不起作用。结果在我的代码的其他地方我正在使用不同的压缩将文件写入磁盘。您可能正在对这个函数返回的数据做同样的事情。检查压缩是否有效的一个好方法是执行以下操作:

NSData *imgData1 = UIImageJPEGRepresentation(newImage, 1.0f);
NSLog(@"1.0 size: %d", imgData1.length);

NSData *imgData2 = UIImageJPEGRepresentation(newImage, 0.7f);
NSLog(@"0.7 size: %d", imgData2.length);

NSData *imgData3 = UIImageJPEGRepresentation(newImage, 0.4f);
NSLog(@"0.4 size: %d", imgData3.length);

NSData *imgData4 = UIImageJPEGRepresentation(newImage, 0.0f);
NSLog(@"0.0 size: %d", imgData4.length);

// Don't convert NSData back to UIImage before writing to disk
[imgData4 writeToFile:imagePath atomically:YES];

我使用的是 640x480 的图像,文件大小从 325 kB(对于 1.0)到 18 kB(对于 0.0)不等

【讨论】:

  • 一旦上传到服务器,可能无法重建实际图像。可能并非在所有情况下都有用。
【解决方案2】:

@codeMonkey 的 Swift-3 版本:-

它在图像压缩方面完美

func compressImage() -> UIImage {

        let oldImage = UIImage(named: "background.jpg")
        var imageData =  Data(UIImagePNGRepresentation(oldImage!)! )
        print("***** Uncompressed Size \(imageData.description) **** ")

        imageData = UIImageJPEGRepresentation(oldImage!, 0.025)!
        print("***** Compressed Size \(imageData.description) **** ")

        let image = UIImage(data: imageData)
        return image!

    }

【讨论】:

  • 图片质量怎么样?
  • 压缩会改变质量。
  • 它会降低图片的质量。所以,这可能不是正确的解决方案。
  • 感谢您提供这个快速简单的解决方案...降低质量对我来说不是一个因素,因为我的压缩只是基于“分享”到第三部分社交媒体
【解决方案3】:
Please Try below answer.

+(UIImage *)compressImage:(UIImage *)image{
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float maxHeight = 1136.0f;
float maxWidth = 640.0f;
float imgRatio = actualWidth/actualHeight;
float maxRatio = maxWidth/maxHeight;
float compressionQuality = 1;//50 percent compression

if (actualHeight > maxHeight || actualWidth > maxWidth){
    if(imgRatio < maxRatio){
        //adjust width according to maxHeight
        imgRatio = maxHeight / actualHeight;
        actualWidth = imgRatio * actualWidth;
        actualHeight = maxHeight;
    }
    else if(imgRatio > maxRatio){
        //adjust height according to maxWidth
        imgRatio = maxWidth / actualWidth;
        actualHeight = imgRatio * actualHeight;
        actualWidth = maxWidth;
    }
    else{
        actualHeight = maxHeight;
        actualWidth = maxWidth;
    }
}else{
    actualHeight = maxHeight;
    actualWidth = maxWidth;
    compressionQuality = 1;
}

CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
NSData *imageData = UIImageJPEGRepresentation(img, compressionQuality);
UIGraphicsEndImageContext();

return [UIImage imageWithData:imageData];
}

【讨论】: