2009-07-21 23 views
2

既存の8ビット.pngイメージに新しいパレットを素早く適用する方法を探しています。どうやってやるの?画像を保存すると.pngが再エンコードされますか? (自身の答え:そう思える):私のtestimageでPythonを使用して8ビットの.pngイメージのパレットを変更するPIL

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ミリ秒を要し、私が(編集済み)試してみました何

。私の考え:デコードとエンコードなしでは、ずっと速くなることができますか?

+0

例:http://stackoverflow.com/questions/236692/how-do-i-convert-any-image-to-a-4-color-paletted-image-using -the-python-imaging-l –

答えて

4

パレットだけを変更したい場合は、PILがそのまま使用できます。幸いなことに、PNGファイル形式は、データチャンクの一部にしか関心がない場合に対処しやすいように設計されています。 PLTE chunkのフォーマットは、最後に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のパレットを変更します。

red ghost - >blue ghost

+0

Thx!まさに私が探していたもの! –

1

im.paletteは、のImagePaletteクラスのインスタンスです。それ以外の場合はNoneです。 im.putpalette(...)はメソッドなので、呼び出し可能です:引数は、各インデックスにR、G、Bの値を与える768の整数のシーケンスでなければなりません。

0

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

関連する問題