FMF読込クラス

もう少し変態的な書き方に修正。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import struct

class Layer2D:
	""" 2次元レイヤー """
	def __init__(self, width, height, data):
		"""
		コンストラクタ
		@param width  幅
		@param height 高さ
		@param data   データ
		"""
		self.width  = width
		self.height = height
		self.data   = data
	def get(self, x, y):
		"""
		座標を指定して値を取得
		@param x, y 座標
		@return 値
		"""
		if 0 <= x < self.width:
			if 0 <= y < self.height:
				return self.data[y*self.width + x]
		return None
	def __str__(self):
		strData = "  "
		for i, data in enumerate(self.data):
			strData += "%r,"%data
			if (i+1) % self.width == 0:
				strData += "\n  "
		return "(Width,Height)=(%d,%d)\n%s"%(
			self.width, self.height, strData)

class FMFLoader:
	""" FMFファイル読込クラス """
	# データのbit数に対応するバイナリコード変換関数テーブル
	CONVERT_BIN_FUNC_TBL = {
		8:  lambda cnt, b: struct.unpack("%dB"%cnt, b),
		16: lambda cnt, b: struct.unpack("%dH"%cnt, b),
	}
	def __init__(self, filepath, layer2d=Layer2D):
		"""
		コンストラクタ
		@param filepath FMFファイルパス
		@param layer    レイヤーとして使用するクラス(Layer2Dの派生クラス)
		"""
		self.filepath = filepath
		self.file     = open(filepath, "rb")
		# ヘッダ
		self._readHeader()
		# データ( レイヤーリスト)
		self.layerList = map(self._createLayer, [layer2d]*self.layerCount)
	def _readHeader(self):
		""" ヘッダ読込[20byte] """
		b = self.file.read(4)
		assert b == "FMF_", "FileformatError: Expected 'FMF'file. (file:'%s')"%self.filepath
		self.identifier = b  # ファイル識別子       [4byte]
		b = self.file.read(16)
		(self.dataSize,      # ヘッダを除いたサイズ [4byte]
			self.width,      # マップの幅           [4byte]
			self.height,     # マップの高さ         [4byte]
			self.chipWidth,  # チップの幅           [1byte]
			self.chipHeight, # チップの高さ         [1byte]
			self.layerCount, # レイヤー数           [1byte]
			self.bitCount    # データのbit数(8/16)  [1byte]
		) = struct.unpack("3L4B", b)
	def _createLayer(self, layer2d):
		""" レイヤーの生成 """
		return apply(layer2d,
			(self.width, self.height,
				self._createLayerData(self.width*self.height)))
	def _createLayerData(self, size):
		"""
		レイヤーデータを生成
		@param size レイヤーデータのサイズ
		"""
		return self.CONVERT_BIN_FUNC_TBL[self.bitCount](
			size,
			self.file.read(size*self.bitCount/8))
	def getLayer(self, index):
		"""
		レイヤーオブジェクト取得
		@parma index レイヤー番号
		"""
		if 0 <= index < self.layerCount:
			return self.layerList[index]
		return None
	def toStringHeader(self):
		""" ヘッダを文字列に変換 """
		return "%s%s%s%s%s%s%s%s"%(
		"  Identifier         :%s\n"%self.identifier,
		"  Size(except Header):%i\n"%self.dataSize,
		"  Width              :%i\n"%self.width,
		"  Height             :%i\n"%self.height,
		"  ChipWidth          :%i\n"%self.chipWidth,
		"  ChipHeight         :%i\n"%self.chipHeight,
		"  LayerCount         :%i\n"%self.layerCount,
		"  BitCount           :%i\n"%self.bitCount,
		)
	def toStringData(self):
		""" データを文字列に変換 """
		result = "  "
		for idx, layer in enumerate(self.layerList):
			result += "[Layer:%d]\n  "%idx
			for i, data in enumerate(layer.data):
				result += "%r,"%data
				if (i+1) % layer.width == 0:
					result += "\n  "
		return result
	def __str__(self):
		return "Header ... \n%s\nData ... \n%s"%(
			self.toStringHeader(),
			self.toStringData())
def main():
	fmf = FMFLoader("area.fmf")
	print fmf

if __name__ == "__main__":
	main()