生成小于10KB且保持比例的图片缩略图

1 投票
3 回答
5816 浏览
提问于 2025-04-15 12:38

注意到谷歌为每张被索引的图片都提供了一个小小的缩略图吗?这些缩略图有以下特点:

  1. 大小都在10KB以下。
  2. 宽高比和原图保持一致。

我想写一个函数(用python),这个函数可以接收一张图片,并生成符合这两个特点的缩略图。

编辑:现在有三个回答,但都只对了一半。

我需要一个函数,不仅要按比例缩放图片,还要确保文件大小小于10KB。我该怎么做呢?

3 个回答

1

使用PIL库,下面的示例代码可以帮助你在调整图片大小时保持比例。

如何使用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的目标非常简单。

1

你有没有看过PIL的文档?里面有一个叫做image.thumbnail的方法。

3

这篇简短的帖子中,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()

撰写回答