2009-07-21 156 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似乎要快得多。