我正在构建一个 PHP 系统,用户可以创建一个视觉上复杂的图像,其最终要求是50kB 或更少。
用户可以选择将文本打印到 37 个模板图像之一上,因此结果是单个平面图像。
文本可以是任何颜色和多种字体之一。这意味着最终图像在视觉上可能相当复杂且不可预测(图像尺寸除外)。
然后我要求最终图像文件大小不大于50kB(这是外部要求,无法更改)。
最后一个要求(同样是外部要求)是图像格式必须为 .jpeg、.png 或 .gif。
我已经浏览了 GraphicsMagick 文档,但找不到任何提到能够设置文件大小并具有 自动计算压缩。
我考虑过通过压缩->保存->测试循环以编程方式执行此操作,但是我可以想象这将是相当处理器密集型的,因为我不一定能够提前根据压缩计算文件大小。这就是为什么我要求查看问题是否已在 GraphicsMagick 中得到解决。
编辑
要明确为什么存在外部要求:
用户将利用该系统创建平面图像,然后将其保存到 PC 上。然后将该图片上传到 Adroll 以用于重定向营销活动。
以下是 Adroll 对图片的要求。我的系统仅提供 728x90、300x250 和 120x600 图像尺寸。
编辑 2010年11月27日
由于这对于GraphicsMagick来说似乎不可能,我愿意研究其他解决方案,例如直接与压缩库(libpng等)连接,它可能能够提供功能。
作为最后的手段,我什至可以研究可以实现这一目标的算法并自己实现一个。
打个比方,对于那些有这种倾向的人来说:
我追求的是A*的搜索:它有明确的起点/终点,并在最快的时间内找到最佳的路线。
我希望避免的是广度/深度优先搜索:明确的起点/终点,但一旦找到局部最小值,可能无法找到最佳解决方案,并且有可能在计算上完全崩溃。
I am building a PHP system whereby users can create a visually complex image that has the final requirement of being 50kB or less.
The user can select to have text printed onto one of 37 template images, so the result is a single flat image.
The text can be any colour and one of a number of fonts. This means the final image can be quite visually complex and unpredictable (with the exception of image dimensions).
I then have the requirement of having the final image file size no greater than 50kB (this is an external requirement and cannot be changed).
The last requirement (again, external) is the image format must be .jpeg, .png, or .gif.
I have looked through the GraphicsMagick documentation, but cannot find anywhere that mentions being able to set the filesize and have the compression automatically calculated.
I have considered doing this programatically via a compress->save->test loop, however I can imagine this would be quite processor intensive as I cannot necessarily calculate the filesize based on compression in advance. This is why I am asking to see if the problem has already been solved in GraphicsMagick.
Edit
To be clear as to why there are external requirements:
The user will utilize this system to create a flat image, which they will then save onto their PC. This image is then to be uploaded to Adroll for use in a Retargeting campaign.
Here are Adroll's requirements on the image. My system will only provide the 728x90, 300x250, and 120x600 image sizes.
Edit 27th Nov, 2010
As this does not seem to be possible with GraphicsMagick, I am willing to look into other solutions, such as directly interfacing with compression libraries (libpng, etc) which may be able to provide the functionality.
As a last resort, it my even be feasible to look at algorithms which can accomplish this and implement one myself.
As an analogy, for those who are that way inclined:
I am after what A* is to search: It has a definite starting/ending point, and finds the best possible route in the fastest time.
What I was hoping to avoid was what Breadth/Depth First is to Search: definite starting/ending points, but may not hit on the optimal solution once finding a local minimum, and has the potential to completely blow out computationally.
发布评论
评论(9)
由于无法压缩到我所知道的目标大小,我建议寻找一种间接解决方案:
详细说明一下步骤 2 中的数学:
如果您选择起始质量,使得平均计算大小 + 3 * 标准差 <如果您的目标大小,那么 99.7% 的压缩将在第一次尝试时生成一个适当的小文件(假设压缩大小呈正态分布)。
您可以根据需要调整起始质量以及增加或减少质量的逻辑,在较少的服务器负载和更接近最大大小的文件之间进行平衡(“更好地利用”您的限制)。
Since there is no way to compress to a target size that I know of, I suggest looking into an indirect solution:
To elaborate a bit on the maths in step 2:
If you choose your starting quality such that your mean calculated size + 3 * standard deviation < your target size, then 99.7% of compressions will result in a suitably small file on the first try (assuming a normal distribution of compressed sizes).
You can tweak the starting quality and the logic that increases or decreases it as you wish, balancing between less server load and files closer to your maximum size ("making better use" of your restrictions).
看一下以下包:
http://www.phpclasses.org/package/3810-PHP-Optimize-images-to-fit-in-a-given-file-size-limit.html
漂亮酷 - 我想说作者应该喝一杯啤酒;)
示例图像实际上是 61081 字节(第一个在图像中显示文件大小的 jpeg 图像?):
Have a look at the following package:
http://www.phpclasses.org/package/3810-PHP-Optimize-images-to-fit-in-a-given-file-size-limit.html
Pretty cool - I'd say the author deserves a beer ;)
Example image which is actually 61081 bytes (first ever jpeg image to show file size in image?):
是否可以将 GraphicMagick 的“-limit disk 50mb”与“-list resources”结合使用,以便您可以在过程中尽早检查(或者实际上在整个过程中进行轮询)并进行调整以适应?
http://www.graphicsmagick.org/GraphicsMagick.html#details-limit
Would it be possible to use GraphicMagick's "-limit disk 50mb" in coalition with "-list resource" so you can check this early on in (or indeed polled throughout) the process and make adjustments to suit?
http://www.graphicsmagick.org/GraphicsMagick.html#details-limit
我不知道有什么方法可以自动确定图像的最终文件大小 - 这是生成图像的库的任务。除非您自己实现压缩,否则无法预先计算结果大小。
您可以做的是收集统计数据(图像高度和宽度以及文件大小与不同的压缩选项),并根据新图像的数据进行估计。
示例:
->当你得到一个 59k 的 100x202px 图像时,压缩后的大小将大致估计为 35k。
I do not know of a way to automatically determine the resulting file size of an image - that's task of the library generating the image. Unless you implement the compression yourself, you cannot pre-calculate the resulting size.
What you could do is collect statistical data (image height and width and file size vs. different compression options) and do your estimations based on that data for new images.
Example:
-> when you get a 100x202px image with 59k, the compressed size will be roughly estimated 35k.
所以,如果我理解正确的话 - 您正在构建一个系统,允许用户在您提供的模板图像之一上编写一些文本。如果这是正确的,你为什么要保存图像?您可以通过保存用户操作本身轻松消除 50Kb 大小限制。您也许可以执行类似的操作 - 保存文本(及其属性和位置)及其所在的模板。
So, if I understand this correctly - You are building a system which allows users to write some text on one of the template images that you provide. If that is correct, why are you saving the image at all? You can easily remove the 50Kb size limit by saving the user actions itself. You might be able to do something like - save the text (along with its properties and location) and the template it is on.
只有三种方法可以减小任何给定图像的最终尺寸:
前两种方法由您控制。如果上传的图像的文件大小超过限制,您可以尝试将其缩小到下一个较小的可用大小,看看是否适合该限制。鉴于您只有 3 个目标分辨率,这不会太昂贵。但如果您需要“大”尺寸可用,那么您就只剩下选项 3。
降低图像复杂性是一件令人讨厌的事情。您可以尝试减少像素间“噪声”以产生相同颜色的更大区域,这将在 GIF/PNG 图像中很好地压缩。一个简单的模糊滤镜可以实现这一点,但它也可能会破坏图像中任何精细印刷/文本的可读性。对于 JPG 目标,您可以尝试降低压缩质量,但同样,如果质量降得太低,这可能会破坏图像。如果简单的服务器端转换无法处理此问题,则图像必须由最初创建它的艺术家重做。
我能看到的自动化此操作的唯一实用方法是您提到的压缩保存测试循环。鉴于最终图像相对较小,这不会给服务器带来太大的负担。保存 gif/png 是一项轻量级操作。 JPG 压缩需要更多的 CPU 能力,但同样,对于小图像,现代服务器在一两秒内处理 10 或 20 个测试图像应该不会有任何问题。
There's only three ways to reduce the final size of any given image:
The first two are under your control. If the uploaded image comes out with a file size over the limit, you can try shrinking it to the next smaller available size and see if it fits into that. Given you've only got 3 target resolutions, this wouldn't be too expensive. But if you need the "large" size to be available, then you're left with option 3.
Reducing image complexity is a nasty beast. You can try to reduce inter-pixel "noise" to produce larger areas of the same color, which will compress in GIF/PNG images very nicely. A simple blur filter could accomplish this, but it might also destroy the legibility of any fine print/text within the image. For a JPG target, you can try to lower the compression quality, but again, this can trash images if you take the quality down too low. If simple server-side transforms can't handle this, the image would have to be redone by the artist who created it in the first place.
The only practical method I can see to automate this is the compress-save-test loop you mention. Given that the final images are relatively small, this won't be that large a burden on the server. Saving a gif/png is a lightweight operation. JPG compression takes more CPU power, but again, with small images, a modern server shouldn't have any trouble doing 10 or 20 test images within a second or two.
虽然循环直到达到目标文件大小的编程选项似乎是流行的答案,但有两种方法可以使用 .jpeg 压缩来实现此目的:
有一种专利方法作者:Kuo, Chun-ming,所以我不确定利用它的商业可行性:
方法和调整 jpeg 图像压缩比的电子设备
基于以下公式:
其中
不清楚 SF1、SF2 和 NSF 是否在 0-1、或 0-100 等范围内,以及 FileSize1 是否在、FileSize2 和 Target 的单位为字节、千字节等。在此处尝试正确的组合以找出正确的单位。
The second method comes from Ricky D. Nguyen at MIT:
JPEG 转码的速率控制和位分配
他建议改变用于压缩的数据当它发生的时候。该选项实施起来可能不太可行,因为它需要修改实际的压缩代码本身。
从这两个示例来看,当然可以保存具有特定目标文件大小的 .jpeg 文件。
Whilst the programmatic option of looping until the target filesize is reached seems to be the popular answer, there are two ways to do this with .jpeg compression:
There is a patented method by Kuo, Chun-ming, so I'm not sure of the commercial viability of utilizing it:
Method and electronic device for adjusting compression ratio of jpeg image
Which is based on this formula:
Where
It's not clear if SF1, SF2, and NSF are in the range 0-1, or 0-100, etc, and if the FileSize1, FileSize2, and Target are in Bytes, KiloBytes, etc. Experiment with the correct combination here to find out the correct units.
The second method comes from Ricky D. Nguyen at MIT:
Rate control and bit allocations for JPEG transcoding
He suggests varying the data that is used for the compression while it's happening. This option may not be as feasible to implement as it requires modifications to the actual compression code itself.
From both of these examples, it is certainly possible to save out a .jpeg file with a certain target file size.
首先尝试 24 位 .png。如果合适的话,这将是最好的质量,然后你就完成了。或者,您可以测试一些典型的图像,如果它们都不适合,您可以完全不考虑该格式。
对于 .gif 和 .jpg,您需要搜索最合适的;两种算法都无法以足够的确定性进行预测,并且两种算法都不适合恒定比特率编码。您可以使用二分搜索来找到最合适的。您可以从预定列表中选择压缩系数,以限制需要执行的测试压缩次数;例如,如果您的 .jpg 压缩系数列表为 4、6、8、12、18、27、44、66,则您最多需要进行 4 次测试压缩。
.gif 和调色板 .png 非常相似,您应该只选择一个而忽略另一个。
根据压缩结果,很难在 .gif/.png 和 .jpg 之间做出选择;每个过程引入的工件完全不同。同样,您最好的方法可能是将多个测试图像压缩到目标大小,并根据眼球测试消除一种或另一种格式。
Try 24-bit .png first. If that fits it will be the best quality, and you're done. Alternatively you could test some typical images and if none of them fit, you could eliminate the format from consideration altogether.
For the .gif and .jpg you'll need to search for the best fit; neither one can be predicted with enough certainty, and neither algorithm is suitable for constant bit rate encoding. You can use a binary search to find the best fit. You can choose compression factors from a predetermined list to limit the number of test compressions you need to do; for example if your list of .jpg compression factors is 4, 6, 8, 12, 18, 27, 44, 66, you would need to do 4 test compressions at most.
.gif and paletted .png are similar enough that you should just pick one and forget about the other.
It will be tough to choose between .gif/.png and .jpg based on the compression results; the artifacts introduced by each process are completely different. Again you might be best off by compressing a number of test images to your target size, and eliminating one format or the other based on eyeball testing.
也许您从错误的角度看待问题。通过选择使用 PNG 并最小化图像中存储的元数据,您可以最小化文件大小。这是因为 PNG 是位图结构。只要 GMagick 不将文本存储为元数据,它就不会对文件大小产生影响。只有颜色深度(您也可以控制)会影响文件的大小。不带过滤的逐行扫描文件大小应与模板大小基本相同。只要模板小于 50Kb 就应该没问题。
Purhaps you are looking at the problem from the wrong angle. By selecting to use PNG and minimizing the metadata stored in the image you will minimize the file size. This is because PNG is a Bitmap structure. So long as GMagick does not store the text as metadata it will have no impact on the file size. Only the color depth (which you can also control) will impact the size of the file. Non-interlaces without filtering the file size should be essentially the same as the template size. So long as the templates are less than 50Kb you should be alright.