某アプリケーションが出力するPNGファイルのサムネイル画像(JPEG)をpythonで作ろうとしたのですが、使用しようとしたPIL(python Imaging Library)で”cannot read interlaced PNG files”というエラーが出ました。
“interlaced”とはすなわちインタレース、こちらのWikipediaの記事を読んでいただければわかると思いますが、ブラウザで画像を表示する時に徐々に見えてくるような効果を出してくれる画像の保存形式です。(本記事執筆時点の)PILでは、どうもこのインタレースPNGには対応していないようです。
ターゲットのアプリケーションが出力するPNGの種類を変える方法もなかったので、PIL以外の画像ライブラリを使ってみることにしました。(ImageMagickなどの外部コマンドを使う手もありそうですけど、pythonにこだわってみました。)
pythonで使える画像ライブラリはPILが主流なようで、他にあまり見つからないのですが、pypngというのを見つけました。
これはpure pythonのライブラリで、PNGのフォーマットを解析したり、読み書きできるものです。
残念ながら、今回の目的であるサムネイル画像を直接生成できるものではありませんが、インタレースPNGをノンインタレースPNGに変換することはできました。
このpypngとPILを組み合わせると、
と変換できそうです。
というわけで、同じディレクトリにあるPNGファイルのサムネイル画像(JPEG)を生成するスクリプトを作ってみました。
(このスクリプトの他に同じディレクトリに、png.pyとPILのディレクトリがある前提です。)
import os import png from PIL import Image files = os.listdir('.') for file in files: if file.endswith('.png'): ### read Image by pypng preader = png.Reader(file=open(file,'rb')) (base,exp) = file.split('.') imgdata = preader.asDirect() if bool(imgdata[3]['interlace']) == True: pwriter = png.Writer(imgdata[0],imgdata[1],interlace=False,bitdepth=imgdata[3]['bitdepth'],planes=imgdata[3]['planes'],alpha=imgdata[3]['alpha']) pngfilename = base + '_tmp.'+exp pngfile = open(pngfilename,'wb') pwriter.write(pngfile,imgdata[2]) pngfile.close() isremove = True else: pngfilename = file isremove = False imgdata = None ### read Image by PIL from PIL import ImageFilter im = Image.open(pngfilename) im.thumbnail([101,78],Image.ANTIALIAS) im.filter(ImageFilter.DETAIL) im.save(base + '_s.jpg','JPEG',quality=95) if isremove == True: os.remove(pngfilename)
少し解説すると、10行目でPNGファイルの内容を読み込んでいます。asDirect()で返ってくるのは4要素あるタプルで、0番目が画像の幅、1番目が高さ、2番目がピクセルデータ、3番目がPNGのフォーマットに関する辞書が入っています。(詳しくはpypngのソースを読んでください。png.pyだけなので簡単だと思います。)
上記ソースのPILを使ったサムネイルの作り方は、こちらを参考にさせていただきました。
Pythonで画像サムネイルを生成するには
OZACC.blog: PILでサムネイル生成
なお、PILの将来のバージョンではinterlaced PNGに対応する可能性があります。
PILの最新情報をご確認の上、まだ対応していないようでしたら上記ソースを参考にしてみてください。
ちなみに、このノウハウを使ったシステムをコラボさいたま2009の当社ブースにて展示します。お近くの方は是非お立ち寄りください。どのシステムで使っているかは、実際にご来場の上、ご確認ください。;-)
(もったいつけるようなものでもないんですけどね。)
[…] インタレースPNGをノンインタレースPNGに変換する方法の詳しい方法は、こちらを参照してください。 […]
[…] インタレースPNGをノンインタレースPNGに変換する方法の詳しい方法は、こちらを参照してください。 […]