生成小于10KB且保持比例的图片缩略图
注意到谷歌为每张被索引的图片都提供了一个小小的缩略图吗?这些缩略图有以下特点:
- 大小都在10KB以下。
- 宽高比和原图保持一致。
我想写一个函数(用python),这个函数可以接收一张图片,并生成符合这两个特点的缩略图。
编辑:现在有三个回答,但都只对了一半。
我需要一个函数,不仅要按比例缩放图片,还要确保文件大小小于10KB。我该怎么做呢?
3 个回答
使用PIL库,下面的示例代码可以帮助你在调整图片大小时保持比例。
这里还有一个关于如何在文件夹中做类似操作的链接。
上面的链接介绍了如何使用PIL调整图片大小,现在来说说你提到的10KB的最大大小,这个目标其实很容易实现。
假设你需要的图片大小是100x100像素,如果使用JPEG压缩,100%质量的JPEG大约每个像素需要9位(可以参考这个链接),那么100x100的图片大小大约是100x100x9/(1024x8) = 11KB。也就是说,质量设置为100时,你几乎达到了目标,但如果你只想要10KB,可以把质量设置为90。一般来说,你可以把质量作为参数传给调整大小的函数,如果图片大小超过10KB,就把质量降低10%。不过我觉得这其实没必要,因为在90%质量下,所有的JPEG图片都应该小于10KB。
另外要注意的是,如果不压缩,RGB图片的大小大约是30KB。如果你把图片大小缩小到60x60像素,图片大小在没有任何压缩的情况下就会只有10KB。也就是说,你可以使用bmp格式的图片,如果想要更小的文件但又不想损失质量,可以选择PNG格式。
总之,达到10KB的目标非常简单。
你有没有看过PIL的文档?里面有一个叫做image.thumbnail的方法。
在这篇简短的帖子中,Mike Fletcher和effbot展示了一种很棒的方法来完成你想做的事情,并进行了详细的讨论。
补充说明:关于10K的要求,预测一张图片能压缩到什么程度是很困难的,尤其是因为现在的压缩算法非常复杂。如果你希望缩略图的大小(像素)尽可能接近这个<10K的要求,你可能需要采用“试错法”,不断调整缩放比例,直到得到一个满意的结果。
例如,这里有一种“二分查找”的方法来获取正确的大小(可能还有更好的策略!),并且有很多打印语句等来解释发生了什么……:
import Image
import cStringIO
import math
import os
import stat
# try no more than 10 times, then give up
MAX_TRIES = 10
def getThumbnail(filename, max_bytes=(10*1024)):
'''Get a thumbnail image of filename, <max_bytes'''
original_size = os.stat(filename)[stat.ST_SIZE]
print "Original file size: %.1f KB" % (original_size/1024.)
image = Image.open(filename)
image.load()
print "Original image size: %dx%d pixels" % image.size
min_bytes = int(0.9 * max_bytes)
largest_side = max(image.size)
smallest_side = 16
for attempt in range(MAX_TRIES):
try_side = (largest_side + smallest_side) / 2
print "Attempt #%d of %d" % (attempt+1, MAX_TRIES)
print "Side must be within [%d:%d], now trying %d" % (
smallest_side, largest_side, try_side)
thumb = image.copy()
thumb.thumbnail((try_side,try_side), Image.ANTIALIAS)
afile = cStringIO.StringIO()
thumb.save(afile, "PNG")
resulting_size = len(afile.getvalue())
afile.close()
print "Reduced file size: %.1f KB" % (resulting_size/1024.)
print "Reduced image size: %dx%d pixels" % thumb.size
if min_bytes <= resulting_size <= max_bytes:
print "Success!"
return thumb
elif resulting_size > max_bytes:
print "Too large (>%d), reducing more" % max_bytes
largest_side = try_side
else:
print "Too small (<%d), reducing less" % min_bytes
smallest_side = try_side
print "too many attempts, returning what I've got!"
return thumb
def main():
thumb = getThumbnail("pyth.png")
print "Reduced image size: %dx%d pixels" % thumb.size
print "Saving to thumb.png"
thumb.save("thumb.png")
thumb_size = os.stat("thumb.png")[stat.ST_SIZE]
print "Reduced file size: %.1f KB" % (thumb_size/1024.)
print "Done, bye!"
if __name__ == '__main__':
main()