DOBON.NET DOBON.NETプログラミング掲示板過去ログ

System.IO.FileStreamを使用して呼び出したマルチTiffの表示について

環境/言語:[WinXP Sp2 , VB.NET2005 .NET Framework 2.0]
分類:[.NET]

いつも参考にさせていただいています。

マルチTiffの表示ついてですが、.NET Tipsの「マルチTIFFや〜」を参考に
させていただいて表示できました。
それに付け加えて、.NET Tipsの「表示中の画像ファイルが削除できない問題〜」
の対策として、マルチTIFFの表示のサンプルの Image.FromFile 部分を
変更しました。


Dim img As Image = Image.FromFile(filePath)

  ↓

Dim fs As System.IO.FileStream
fs = New System.IO.FileStream(filePath, _
IO.FileMode.Open, IO.FileAccess.Read)
img = System.Drawing.Image.FromStream(fs)
fs.Close()

この状態でプログラムを実行すると、2ページ目のフレームを選択する
「img.SelectActiveFrame(fd, i)」でエラーが発生しました。

エラー内容は「GDI+ で汎用エラーが発生しました。」(-2147467259)です。

イメージを呼び出す処理を元に戻すと正常に動作します。
また、「System.IO.FileStream」であっても、フレーム数は正常に取得できている
みたいです。

何か対応方法がありましたら、教えていただければと思います。

<参考>

マルチTIFFやアニメーションGIFに含まれるすべてのイメージを表示する
http://dobon.net/vb/dotnet/graphics/selectactiveframe.html

表示中の画像ファイルが削除できない問題の解決法
http://dobon.net/vb/dotnet/graphics/drawpicture2.html
FileStream の内容をいったん MemoryStream に移して、その MemoryStream から Image.FromStream すればいいんではないでしょうか。
なおこの MemoryStream は Close する必要はありません。
Hongliang さん、早速の回答有難うございます。

回答にありましたMemoryStreamを使用してイメージの読み込み部分を
以下のように組み込んでみましたところ、マルチTiffの読み込みが
可能になりました。これで、もう少しテストしてみたいと思います。

Dim br As New IO.BinaryReader(fs)
Dim ms As New IO.MemoryStream(br.ReadBytes(CInt(fs.Length)))
img = System.Drawing.Image.FromStream(ms)


ただ、動いてはいるようなのですが、こんな感じの修正でいいのか
何故動くのかいまいちわかっていません。

また、BinaryReaderを使用せずに、

Dim ms As New IO.MemoryStream
ms.WriteTo(fs)

などでできないかなとやってみたのですがエラーが発生してしまいます。

FileStream、MemoryStreamの関係が良くわからないので調べては
いるのですが… msdnは意味はわかるのですが、どんなときに使ったらいいのか
わからずじまいです。
もし参考になるHPがあれば勉強したいので教えていただければ幸いです。

MemoryStream クラス
http://msdn.microsoft.com/ja-jp/library/system.io.memorystream(VS.80).aspx
まず、Stream は「何か」をバイト列として扱い、それに対して読み書きを行うための抽象的なクラスです。
Stream のうち、ファイルをバイト列として扱うのが FileStream クラスで、メモリをバイト列として扱うのが MemoryStream クラスです。どちらも Stream クラスから派生しており、Stream として振舞うことができます。
// ファイルなら、Close するまでは他からの操作によって勝手にファイルの内容が書き換えられたりしないようにロックを行います(ロックのレベルは FileStream の作成時に操作できますが)。Image.FromFile で作った場合、内部で FileStream が作られそれが開きっぱなしになるため、ロックによってファイルの削除等が行えなくなります。
実装を見たわけではありませんが、挙動からして SelectActiveFrame する際には画像の基になった Stream から読み込むのでしょう。このときに基の Stream を Close していれば当然読み込むことができず例外ということになります。
FileStream の内容を一旦 MemoryStream に読み込み、それを画像の基とすれば、FileStream は Close することができファイルの書き換えや削除ができる。画像の基は MemoryStream なので Close されておらず SelectActiveFrame で読み込みが可能。ということになります。

> Dim ms As New IO.MemoryStream
> ms.WriteTo(fs)
ヘルプ等で MemoryStream のメンバ一覧を見てください。WriteTo メソッドというのが存在しないのがわかるでしょう。
Stream への書き込み・Stream からの読み取りには、Byte() つまりバイト配列を使用して Read や Write メソッドを使用します。
BinaryReader / BinaryWriter はその操作をちょっとだけ手伝ってくれるものと考えればいいでしょう。
Hongliang さん、丁寧な説明有難うございます。

Stream クラスについてだいぶ理解できたと思います。
Image.FromFile が、イメージをロックしてしまい上書き保存できない原因も
そんなものなのだと思っていましたが、内部で FileStream がロックして
いるとわかったことで、すこしすっきりしました。

> 実装を見たわけではありませんが、挙動からして SelectActiveFrame
> する際には画像の基になった Stream から読み込むのでしょう。
> このときに基の Stream を Close していれば当然読み込むことができず
> 例外ということになります。

の件ですが、FileStream を Close せずに、SelectActiveFrame を
呼び出すと正常に動作しました。SelectActiveFrame は基の Stream を
読み込んでるみたいですね。

FileStream では、マルチTiffを使えないと思っていたので Image.FromFile
を使って、読み込み→画面で確認→解放→ファイル削除を行っていました。
ただ、これだと環境によって、解放が間に合わず?に削除でエラーが発生
してしまうことがありました。どうしようかと思っていたので本当に
助かりました。有難うございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板