我正在寻找一种快速方法将新调色板应用于现有的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毫安。我的想法:没有解码和编码,它可以快得多吗?
答案 0 :(得分:6)
如果你只想改变调色板,那么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的调色板。
- >
答案 1 :(得分:1)
im.palette
不可调用 - 它是ImagePalette
类的实例,模式为P
,否则为None
。 im.putpalette(...)
是一个方法,所以可以调用:参数必须是768个整数的序列,在每个索引处给出R,G和B值。
答案 2 :(得分:0)
在没有解码和(重新)编码的情况下更改调色板似乎不可能。问题中的方法似乎最好(目前)。如果性能很重要,那么编码到GIF似乎要快得多。