Python PIL:查找图像的大小而不将其写为文件 [英] Python PIL: Find the size of image without writing it as a file

查看:152
本文介绍了Python PIL:查找图像的大小而不将其写为文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:此问题已被标记为重复?我的问题显然是关于优化这个过程,而不是如何去做。我甚至提供了代码来证明我已经找到了后者。在你标记它们之前,你的互联网大厅监视器是否甚至通过标题阅读了这些问题?

我有以下代码块来使用PIL压缩图像,直到所述图像小于一定大小。

I have the following block of code to compress an image using PIL, until said image is under a certain size.

from PIL import Image
import os

def compress(image_file, max_size, scale):
    while os.path.getsize(image_file) > max_size:
        pic = Image.open(image_file)
        original_size = pic.size
        pic = pic.resize((int(original_size[0] * scale),
            int(original_size[1] * scale)),
            Image.ANTIALIAS)
        pic.save(image_file, optimize=True, quality=95)

在这段代码中,我使用 os.path.getsize(image_file)来获取图像的大小。但是,这意味着每次循环运行时,文件必须保存在 pic.save(image_file,optimize = True,quality = 95 中。

In this code, I use os.path.getsize(image_file) to get the size of the image. However, this means that the file must be saved in pic.save(image_file, optimize=True, quality=95 every time the loop runs.

这个过程需要很长时间。

That process takes a long time.

有没有办法通过某种方式获得大小的优化 PIL中的图像 图像对象图片

Is there a way to optimise this by somehow getting the size of the image in the PIL Image object pic?

推荐答案

使用 io.BytesIO()将图像保存到内存中。也许最好每次调整原始文件的大小,如下所示:

Use io.BytesIO() to save the image into memory. It is also probably better to resize from your original file each time as follows:

from PIL import Image
import os
import io

def compress(original_file, max_size, scale):
    assert(0.0 < scale < 1.0)
    orig_image = Image.open(original_file)
    cur_size = orig_image.size

    while True:
        cur_size = (int(cur_size[0] * scale), int(cur_size[1] * scale))
        resized_file = orig_image.resize(cur_size, Image.ANTIALIAS)

        with io.BytesIO() as file_bytes:
            resized_file.save(file_bytes, optimize=True, quality=95, format='jpeg')

            if file_bytes.tell() <= max_size:
                file_bytes.seek(0, 0)
                with open(original_file, 'wb') as f_output:
                    f_output.write(file_bytes.read())
                break

compress(r"c:\mytest.jpg", 10240, 0.9) 

因此,这将获取文件并将其缩小 0.9 每次尝试,直到达到合适的大小。然后它会覆盖原始文件。

So this will take the file and scale it down 0.9 each attempt until a suitable size is reached. It then overwrites the original file.

作为替代方法,您可以创建要尝试的比例列表,例如: [0.01,0.02 .... 0.99,1] 然后使用二进制印章确定最接近 max_size的文件大小的比例结果如下:

As an alternative approach, you could create a list of scales to try, e.g. [0.01, 0.02 .... 0.99, 1] and then use a binary chop to determine which scale results in a filesize closest to max_size as follows:

def compress(original_file, max_size):
    save_opts={'optimize':True, 'quality':95, 'format':'jpeg'}
    orig_image = Image.open(original_file)
    width, height = orig_image.size
    scales = [scale / 1000 for scale in range(1, 1001)]  # e.g. [0.001, 0.002 ... 1.0]

    lo = 0
    hi = len(scales)

    while lo < hi:
        mid = (lo + hi) // 2

        scaled_size = (int(width * scales[mid]), int(height * scales[mid]))
        resized_file = orig_image.resize(scaled_size, Image.ANTIALIAS)

        file_bytes = io.BytesIO()
        resized_file.save(file_bytes, **save_opts)
        size = file_bytes.tell()
        print(size, scales[mid])

        if size < max_size: 
            lo = mid + 1
        else: 
            hi = mid

    scale = scales[max(0, lo-1)]
    print("Using scale:", scale)
    orig_image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS).save(original_file, **save_opts)

因此对于 max_size 10000 ,如果尝试过大 0.251 ,则循环首先尝试 0.501 的比例等等。当 max_size = 1024 时,将尝试以下比例:

So for a max_size of 10000, the loop first tries a scale of 0.501, if too big 0.251 is tried and so on. When max_size=1024 the following scales would be tried:

180287 0.501
56945 0.251
17751 0.126
5371 0.063
10584 0.095
7690 0.079
9018 0.087
10140 0.091
9336 0.089
9948 0.09
Using scale: 0.09

这篇关于Python PIL:查找图像的大小而不将其写为文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆