PIL(python Imaging Library)でcannot read interlaced PNG filesが出て困った

某アプリケーションが出力する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→[pypng]→ノンインタレースPNG→[PIL]→サムネイル画像(JPEG)

と変換できそうです。

というわけで、同じディレクトリにある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の当社ブースにて展示します。お近くの方は是非お立ち寄りください。どのシステムで使っているかは、実際にご来場の上、ご確認ください。;-)
(もったいつけるようなものでもないんですけどね。)

2 Comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*