この記事のURL

http://www.dango-itimi.com/blog/archives/2011/001041.html


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

[ FLASH ] [ tips ] 投稿者 siratama : 2011年01月18日 23:49

トラックバック

http://www.dango-itimi.com/blog/mt-tb.cgi/1001

コメント

以下コメントを書き込むだけでは、管理人には通知が行われません。通知を行いたい場合、管理人の書き込みに「返信」を押してコメントをしていただくか、あるいは Google+, Twitter へご連絡ください。




[EDIT]