Python + SWFバイナリ解析 その3 : gif 埋め込み
Python による gif データ解析と swf 内データ差し替えのサンプルを作成しました。
・参考
GREE Engineers' Blog : SWFバイナリ編集のススメ第四回 (GIF)
http://labs.gree.jp/blog/2010/10/1263/
初め、gif バイナリ解析を自力で行おうと考えましたが、gif データ内の LZW 圧縮箇所の解析で頭が沸騰しそうになったため断念。解析部分は Python Imaging Library (以下PIL) を利用することにしました。
Google App Engine (以下GAE) サイト内説明に「PIL をインストール」する旨の項目があり、GAE は PIL をデフォルトでサポートしているのかと思いましたが、どうやらそんなことはなく?、PIL の Image クラスに似た Google App Engine 独自の Image クラスが用意されている模様。その独自の Image クラスの API 説明を見る限りでは、gif 解析を行うのに十分な処理が用意されていないため、本家の PIL モジュール一式そのまま GAE のサーバにアップロードして利用しています。
サンプル
以下透明化 gif の埋め込み(差し替え)を行ったサンプル swf となります。
差し替え前の gif
差し替え後の gif
データ差し替え前の swf
データ差し替え後の swf
以下は今回作成した GIF データ解析処理用クラスです。PIL の Image クラスの open メソッドで生成されるインスタンスを GifParser.parse メソッドの引数に指定します。その後、GifParser.getBinary メソッドから swf 内に埋め込むためのデータを取得することが可能です。ご参考程度にどうぞ。
# coding: UTF-8 import zlib from struct import * class GifParser: def __init__(self): self.__TRANSPARENCY_KEY = "transparency" def parse(self, image): self.__width = image.size[0] self.__height = image.size[1] self.__transparentPaletteIndex = -1 if self.__TRANSPARENCY_KEY in image.info: self.__transparentPaletteIndex = image.info[self.__TRANSPARENCY_KEY] palette = image.palette.palette self.__colorTableSize = len(palette) / 3 - 1 #(1~256) - 1 self.__colorTableBinary = "" if self.checkTransparent(): self.__colorTableBinary = self.__createColorTableBinaryForTransparency(palette, self.__transparentPaletteIndex) else: self.__colorTableBinary = self.__createColorTableBinary(palette) self.__colormapPixelData = self.__createColormapPixelData(image, self.__width, self.__height) def toString(self): print "width", self.__width print "height", self.__height print "transparentPaletteIndex", self.__transparentPaletteIndex print "colorTableSize", self.__colorTableSize print "colorTableBinary length", len(self.__colorTableBinary) print "colormapPixelData", len(self.__colormapPixelData) def checkTransparent(self): return self.__transparentPaletteIndex != -1 def getBinary(self): widthBinary = pack("<H", self.__width) heightBinary = pack("<H", self.__height) colorTableSizeBinary = pack("B", self.__colorTableSize) binary = "\x03" + widthBinary + heightBinary + colorTableSizeBinary binary = binary + zlib.compress(self.__colorTableBinary + self.__colormapPixelData) return binary def __createColorTableBinary(self, palette): colorTableBinary = "" paletteSize = len(palette) n = 0 while n < paletteSize: colorTableBinary = colorTableBinary + palette[n] colorTableBinary = colorTableBinary + palette[n + 1] colorTableBinary = colorTableBinary + palette[n + 2] n = n + 3 return colorTableBinary def __createColorTableBinaryForTransparency(self, palette, transparentPaletteIndex): colorTableBinary = "" paletteSize = len(palette) n = 0 while n < paletteSize: colorTableBinary = colorTableBinary + palette[n] colorTableBinary = colorTableBinary + palette[n + 1] colorTableBinary = colorTableBinary + palette[n + 2] colorTableBinary = colorTableBinary + "\xff" n = n + 3 pos = transparentPaletteIndex * 4 + 3 return colorTableBinary[0:pos] + "\x00" + colorTableBinary[pos+1:] def __createColormapPixelData(self, image, width, height): n = width % 4 if (width % 4) == 0: maxWidth = width else: maxWidth = width + (4 - (width % 4)) colormapPixelData = "" y = 0 while y < height: xList = "" x = 0 while x < maxWidth: n = 0 if x < width: n = image.getpixel((x, y)) xList = xList + pack("B", n) x = x + 1 colormapPixelData = colormapPixelData + xList y = y + 1 return colormapPixelData
追記:2011/1/20 )
__createColormapPixelData メソッド内 変数 maxWidth を求める式の誤りを修正