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

Is it possible to resize an image by its bytes rather than width and height?

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

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

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

import os
os.stat('myImage.jpg').st_size

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

这是我用PIL写的一个函数。它对图像进行一些迭代调整大小和 jpeg 压缩,然后查看生成的文件大小并将其与目标值进行比较,根据大小偏差比猜测下一个最佳 width/height 组合(基本上是某种 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
)

编辑:

With "in memory" 我的意思是当循环中 saveimgbuffer 时,它会将其保存到 BytesIO 对象中,这不是磁盘上的文件,而是内存中的文件。然后我可以从该对象确定生成的文件大小(这只是该数据缓冲区的长度),而无需实际将其保存到文件中。最后也许这就是您期望它的工作方式,但我已经看到太多代码由于缺乏对 Python 的 io.BytesIO 的了解而在磁盘上保存文件时浪费性能.

只有最终结果会保存到文件中 - 这就是您想要的位置。尝试为 img_target_filename.

使用绝对文件名

刚好有个朋友需要resize/rescale个人头像,要求头像最大40KB。考虑到磁盘上的大小,我将以下代码写入 downscale/rescale 图像。我假设 40KB = 40000Bytes 这不准确但它可以派上用场

from skimage.io import imread, imshow
from skimage.transform import rescale, resize, downscale_local_mean
from skimage.io import imsave
import matplotlib.pyplot as plt
import os
import numpy as np

img = imread('original.jpg')
target_size = 40000
size = os.path.getsize('original.jpg')
factor = 0.9
while(size>=40000):
    image_rescaled = rescale(img, factor, anti_aliasing=False)
    imsave('new.jpg', image_rescaled)
    print('factor {} image of size {}'.format(factor,size))
    factor = factor - 0.05
    size = os.path.getsize('new.jpg')

end_size = os.path.getsize('new.jpg')
print(end_size)

希望对你有帮助!!!! 你可以在 GitHub 上以 LeningGF

关注我