在使用以下代码处理先前优化的具有透明度的索引彩色 PNG 图像后(有关某些背景,请参见此处,因为此问题涉及相同的图像文件),PLTE 块似乎使用比有效使用的颜色更多的颜色进行扩展。
亩电流代码:
#!/usr/bin/env/python3
import os
from PIL import Image
source_file = os.path.expanduser("~/Desktop/prob.png")
dest_file = os.path.expanduser("~/Desktop/processed_img.png")
img = Image.open(source_file)
# Convert all colors in the palette to grayscale and save the new palette
pal = img.getpalette()
for i in range(len(pal) // 3):
# Using ITU-R 601-2 luma transform
g = (pal[3*i] * 299 + pal[3*i+1] * 587 + pal[3*i+2] * 114) // 1000
pal[3*i: 3*i+3] = [g, g, g]
img.putpalette(pal)
try:
img.save(dest_file, optimize=True, format="PNG")
except IOError:
ImageFile.MAXBLOCK = img.size[0] * img.size[1]
img.save(dest_file, optimize=True, format="PNG")
使用pngcheck
我为原始文件获得了一个小的 16 色调色板:
$ pngcheck -tc7pv ~/Desktop/prob.png
File: /Users/victor/Desktop/prob.png (12562 bytes)
chunk IHDR at offset 0x0000c, length 13
825 x 825 image, 8-bit palette, non-interlaced
chunk PLTE at offset 0x00025, length 48: 16 palette entries
0: ( 0, 0, 0) = (0x00,0x00,0x00)
1: (230,230,230) = (0xe6,0xe6,0xe6)
2: (215,215,215) = (0xd7,0xd7,0xd7)
3: (199,199,199) = (0xc7,0xc7,0xc7)
4: (175,175,175) = (0xaf,0xaf,0xaf)
5: (143,143,143) = (0x8f,0x8f,0x8f)
6: (111,111,111) = (0x6f,0x6f,0x6f)
7: ( 79, 79, 79) = (0x4f,0x4f,0x4f)
8: ( 22, 22, 22) = (0x16,0x16,0x16)
9: ( 0, 0, 0) = (0x00,0x00,0x00)
10: ( 47, 47, 47) = (0x2f,0x2f,0x2f)
11: (254,254,254) = (0xfe,0xfe,0xfe)
12: (115, 89, 0) = (0x73,0x59,0x00)
13: (225,176, 0) = (0xe1,0xb0,0x00)
14: (255,211, 0) = (0xff,0xd3,0x00)
15: (254,204, 0) = (0xfe,0xcc,0x00)
chunk tRNS at offset 0x00061, length 1: 1 transparency entry
0: 0 = 0x00
chunk IDAT at offset 0x0006e, length 12432
zlib: deflated, 32K window, maximum compression
chunk IEND at offset 0x0310a, length 0
No errors detected in /Users/victor/Desktop/prob.png (5 chunks, 98.2% compression).
然后,在使用上面的代码示例处理图像后,pngcheck
会显示一个更大的 PLTE 块,其中填充了许多(可能未使用的)颜色值:
$ pngcheck -tc7pv ~/Desktop/processed_img.png
File: /Users/victor/Desktop/processed_img.png (14680 bytes)
chunk IHDR at offset 0x0000c, length 13
825 x 825 image, 8-bit palette, non-interlaced
chunk PLTE at offset 0x00025, length 768: 256 palette entries
0: ( 0, 0, 0) = (0x00,0x00,0x00)
1: (230,230,230) = (0xe6,0xe6,0xe6)
2: (215,215,215) = (0xd7,0xd7,0xd7)
3: (199,199,199) = (0xc7,0xc7,0xc7)
4: (175,175,175) = (0xaf,0xaf,0xaf)
5: (143,143,143) = (0x8f,0x8f,0x8f)
6: (111,111,111) = (0x6f,0x6f,0x6f)
7: ( 79, 79, 79) = (0x4f,0x4f,0x4f)
8: ( 22, 22, 22) = (0x16,0x16,0x16)
9: ( 0, 0, 0) = (0x00,0x00,0x00)
10: ( 47, 47, 47) = (0x2f,0x2f,0x2f)
11: (254,254,254) = (0xfe,0xfe,0xfe)
12: ( 86, 86, 86) = (0x56,0x56,0x56)
13: (170,170,170) = (0xaa,0xaa,0xaa)
14: (200,200,200) = (0xc8,0xc8,0xc8)
15: (195,195,195) = (0xc3,0xc3,0xc3)
16: ( 16, 16, 16) = (0x10,0x10,0x10)
17: ( 17, 17, 17) = (0x11,0x11,0x11)
18: ( 18, 18, 18) = (0x12,0x12,0x12)
19: ( 19, 19, 19) = (0x13,0x13,0x13)
20: ( 20, 20, 20) = (0x14,0x14,0x14)
(...) --- 它继续列出所有高达 255 的值:
254: (254,254,254) = (0xfe,0xfe,0xfe)
255: (255,255,255) = (0xff,0xff,0xff)
chunk tRNS at offset 0x00331, length 1: 1 transparency entry
0: 0 = 0x00
chunk IDAT at offset 0x0033e, length 13830
zlib: deflated, 32K window, maximum compression
chunk IEND at offset 0x03950, length 0
No errors detected in /Users/victor/Desktop/processed_img.png (5 chunks, 97.8% compression).
这种行为在 Pillow 上正常吗?有什么方法可以保存更短的 PLTE 块,类似于原始文件(我正在尝试优化更小的文件大小)?
如果 Pillow 做不到,还有其他简单的方法可以做到吗?最好使用纯 Python,但如果有帮助,它也可以带有numpy
或一些额外的纯 Python 包,比如PyPNG
or PurePNG
。