[英]Python PIL: Find the size of image without writing it as a file
Edit: This question has been marked a duplicate? 编辑:这个问题已被标记为重复? My question is clearly about optimising this process, not HOW to do it.
我的问题显然是关于优化这个过程,而不是如何做到这一点。 I even provided code to prove that I had already figured out the latter.
我甚至提供了代码来证明我已经找到了后者。 Do you internet hall monitors even read these questions past the title before you flag them?
互联网大厅监视器甚至在标记之前读过这些问题吗?
I have the following block of code to compress an image using PIL, until said image is under a certain size. 我有以下代码块来使用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)
In this code, I use os.path.getsize(image_file)
to get the size of the image. 在这段代码中,我使用
os.path.getsize(image_file)
来获取图像的大小。 However, this means that the file must be saved in pic.save(image_file, optimize=True, quality=95
every time the loop runs. 但是,这意味着文件必须保存在
pic.save(image_file, optimize=True, quality=95
每次循环运行时pic.save(image_file, optimize=True, quality=95
。
That process takes a long time. 这个过程需要很长时间。
Is there a way to optimise this by somehow getting the size of the image in the PIL
Image
object pic
? 有没有办法通过某种方式在
PIL
Image
对象pic
获取图像的大小来优化它?
Use io.BytesIO()
to save the image into memory. 使用
io.BytesIO()
将图像保存到内存中。 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)
So this will take the file and scale it down 0.9
each attempt until a suitable size is reached. 因此,这将获取文件并在每次尝试时将其缩小
0.9
直到达到合适的大小。 It then overwrites the original file. 然后它会覆盖原始文件。
As an alternative approach, you could create a list of scales to try, eg [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: 作为替代方法,您可以创建要尝试的比例列表,例如
[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)
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. 因此,对于
max_size
为10000
,如果尝试过大的0.251
,则循环首先尝试0.501
的比例,依此类推。 When max_size=1024
the following scales would be tried: 当
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
Possibly, you might have a look at this answer using StringIO to perform the operations in memory. 可能,您可以使用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.