如何保存具有特定文件大小的图像?
Posted
技术标签:
【中文标题】如何保存具有特定文件大小的图像?【英文标题】:How to save an image with a specific filesize? 【发布时间】:2011-05-14 04:42:45 【问题描述】:我正在构建一个 php 系统,用户可以创建一个视觉复杂图像,最终要求 50kB 或更少。
用户可以选择将文本打印到 37 个模板图像之一上,因此结果是单个平面图像。
文本可以是任何颜色和多种字体中的一种。这意味着最终图像在视觉上可能非常复杂且不可预测(图像尺寸除外)。
然后我要求最终图像文件大小不大于 50kB(这是外部要求,无法更改)。
最后一个要求(同样是外部的)是图像格式必须是 .jpeg、.png 或 .gif。
我浏览了GraphicsMagick 文档,但找不到任何提到能够设置文件大小并自动计算压缩的地方。
我考虑过通过 compress->save->test 循环以编程方式执行此操作,但是我可以想象这将是处理器密集型的,因为我不一定能提前根据压缩计算文件大小。这就是为什么我要求查看问题是否已经在 GraphicsMagick 中解决了。
编辑
要明确为什么会有外部要求:
用户将利用此系统创建平面图像,然后将其保存到他们的 PC 上。然后将此图片上传到Adroll,用于重新定位广告系列。
这是图片上的Adroll's requirements。我的系统将只提供 728x90、300x250 和 120x600 的图像尺寸。
编辑 2010 年 11 月 27 日
由于 GraphicsMagick 似乎无法做到这一点,我愿意研究其他解决方案,例如直接与能够提供该功能的压缩库(libpng 等)接口。
作为最后的手段,我什至可以看看可以实现这一点的算法并自己实现一个。
打个比方,对于那些有这种倾向的人:
我追求的是 A* 的搜索:它有明确的起点/终点,并在最快的时间内找到可能的最佳路线。
我希望避免的是广度/深度优先是搜索:确定的起点/终点,但一旦找到局部最小值就可能无法达到最佳解决方案,并且有可能在计算上完全崩溃。
【问题讨论】:
你的目标格式是什么,JPG? 道歉;它可以是 .jpeg、.png 或 .gif - 更新问题以反映这一点。 你能告诉我图片的尺寸是多少吗?这将对图像大小设置上限。另外,对画质有什么要求?毕竟,最终用户可能无法接受高度压缩的 JPEG。 图片尺寸将为以下之一:728x90、300x250 或 160x600。图像质量是最好的(图像最终将用于广告环境),但 50KB 的要求高于任何质量要求。尽管在这种情况下大小限制为 50KB,但我最感兴趣的是可以适应任何文件大小限制的过程。 【参考方案1】:看看下面的包:
http://www.phpclasses.org/package/3810-PHP-Optimize-images-to-fit-in-a-given-file-size-limit.html
很酷 - 我会说作者应该喝啤酒;)
实际上是 61081 字节的示例图像(第一个在图像中显示文件大小的 jpeg 图像?):
【讨论】:
+1 我在最终解决方案中使用了这个类。感谢您指出! 这个类必须在自身内部使用某种预扫描或反复试验......所以,它是“反复试验”的抽象。 似乎做得很好【参考方案2】:也许您从错误的角度看待问题。通过选择使用 PNG 并最小化存储在图像中的元数据,您将最小化文件大小。这是因为 PNG 是位图结构。只要 GMagick 不将文本存储为元数据,它就不会影响文件大小。只有颜色深度(您也可以控制)会影响文件的大小。不过滤文件大小的非交错应该与模板大小基本相同。只要模板小于 50Kb 就可以了。
【讨论】:
【参考方案3】:首先尝试 24 位 .png。如果合适,它将是最好的质量,你就完成了。或者,您可以测试一些典型的图像,如果它们都不适合,您可以完全排除这种格式。
对于 .gif 和 .jpg,您需要搜索最合适的;这两种算法都不能有足够的把握进行预测,而且这两种算法都不适用于恒定比特率编码。您可以使用二分搜索来找到最合适的。您可以从预先确定的列表中选择压缩系数,以限制您需要进行的测试压缩次数;例如,如果您的 .jpg 压缩因子列表为 4、6、8、12、18、27、44、66,则您最多需要进行 4 次测试压缩。
.gif 和调色板 .png 非常相似,您应该只选择一个而忘记另一个。
根据压缩结果在 .gif/.png 和 .jpg 之间进行选择会很困难;每个过程引入的工件是完全不同的。同样,您最好将一些测试图像压缩到您的目标大小,并根据眼球测试消除一种或另一种格式。
【讨论】:
【参考方案4】:虽然循环直到达到目标文件大小的编程选项似乎是流行的答案,但有两种方法可以使用 .jpeg 压缩:: p>
郭春明有一个专利方法,所以我不确定使用它的商业可行性:
Method and electronic device for adjusting compression ratio of jpeg image
这是基于这个公式:
log(NSF) = (log(SF1 / SF2) / log(FileSize1 / FileSize2)) * log(Target / FileSize1) + log(SF1)
在哪里
SF1 is a first compression parameter
SF2 is a second compression parameter
FileSize1 is the size of the image compressed with SF1
FileSize2 is the size of the image compressed with SF2
Target is the target file size
NSF is the target compression parameter.
不清楚 SF1、SF2 和 NSF 是否在 0-1 或 0-100 等范围内,以及 FileSize1、FileSize2 和 Target 是否以 Bytes、KiloBytes 等为单位。尝试正确的组合在这里找出正确的单位。
第二种方法来自 MIT 的 Ricky D. Nguyen:
Rate control and bit allocations for JPEG transcoding
他建议在压缩过程中改变用于压缩的数据。此选项可能无法实现,因为它需要修改实际的压缩代码本身。
根据这两个示例,当然可以保存具有特定目标文件大小的 .jpeg 文件。
【讨论】:
【参考方案5】:由于无法压缩到我知道的目标大小,我建议寻找间接解决方案:
-
做一些快速统计(可能通过使用不同的 JPEG 压缩系数压缩大量图像)来找出给定质量级别的平均压缩大小及其标准偏差。
在接受图像时,尝试以合适的质量进行压缩。如果生成的文件太大,请降低质量并重试。或者,如果结果太小,您也可以提高质量。
当生成的图像“接近”您的目标尺寸但更小时停止。
详细说明第 2 步中的数学:
如果您选择起始质量,使得平均计算大小 + 3 * 标准偏差
您可以根据需要调整启动质量和增加或减少它的逻辑,在较少的服务器负载和接近最大大小的文件之间取得平衡(“更好地利用”您的限制)。
【讨论】:
这正是我的做法(不是以编程方式,使用 GIMP,正如您可以通过滑块看到的文件大小(如果您检查了预览 - 显然会为预览创建临时文件))我需要一张图片来满足网站上传限制的特定文件大小。 +1 这似乎是普遍的共识,因为没有人知道如何通过算法来做到这一点。虽然是一个潜在的解决方案(并且经过深思熟虑,谢谢!),但我仍然愿意等待,看看是否有其他人能提出算法解决方案。 你能不能给我一些建议***.com/questions/38144543/…谢谢【参考方案6】:是否可以将 GraphicMagick 的“-limit disk 50mb”与“-list resource”结合使用,以便您可以在整个过程中及早检查(或实际上在整个过程中进行轮询)并进行调整以适应?
http://www.graphicsmagick.org/GraphicsMagick.html#details-limit
【讨论】:
这不只适用于图像的未压缩、原始、工作副本吗? 啊,是的,我认为您重新阅读是对的。不幸的是,我认为也许上面的试错方法看起来越来越像解决方案了。 同样感谢 :) 我投了反对票,因为它没有回答这个问题,并给另一个答案提供赏金的机会。 别担心,也许它真的应该是一个评论。 ;oD【参考方案7】:只有三种方法可以减小任何给定图像的最终尺寸:
-
降低分辨率
降低颜色深度
降低图像复杂度
前两个在您的控制之下。如果上传的图片文件大小超过限制,您可以尝试将其缩小到下一个更小的可用大小,看看它是否适合。鉴于您只有 3 个目标分辨率,这不会太贵。但是,如果您需要“大”尺寸可用,那么您就剩下选项 3。
降低图像复杂性是一头讨厌的野兽。您可以尝试减少像素间“噪声”以产生更大的相同颜色区域,这将在 GIF/PNG 图像中很好地压缩。一个简单的模糊滤镜可以实现这一点,但它也可能破坏图像中任何精美印刷品/文本的易读性。对于 JPG 目标,您可以尝试降低压缩质量,但同样,如果您将质量降低得太低,这可能会破坏图像。如果简单的服务器端转换无法处理此问题,则图像必须由最初创建它的艺术家重做。
我能看到的唯一可行的自动化方法是您提到的 compress-save-test 循环。鉴于最终的图像相对较小,这不会对服务器造成太大的负担。保存 gif/png 是一种轻量级的操作。 JPG 压缩需要更多的 CPU 资源,但同样,对于小图像,现代服务器在一两秒内处理 10 或 20 个测试图像应该不会有任何问题。
【讨论】:
这主要是对替代解决方案的描述(自提出问题以来我已经考虑过)。我希望不是通过降低图像复杂性、颜色深度等来“猜测”,而是有一种算法方法可以将压缩推向目标文件大小。与广度优先或深度优先相比,A* 的搜索方式有点类似于简单地在第一个有效结果处停止。不过,感谢您的 cmets!【参考方案8】:所以,如果我理解正确 - 您正在构建一个允许用户在您提供的模板图像之一上写一些文本的系统。如果这是正确的,你为什么要保存图像?您可以通过保存用户操作本身轻松消除 50Kb 大小限制。您可能可以执行以下操作 - 保存文本(连同其属性和位置)和它所在的模板。
【讨论】:
您是正确的,因为这是可能的,但是 50kB 限制是无法更改的外部限制 - 必须保存展平图像,并且必须小于 50kB 才能在外部使用。跨度> 能否详细说明项目的用例?如果您能给我们提供功能需求(从最终用户的角度),您可能会得到更好的解决方案。你说的外部工具是什么?它是您开发的东西还是任何图片查看器? 我已经用要求的描述更新了问题。【参考方案9】:我不知道如何自动确定图像的最终文件大小 - 这是生成图像的库的任务。除非您自己实现压缩,否则您无法预先计算结果大小。
您可以做的是收集统计数据(图像高度和宽度以及文件大小与不同的压缩选项),并根据这些数据对新图像进行估计。
例子:
50k jpg,100x200 压缩为 30k 100k jpg,100x200 压缩为 60k->当你得到一个59k的100x202px的图片时,压缩后的大小大概会估计为35k。
【讨论】:
问题是,图像可能会有很大差异。当我们来到jpeg压缩时,宽度/高度/压缩比与最终压缩后的大小没有密切关系。 这就是为什么您可以收集有关原始文件大小和高度/宽度与压缩文件大小的数据的原因。我希望原始文件大小可以作为压缩文件的指标。 图像的文件大小与其尺寸并不完全成正比,因为压缩量取决于其复杂性。虽然,您可以从最复杂的图像之一中获得此等式的上限,但是始终考虑最坏的情况会丢失一些 KB。 是的,这就是我说“估计”的原因:)以上是关于如何保存具有特定文件大小的图像?的主要内容,如果未能解决你的问题,请参考以下文章
Android - 将 ImageView 保存到具有全分辨率图像的文件
如何将具有特定大小的字符复制到另一个图像中与原始图像相同的位置?