在 Mail 中,当我添加图像并尝试发送它时,它会快速询问我要以哪种尺寸发送图像。看截图:
我想在我将上传图像的应用程序中做类似的事情,并希望用户能够在上传图像之前调整图像大小。像Apple在这里所做的那样估计文件大小的最佳方法是什么?
似乎实际上创建每个调整大小的图像只是为了检查它们的大小需要太长时间。有没有更好的办法?
我确实发现这个 Apple 示例代码有点帮助,但老实说有点不知所措。:)
在 Mail 中,当我添加图像并尝试发送它时,它会快速询问我要以哪种尺寸发送图像。看截图:
我想在我将上传图像的应用程序中做类似的事情,并希望用户能够在上传图像之前调整图像大小。像Apple在这里所做的那样估计文件大小的最佳方法是什么?
似乎实际上创建每个调整大小的图像只是为了检查它们的大小需要太长时间。有没有更好的办法?
我确实发现这个 Apple 示例代码有点帮助,但老实说有点不知所措。:)
决定最终压缩图像大小的最大因素不是图像大小或 JPEG 压缩质量,而是图像复杂度(点燃熵)。如果您知道您总是要处理高度详细的照片(而不是纯色场或渐变),这会在一定程度上减少沿该维度的差异,但是......
我花了相当多的时间对这个问题进行数值分析。我以 9 个不同的 JPEG 质量级别对一张详细的高分辨率图像的压缩图像大小进行了采样,该图像以 10 个百分点的增量缩小。这产生了一个描述隐式函数 z = (x, y) 的 3 维数据集,其中 x 是以像素为单位的缩放图像大小 (w*h),y 是 JPEG 压缩质量,z 是结果图像的大小以字节为单位。
由此产生的表面很难估计。与直觉相反,它具有振荡和多个拐点,这意味着 x 和 y 中的 2 次函数不足以拟合它,并且增加多项式次数和创建自定义拟合函数并没有产生明显更好的结果。它不仅不是线性关系,甚至不是单调关系。这很复杂。
让我们变得实用。请注意 Apple 何时提示您输入图像大小:当您点击“发送”时,而不是图像首次出现在邮件撰写视图中时。这可以让他们在必须准备好估计的图像尺寸之前撰写您的消息。所以我的怀疑是:他们做的很艰难。将图像缩放到不同大小可以在后台并行执行,即使在 iPhone 4 calibur 硬件上需要几秒钟,所有这些工作都可以对用户隐藏。如果您担心内存使用情况,您可以将图像写入临时文件并按顺序而不是并行渲染它们,这将使用不超过内存中未压缩文件的 2 倍内存。
总而言之:除非您对正在压缩的图像的预期熵有很多了解,否则对于某些类别的图像,任何估计函数都会非常不准确。如果你能处理好,那么对一些样本数据进行线性或二次拟合并产生一个用于估计目的的函数是相当容易的。但是,如果您想像 Apple 一样接近,您可能需要在后台进行实际的调整大小工作,因为构建一个始终正确的启发式方法的因素太多了。
我已经构建了一个可以调整图像大小的方法,如下所示:
-(UIImage *)resizeImage:(UIImage *)image width:(CGFloat)resizedWidth height:(CGFloat)resizedHeight
{
CGImageRef imageRef = [image CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef bitmap = CGBitmapContextCreate(NULL, resizedWidth, resizedHeight, 8, 4 * resizedWidth, colorSpace, kCGImageAlphaPremultipliedFirst);
CGContextDrawImage(bitmap, CGRectMake(0, 0, resizedWidth, resizedHeight), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage *result = [UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return result;
}
要获得图像的大小,您必须将其转换为NSData
,并询问长度:
UIImage* actualImage = [UIImage imageNamed:@"image"];
NSData* actualImageData = UIImagePNGRepresentation(actualImage);
NSLog(@"Actual %f KB", (CGFloat)actualImageData.length / (CGFloat)1024);
UIImage* largeImage = [self resizeImage:actualImage width:actualImage.size.width * 0.8 height:actualImage.size.height * 0.8];
NSData* largeImageData = UIImagePNGRepresentation(largeImage);
NSLog(@"Large %f KB", (CGFloat)largeImageData.length / (CGFloat)1024);
UIImage* mediumImage = [self resizeImage:actualImage width:actualImage.size.width * 0.5 height:actualImage.size.height * 0.5];
NSData* mediumImageData = UIImagePNGRepresentation(mediumImage);
NSLog(@"Medium %f KB", (CGFloat)mediumImageData.length / (CGFloat)1024);
UIImage* smallImage = [self resizeImage:actualImage width:actualImage.size.width * 0.3 height:actualImage.size.height * 0.3];
NSData* smallImageData = UIImagePNGRepresentation(smallImage);
NSLog(@"Small %f KB", (CGFloat)smallImageData.length / (CGFloat)1024);
如果将其存储到NSData
您可以调用[NSData length]
以获取包含的字节数,然后将其划分以获得适当的大小(以 kB 或 MB 为单位)
Mail 应用程序中提供的图像大小仅为估计值 - 发送图像的实际文件大小不同。将全尺寸图像(iPhone 4S 中为 3264 x 2448)转换为各种尺寸,只是为了获得文件大小也太慢了。
[编辑]
压缩文件大小不是线性的,因此您不能只获取 numPixels/filesize 来准确估计较小图像的文件大小。
所以这个答案并不是完全没用,这里是 Mail.app 导出的图像大小:
小号:320x240 中号:640x480 大号:1224x1632
您始终可以使用UIImageJPEGRepresentation
来压缩图像。四个选项可以是 0.25、0.5、0.75 和 1.0 范围内的值,它们的大小可以很容易地通过应用相同方法后的图像计算找到。