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 を求める式の誤りを修正


