4

我正在寻找一种将新调色板应用于现有 8 位 .png 图像的快速方法。我怎样才能做到这一点?保存图像时 .png 是否重新编码?(自己的答案:似乎是这样)

我尝试过的(编辑):

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 毫秒。我的想法:没有解码和编码,它可以快很多??

4

3 回答 3

8

如果您只想更改调色板,那么 PIL 只会妨碍您。幸运的是,当您只对某些数据块感兴趣时,PNG 文件格式的设计很容易处理。PLTE 块的格式只是一个 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 的调色板。

红鬼->蓝鬼

于 2009-07-31T20:39:56.680 回答
1

im.palette不可调用——它是ImagePalette类的一个实例,在 mode 中P,否则None. im.putpalette(...)是一种方法,因此可调用:参数必须是 768 个整数的序列,在每个索引处给出 R、G 和 B 值。

于 2009-07-21T14:32:27.513 回答
0

在不解码和(重新)编码的情况下更改调色板似乎是不可能的。问题中的方法似乎最好(目前)。如果性能很重要,那么编码为 GIF 似乎要快得多。

于 2009-07-29T12:13:39.930 回答