簡體   English   中英

Python PIL:查找圖像的大小而不將其寫為文件

[英]Python PIL: Find the size of image without writing it as a file

編輯:這個問題已被標記為重復? 我的問題顯然是關於優化這個過程,而不是如何做到這一點。 我甚至提供了代碼來證明我已經找到了后者。 互聯網大廳監視器甚至在標記之前讀過這些問題嗎?

我有以下代碼塊來使用PIL壓縮圖像,直到所述圖像具有一定的大小。

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每次循環運行時pic.save(image_file, optimize=True, quality=95

這個過程需要很長時間。

有沒有辦法通過某種方式在PIL Image對象pic獲取圖像的大小來優化它?

使用io.BytesIO()將圖像保存到內存中。 每次調整原始文件的大小也可能更好,如下所示:

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直到達到合適的大小。 然后它會覆蓋原始文件。


作為替代方法,您可以創建要嘗試的比例列表,例如[0.01, 0.02 .... 0.99, 1]然后使用二進制斬波來確定哪個比例結果最接近max_size的文件大小,如下所示:

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_size10000 ,如果嘗試過大的0.251 ,則循環首先嘗試0.501的比例,依此類推。 max_size=1024 ,將嘗試以下比例:

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

可能,您可以使用StringIO查看此答案,以在內存中執行操作。

import StringIO

output = StringIO.StringIO() 
image.save(output) 
contents = output.getvalue() 
output.close()

image.save(output, format="GIF")

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM