如何使用PIL减小图像文件大小

138

我正在使用PIL来调整图像大小,从而将较大的图像转换为较小的图像。有没有标准的方法可以在不太损失质量的情况下减小图像文件的大小?假设原始图像的大小为100kB。我希望将其缩小到5或10KB,特别是对于PNG和JPEG格式的图像。


3
您认为“太多”的质量丢失是什么意思?如果您想将文件大小缩小10倍到20倍,最简单的方法就是减少像素数量。将宽度和高度均减少2/3可以得到一张大约是原始图片1/9大小的图片。但这会损失相当多的分辨率。 - Roland Smith
8个回答

216

保存JPEG和PNG图像时的内置参数是optimize

 from PIL import Image

 foo = Image.open('path/to/image.jpg')  # My image is a 200x374 jpeg that is 102kb large
 foo.size  # (200, 374)
 
 # downsize the image with an ANTIALIAS filter (gives the highest quality)
 foo = foo.resize((160,300),Image.ANTIALIAS)
 
 foo.save('path/to/save/image_scaled.jpg', quality=95)  # The saved downsized image size is 24.8kb
 
 foo.save('path/to/save/image_scaled_opt.jpg', optimize=True, quality=95)  # The saved downsized image size is 22.9kb
optimize标志将对图像进行额外处理,以找到尽可能减小其大小的方法。1.9kb可能看起来不算多,但在数百/数千张图片中,它会逐渐累加。

现在,为了将其缩小至5KB至10KB左右,您可以更改保存选项中的质量值。在这种情况下,使用85而不是95的质量值将产生以下结果:
未优化:15.1 KB
优化后:14.3 KB
如果参数被省略,则使用75的质量(默认值)将产生以下结果:
未优化:11.8 KB
优化后:11.2 KB

我更喜欢使用optimize和品质85,因为品质变化不大,文件大小会更小。


11
自2.7.0版本开始,所有的调整大小方法都采用了ANTIALIAS方法。特定的ANTIALIAS过滤器的真正名称是LANCZOS。(尽管为了向后兼容性,目前仍保留antialias的名称)。https://pillow.readthedocs.io/en/3.0.x/releasenotes/2.7.0.html#antialias-renamed-to-lanczos - hbrannan

31

假设您有一个名为Book的模型,并在其上有一个名为'cover_pic'的字段, 在这种情况下,您可以执行以下操作来压缩图像:

from PIL import Image
b = Book.objects.get(title='Into the wild')
image = Image.open(b.cover_pic.path)
image.save(b.image.path,quality=20,optimize=True)

希望它能对任何遇到困难的人有所帮助。


7
请参考PIL的Image模块中的thumbnail函数。您可以使用它来将文件保存为各种文件类型的较小版本,如果您想尽可能保留更多的质量,请考虑在保存时使用ANTIALIAS过滤器。
除此之外,我不确定是否有一种指定最大所需大小的方法。当然,您可以编写一个函数,尝试以不同的质量保存多个版本的文件,直到达到特定的大小,丢弃其余部分并给您所需的图像。

2
有没有一种方法可以在保持尺寸不变的情况下减小文件大小,特别是对于PNG格式的文件? - Yashwanth Kumar
2
如果你想保持相同的尺寸,唯一可以尝试的是在保存图像时设置图像质量设置。请参阅此答案 - Cryptite
3
但对于PNG格式来说,质量属性没有任何影响。即使我更改了质量,文件大小仍然相同。 - Yashwanth Kumar
1
在这种情况下,恐怕我不知道。由于它们的压缩格式,PNG通常比较大。PNG是必须的吗?如果不是,您考虑过尝试使用GIF吗? - Cryptite
1
对于PNG格式的图片,将其转换为使用较小的调色板。在写入文件时,使用“bits”选项并设置值<8。 - Roland Smith
2
通过“pngcrush”实用程序运行PNG文件。不过,根据您获取它们的位置,它们可能已经被压缩了,因此这并没有帮助。但是,对于您自己创建的文件,它非常有效。 - kindall

6
PIL中的主要图像管理器是Image模块。
from PIL import Image
import math

foo = Image.open("path\\to\\image.jpg")
x, y = foo.size
x2, y2 = math.floor(x-50), math.floor(y-20)
foo = foo.resize((x2,y2),Image.ANTIALIAS)
foo.save("path\\to\\save\\image_scaled.jpg",quality=95)

您可以在参数中添加optimize=True以进一步减小大小,但优化仅适用于JPEG和PNG格式的图像。 对于其他图像扩展名,您可以降低新保存的图像的质量。 您可以通过删除一些代码并定义图像大小来更改新图像的大小,只有仔细查看代码才能找到如何执行此操作。 我定义了这个尺寸:
x, y = foo.size
x2, y2 = math.floor(x-50), math.floor(y-20)

这里只是为了展示通常使用横向图片的情况。对于竖向图片,您可以采取以下方式:

x, y = foo.size
x2, y2 = math.floor(x-20), math.floor(y-50)

记住,您仍然可以删除那段代码并定义一个新的尺寸。


1
如果你从整数中减去一个整数,就不需要使用 math.floor。例如,85-2 等于 83math.floor 只会将小数转换为整数(例如,84.912 变成了 84)。如果你想将 浮点数 转换为 整数,只需编写类似于 x = int(84.912)x = 84.912 // 1 的代码即可。 - Samuel Muldoon

5

这段脚本可以减小图片的宽度和高度,同时保持其比例,并且还可以减小图片大小。

两个选项,它们会执行相同的逻辑,第一个选项是我在django项目中使用的方法第二个选项是纯Python版的实现

你可以根据自己的需要改变TARGET_WIDTH的值。

Django models.py中,图片保存后会再次被处理。

from PIL import Image

class Theme(models.Model):
    image = models.ImageField(upload_to='theme_image/')
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        this_image = Image.open(self.image.path)
        width, height = this_image.size
        TARGET_WIDTH = 500
        coefficient = width / 500
        new_height = height / coefficient
        this_image = this_image.resize((int(TARGET_WIDTH),int(new_height)),Image.ANTIALIAS)
        this_image.save(self.image.path,quality=50)

没有Django,foo.py文件:

from PIL import Image

this_image = Image.open("path\to\your_image.jpg")
width, height = this_image.size
TARGET_WIDTH = 500
coefficient = width / 500
new_height = height / coefficient
this_image = this_image.resize((int(TARGET_WIDTH),int(new_height)),Image.ANTIALIAS)
this_image.save("path\where\to_save\your_image.jpg",quality=50)

3
Python图像处理库(PIL)已经过时,应使用Pillow代替。 - Samuel Muldoon
2
还有一些事情需要注意 - 为了使Django Cleanup正常工作,您必须在图像保存完成后关闭图像处理。您需要使用 "this_image.close()" 和 "self.image.close()"。 - Conor
2
对于Pillow 9.2.0,您必须执行PIL.Image.open(self.image)...和PIL.Image.ANTIALIAS。 - Conor
2030年下一个PIL弃用的名称:Matrasse.py - Marwen Trabelsi

2
你可以调整图片大小或者降低图片质量。 以下是一些示例:
Python PIL 调整图片大小
from PIL import Image
WIDTH = 1020
HEIGHT = 720
img = Image.open("my_image.jpg")
resized_img = img.resize((WIDTH, HEIGHT))
resized_img.save("resized_image.jpg")

修改图片分辨率 Pillow

from PIL import Image
size = 7016, 4961
im = Image.open("my_image.png")
im_resized = im.resize(size, Image.ANTIALIAS)
im_resized.save("image_resized.png", "PNG")

或者您可以使用

im_resized.save("image_resized.png", quality=95, optimize=True)

1
调整图像大小,将其存储为JPEG格式,并将质量降低到95,可以在最终输出中节省大量字节。
image = Image.open("input_file.png")
image = image.resize((WIDTH, HEIGHT))  #smaller width and height than the original

image.save("output_file.jpg", "JPEG", quality=95)

然而,假设你必须确保图像大小不超过100 kb,无论如何。在这种情况下,我们需要不断降低图像的质量,直到达到正确的文件大小。
minimum_quality = 50      # recommended, but optional (set to 0 if you don't want it)

quality = 95      # initial quality
target = 100000   # 100 kb

while True:
    output_buffer = io.BytesIO()    # import io
    image.save(output_buffer, "JPEG", quality=quality)

    file_size = output_buffer.tell()

    if file_size <= target or quality <= minimum_quality:
        output_buffer.close()
        break
    else:
        quality -= 5

image.save(output_image, "JPEG", quality=quality)

正如你所看到的,我们将图像存储在临时缓冲区中,并读取缓冲区的大小来获取文件大小。

-16
如果你有一个大的PNG文件(例如400x400大小的1MB):
__import__("importlib").import_module("PIL.Image").open("out.png").save("out.png")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接