日経Web刊紙面画像リサイズスクリプト(Python)

先日書いた日経Web刊、紙面ビューア用画像取得スクリプト(Python)の関連記事です。
同記事にka_zuさんから頂いたコメントをもとに、取得した画像の結合ツールを作成してみました。

画像編集ライブラリとしてPILを利用していますので、Python Imaging Library (PIL)からあらかじめインストールしておく必要があります。

使用方法

settings = {
	'dataDir' : 'C:\\Users\\testuser\\Desktop\\data',
	'outputSizeLevel2' : (1000, 1348),
	'outputSizeLevel3' : (1500, 2022)
}

ここで

  • dataDirに取得済み紙面データがあるディレクトリを指定(画像取得スクリプトと同じ設定でOKです)
  • outputSizeLevel2に拡大版(2段階目)の画像書き出しサイズを指定(デフォルトは、そのまま結合して出力したサイズです)
  • outputSizeLevel2に超拡大版(3段階目)の画像書き出しサイズを指定(デフォルトは、データ量が生データの60%程度になるようにしています。(2000, 2696)と設定すると生データ同様のサイズになります)

これらを設定してスクリプトを実行すると、元データディレクトリに2.jpgと3.jpgが出力されます(生データは破壊しません)。
ゴリゴリと機能実装しただけで、あまり利用シーンを考えていないのですが、多分この先は他ディレクトリへの書き出しや、ディレクトリに対するedition.xmlから取得した情報の記入などが出来れば便利かな、と思います。
利用シーン(例えばWindows環境、WindowsMobile環境の特定画像ビューアと連携するなど)を勘案し、あると便利な出力方法などお気づきの際はコメント頂けると幸いです。

その他コメント

  • ひたすらJPEGを開いて加工というのは、まあまあ重い処理なのでAtom向けではないと思います。母艦でデータ取得・加工を行いネットブックへ投入という流れが良さそうです。
  • エラー処理をほとんど行っていないので、一部画像が欠落している(2000.jpg, 2001.jpg, 2003.jpgはあるが2002.jpgが無いなど)場合には例外を吐いて死んでしまいます。画像取得時に並行して処理していくようにすればある程度マシになるはずですが、まだまだ改善余地ありそうです。

ソースコード

import glob, os.path, math
from lxml import etree
from PIL import Image

settings = {
	'dataDir' : 'C:\\Users\\testuser\\Desktop\\data',
	'outputSizeLevel2' : (1000, 1348),
	'outputSizeLevel3' : (1500, 2022)
}

class RebuildNkImages:
	def __init__(self, settings):
		self.settings = settings

	# dummy, right now
	def rebuildAll(self):
		pass

	def rebuildMostRecent(self):
		target = self.getMostRecentLocalPaperId()
		self.performRebuild(target)

	def getMostRecentLocalPaperId(self):
		papers = glob.glob(self.settings['dataDir'] + '/*')
		if len(papers) == 0:
			raise Exception, 'no paper found on local datadir'
		papers.sort()
		papers.reverse()
		return papers[0]

	def performRebuild(self, target):
		configPath = target + '/edition.xml'
		if (os.path.exists(configPath) == False):
			raise Exception, 'no config XML found on ' + configPath
		editionXml = etree.parse(configPath)
		pages = editionXml.xpath("//edition/pages/page")
		for page in pages:
			imageDir = target + '/' + page.attrib['id']
			# process level 2 images
			self.rebuildImages(imageDir, 2, (1000, 1348), self.settings['outputSizeLevel2'])
			# process level 3 images
			self.rebuildImages(imageDir, 3, (2000, 2696), self.settings['outputSizeLevel3'])

	def rebuildImages(self, imageDir, level, defaultSize, outputSize):
		# const values should be splitted off
		nbTiles = {2: 4, 3: 16}
		outImage = Image.new('RGB', defaultSize)
		dstFilePath = imageDir + '/' + str(level) + '.jpg'
		for i in range(nbTiles[level]):
			srcFilePath = imageDir + '/' + str(level * 1000 + i) + '.jpg'
			offsetX = int(i % math.sqrt(nbTiles[level])) * 500
			offsetY = int(i / math.sqrt(nbTiles[level])) * 674
			outImage.paste(Image.open(srcFilePath), (offsetX, offsetY))
		if (defaultSize != outputSize):
			outImage = outImage.resize(outputSize, Image.ANTIALIAS)
		print 'generated: ' + imageDir + ' / level ' + str(level)
		outImage.save(dstFilePath)

rebuilder = RebuildNkImages(settings)
rebuilder.rebuildMostRecent()
# rebuilder.rebuildAll()