2009-07-21 155 views
2

我正在尋找一種將新調色板應用於現有8位.png圖像的快速方法。我怎樣才能做到這一點?當我保存圖像時,.png是否被重新編碼? (自己的答案:它似乎很)使用python更改8位.png圖像的調色板PIL

我都試過(編輯):

import Image, ImagePalette 
output = StringIO.StringIO() 
palette = (.....) #long palette of 768 items 
im = Image.open('test_palette.png') #8 bit image 
im.putpalette(palette) 
im.save(output, format='PNG') 

隨着我testimage保存功能大約需要65米利斯。我的想法:沒有解碼和編碼,它可以快很多?

+0

實例:http://stackoverflow.com/questions/236692/how-do-i-convert-any-image-to-a-4-color-paletted-image-using -python-imaging-l – 2009-07-21 11:58:42

回答

4

如果您只想更改調色板,那麼PIL就會擋住您的路。幸運的是,當您只對某些數據塊感興趣時,PNG文件格式的設計很容易處理。 PLTE chunk的格式只是一個RGB三元組的數組,最後有一個CRC。要更改就地文件中的調色板,而不讀或寫整個文件:

import struct 
from zlib import crc32 
import os 

# PNG file format signature 
pngsig = '\x89PNG\r\n\x1a\n' 

def swap_palette(filename): 
    # open in read+write mode 
    with open(filename, 'r+b') as f: 
     f.seek(0) 
     # verify that we have a PNG file 
     if f.read(len(pngsig)) != pngsig: 
      raise RuntimeError('not a png file!') 

     while True: 
      chunkstr = f.read(8) 
      if len(chunkstr) != 8: 
       # end of file 
       break 

      # decode the chunk header 
      length, chtype = struct.unpack('>L4s', chunkstr) 
      # we only care about palette chunks 
      if chtype == 'PLTE': 
       curpos = f.tell() 
       paldata = f.read(length) 
       # change the 3rd palette entry to cyan 
       paldata = paldata[:6] + '\x00\xff\xde' + paldata[9:] 

       # go back and write the modified palette in-place 
       f.seek(curpos) 
       f.write(paldata) 
       f.write(struct.pack('>L', crc32(chtype+paldata)&0xffffffff)) 
      else: 
       # skip over non-palette chunks 
       f.seek(length+4, os.SEEK_CUR) 

if __name__ == '__main__': 
    import shutil 
    shutil.copyfile('redghost.png', 'blueghost.png') 
    swap_palette('blueghost.png') 

此代碼拷貝redghost.png到blueghost.png並修改就地blueghost.png的調色板。

red ghost - >blue ghost

+0

Thx!正是我在找什麼! – 2009-08-04 08:47:28

1

im.palette不可回叫 - 它是ImagePalette類的一個實例,模式爲P,否則爲Noneim.putpalette(...)是一種可調用的方法:參數必須是768個整數的序列,並在每個索引處給出R,G和B值。

0

更改調色板的沒有解碼和(重新)編碼似乎不可能。問題中的方法似乎是最好的(現在)。如果性能很重要,編碼爲GIF似乎要快得多。