簡體   English   中英

如何將 Python/Pillow 中 PNG 圖像的調色板減少到真正使用的顏色?

[英]How to reduce the palette of PNG image in Python/Pillow to the colors being really used?

在使用以下代碼處理先前優化的具有透明度的索引彩色 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 包,如PyPNGPurePNG ,如果有幫助的話。

我在帶有 Pillow 9.2.0 的蜜蜂 png 上運行了您的代碼,並且輸出 png 在其調色板中具有與原始顏色相同的數字顏色。 此外, Image.convert()具有可用於控制輸出顏色的 args palettecolors 例如,要保持與輸入圖像相同數量的顏色:

from PIL import Image

img = Image.open('bee.png')
num_pixels = img.size[0]*img.size[1]
num_colors = len(img.getcolors(num_pixels))
# Max palette size = 256
if num_colors > 256:
    num_colors = 256

img = img.convert(mode='P', palette=1, colors=num_colors)
img.save('bee2.png', optimize=True, format="PNG")

或者,如果您對減小/管理圖像大小感興趣,我建議使用Image.save()中的quality參數壓縮圖像或使用 ExifTool 等其他工具來消除不必要的元數據(這些可能對蜜蜂.png)。

有關 Pillow 中圖像模式的更多信息,請參閱 Mark Setchell 的回答: PIL 中“P”和“L”模式中的圖像有什么區別?

討論使用 Pillow 減小文件大小的答案: 如何使用 PIL 減小圖像文件大小

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM