Если вы хотите изменить только палитру, то 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 на месте.
->