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')

私のテストイメージでは、保存機能に約 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、モードではクラスのインスタンスでありP、それ以外の場合はNoneです。 im.putpalette(...)はメソッドであるため、呼び出し可能です。引数は、各インデックスでR、G、およびBの値を与える768個の整数のシーケンスである必要があります。

于 2009-07-21T14:32:27.513 に答える
0

デコードおよび (再) エンコードせずにパレットを変更することはできないようです。質問の方法が最善のようです(今のところ)。パフォーマンスが重要な場合は、GIF へのエンコードがはるかに高速に思えます。

于 2009-07-29T12:13:39.930 に答える