FrameDimensionsList, SelectActiveFrame を使って画像の複数フレームにアクセスする場合の注意点

ref: System.IO.FileStreamを使用して呼び出したマルチTiffの表示について: DOBON.NETプログラミング掲示板過去ログ

昔にもハマった記憶があって、昨日またハマってしまったのでメモ。
以下は、.net framework にて画像の複数フレームにアクセスするために Image.SelectActiveFrame メソッドを使う場合、画像の読み込み元ストリームを閉じてしまわないように気をつける必要があるという事について述べている。


たとえば

using(Stream s = new ...){
    new Bitmap(s);
}

のようにしてストリームから画像を読み取ることはよくある(と思う)。

が、上のように画像の読み取り元になったストリームを閉じてしまった後に SelectActiveFrame メソッドを呼ぶと、「GDI+ で汎用エラーが発生しました。」というとても汎用的な文言の例外が生起されてしまう。この例外は、SelectActiveFrame が実際には元ストリームから画像を再読込しているためのようだ。

そのため、SelectActiveFrame するつもりがあるならば、画像のソースとなるストリームは閉じてしまってはいけない。ストリームの Close や Dispose を呼ばないでおけば、Bitmap インスタンスが内部的に元ストリームへの参照を持っていてくれるので、ソースとなったストリームが閉じられることもなく、SelectActiveFrame を正常に行えるようになる。

今回ハマったパターンではアセンブリのリソースストリームを使っていたので開きっぱなしで問題なかったが、元となるストリームがファイルであるといった理由で開きっぱなしにし難いなら、参考にある掲示板にもあるとおり、一端 MemoryStream などにコピーしてから、その MemoryStream を使って画像のインスタンスを作れば良いだろう。

また、SelectActiveFrame は、MSDN

別のフレームを選択する場合は、ピクセル値やプロパティの変更など、現在のフレームに加えた変更をあらかじめすべて保存してください。

とある通り、SelectActiveFrame を呼ぶまでの変更を捨てて再読込するということにも注意が必要そうだ。