如何将JPEG文件大小减小到“所需大小”?

6
在Python 3.x中,我正在使用PIL来调整图像大小,我知道我们可以通过减去或除以像素来减小高度或宽度。但是,是否可以将图像调整为所需的大小,例如200kb,并保持其比例不变?假设图像较大但大小未知。

1
如果不进行编码,预测将会很困难甚至不可能。如果您准备好进行编码,那么可以使用二分查找。 - Peter Wood
你可以使用垃圾数据填充文件。 - Peter Wood
@PeterWood,您所说的“用垃圾填充文件”是什么意思?非常感谢您的建议。 - moomoochen
ImageMagick正是提供了这种能力。你可以使用子进程*"shell out"*(即外壳脚本)并像此处所示https://stackoverflow.com/a/30194093/2836621一样使用命令行工具。或者,您可以使用二进制搜索将jpeg编码为存储在内存中的bytesio缓冲区,并具有不同的质量而无需写入磁盘。 - Mark Setchell
@MarkSetchell,我在这里非常困惑...所以我不能使用PIL来实现这个吗?我已经看了你关于ImageMagick的建议,但是我完全迷失了。我能用Jupyter笔记本来做这个吗? - moomoochen
显示剩余2条评论
1个回答

16

我仍在学习Python,所以可能有更好的方法,但是这里有一个函数,它可以将PIL/Pillow图像保存为JPEG,并允许您指定最大尺寸。

它使用二分搜索来最小化所需的工作量,并将编码到BytesIO内存缓冲区中以避免将图像写入磁盘。如果有人对改进有任何建议,请告诉我!

#!/usr/local/bin/python3

import io
import math
import sys
import numpy as np
from PIL import Image

def JPEGSaveWithTargetSize(im, filename, target):
   """Save the image as JPEG with the given name at best quality that makes less than "target" bytes"""
   # Min and Max quality
   Qmin, Qmax = 25, 96
   # Highest acceptable quality found
   Qacc = -1
   while Qmin <= Qmax:
      m = math.floor((Qmin + Qmax) / 2)

      # Encode into memory and get size
      buffer = io.BytesIO()
      im.save(buffer, format="JPEG", quality=m)
      s = buffer.getbuffer().nbytes

      if s <= target:
         Qacc = m
         Qmin = m + 1
      elif s > target:
         Qmax = m - 1

   # Write to disk at the defined quality
   if Qacc > -1:
      im.save(filename, format="JPEG", quality=Qacc)
   else:
      print("ERROR: No acceptble quality factor found", file=sys.stderr)

################################################################################
# main
################################################################################

# Load sample image
im = Image.open('/Users/mark/sample/images/lena.png')

# Save at best quality under 100,000 bytes
JPEGSaveWithTargetSize(im, "result.jpg", 100000)

如果我按原样运行,目标大小为100,000字节,我会得到:

-rw-r--r--@   1 mark  staff     96835 11 Sep 18:21 result.jpg

如果我将目标大小更改为50,000字节,我会得到:

-rw-r--r--@   1 mark  staff     49532 11 Sep 18:26 result.jpg

关键词:Python、PIL、Pillow、JPEG、质量、质量设置、最大尺寸、图像处理、二分搜索。


我从你的else语句中得到了一个错误,"ERROR: No acceptble quality factor found"。我做错了什么? - moomoochen
1
如果没有看到您的图像和您指定的目标大小,我无法确定。如果您尝试将一个8,000 x 6,000像素的图像压缩到5,000字节,它会遇到困难。请分享你的图像和目标大小,或者尝试增加目标大小以增加成功的机会。 - Mark Setchell
1
请问您能否澄清一下,您尝试压缩的图片尺寸(以像素为单位)和您指定的目标尺寸是多少呢?因为我已经成功地在许多文件上尝试过了。 - Mark Setchell
抱歉回复晚了,可以告诉我你使用的是哪个IDE?还有你使用的是哪个操作系统?非常感谢 :) - moomoochen
1
我不使用集成开发环境(IDE),我只是将代码输入到编辑器中(vi,并不会有任何区别),然后保存并运行它。我在Mac和Debian上测试了这段代码。你知道格式化(缩进)是非常重要的,对吧? - Mark Setchell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接