python PILを使用して、8ビットの.png画像のパレットの変更
-
18-09-2019 - |
質問
私は、既存の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ミリ秒かかります。私の思考:デコードやエンコードせずに、それは多くの高速になります??
解決
あなただけのパレットを変更したい場合は、
、そしてPILはちょうどあなたの方法で取得します。幸いにも、PNGファイル形式は、あなただけのデータチャンクのいくつかに興味があるときに対処しやすいように設計されました。 PLTEチャンクのフォーマットする終了時にCRCを有するRGBの三つ組のちょうど配列です。読み取りまたはファイル全体を記述することなく、その場でファイルのパレットを変更するには:
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')
このコードのコピーがblueghost.pngする上redghost.pngとインプレースblueghost.pngのパレットを変更します。
- >
他のヒント
im.palette
は呼び出すことはできません - それはそうImagePalette
、モードP
で、None
クラスのインスタンスです。 im.putpalette(...)
は、そう呼び出し可能なメソッドである:引数は、各インデックスにR、G及びB値を与える768個の整数のシーケンスでなければならない
パレットのデコードと(再)エンコードなしに変更することはできていないようです。当該の方法は(今のところ)最高のようです。パフォーマンスが重要な場合は、GIFへのエンコードがたくさん速いようです。
所属していません StackOverflow