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
中。
这个过程需要很长时间。
有没有办法通过某种方式获取 PIL
Image
object pic
中的图像大小来优化它?
可能,您可能会看看 this answer 使用 StringIO 在内存中执行操作。
import StringIO
output = StringIO.StringIO()
image.save(output)
contents = output.getvalue()
output.close()
image.save(output, format="GIF")
使用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)
所以对于10000
的max_size
,循环首先尝试0.501
的比例,如果太大则尝试0.251
,依此类推。当 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
编辑:此问题已被标记为重复?我的问题显然是关于优化这个过程,而不是如何去做。我什至提供了代码来证明我已经弄清楚了后者。在标记这些问题之前,您的互联网大厅监控器甚至会阅读标题后面的这些问题吗?
我有以下代码块使用 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
中。
这个过程需要很长时间。
有没有办法通过某种方式获取 PIL
Image
object pic
中的图像大小来优化它?
可能,您可能会看看 this answer 使用 StringIO 在内存中执行操作。
import StringIO
output = StringIO.StringIO()
image.save(output)
contents = output.getvalue()
output.close()
image.save(output, format="GIF")
使用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)
所以对于10000
的max_size
,循环首先尝试0.501
的比例,如果太大则尝试0.251
,依此类推。当 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