是否可以按字节而不是宽度和高度来调整图像大小?

moo*_*hen 1 reduce python-3.x image-size

我想将图像缩小到更小的尺寸,以便于共享和更快的上传。

但我意识到,如果我只是通过其硬件来减小尺寸,它并不能真正起到作用,因为大图像文件可能具有较小的硬件,而小图像文件可能具有较大的硬件,因此通过减小其高度来减小图像尺寸& 重量可能并不总是按照我想要的方式缩小尺寸。

所以现在我使用这个得到了字节大小:

import os
os.stat('myImage.jpg').st_size
Run Code Online (Sandbox Code Playgroud)

是否可以通过减少字节来减小图像大小?并保持其比例?

Jer*_*imo 5

这是我用 PIL 编写的一个函数。它对图像进行一些迭代调整大小和 jpeg 压缩,然后查看生成的文件大小并将其与目标值进行比较,根据大小偏差比猜测下一个最佳宽度/高度组合(基本上是某种 P 控制器)。

它利用 io.BytesIO 来完成内存中的所有大小调整工作,因此对磁盘上的文件实际上只有一次读取和一次写入访问。此外,通过这种强力方法,您可以将目标文件格式更改为 PNG,并且它可以开箱即用。

from PIL import Image
import os
import io

def limit_img_size(img_filename, img_target_filename, target_filesize, tolerance=5):
    img = img_orig = Image.open(img_filename)
    aspect = img.size[0] / img.size[1]

    while True:
        with io.BytesIO() as buffer:
            img.save(buffer, format="JPEG")
            data = buffer.getvalue()
        filesize = len(data)    
        size_deviation = filesize / target_filesize
        print("size: {}; factor: {:.3f}".format(filesize, size_deviation))

        if size_deviation <= (100 + tolerance) / 100:
            # filesize fits
            with open(img_target_filename, "wb") as f:
                f.write(data)
            break
        else:
            # filesize not good enough => adapt width and height
            # use sqrt of deviation since applied both in width and height
            new_width = img.size[0] / size_deviation**0.5    
            new_height = new_width / aspect
            # resize from img_orig to not lose quality
            img = img_orig.resize((int(new_width), int(new_height)))


limit_img_size(
    "test.jpg",   #  input file
    "test_with_limited_size.jpg",     #  target file
    50000,   # bytes    
    tolerance = 5    # percent of what the file may be bigger than target_filesize
)
Run Code Online (Sandbox Code Playgroud)

编辑:

“在内存中”我的意思是当循环中的 to 时,它会将其保存到一个save对象中,该img对象不是磁盘上的文件而是内存中的文件。然后,我可以从该对象确定生成的文件大小(这只是该数据缓冲区的长度),而无需实际将其保存到文件中。最后也许这正是您所期望的工作方式,但我见过太多代码由于缺乏对 Python 的.bufferBytesIOio.BytesIO

只有最终结果才会保存到文件中 - 这就是您想要的位置。尝试使用绝对文件名img_target_filename