2013-07-21 10 views
7

最近アニメーションGIFsのフレーム(ビットマップと期間)の読み込みについて別のSO questionに応答しようとしていました。コードはpastenbinにあります。私のdevのライブラリにそれを移動する前に、このコードに追加のテストをやっている間、私はこのコード行に問題があることに気づいたMonoMac System.Drawing.Image.GetPropertyItem(0x5100)

//Get the times stored in the gif 
//PropertyTagFrameDelay ((PROPID) 0x5100) comes from gdiplusimaging.h 
//More info on http://msdn.microsoft.com/en-us/library/windows/desktop/ms534416(v=vs.85).aspx 
var times = img.GetPropertyItem(0x5100).Value; 

これを使用してWindowsネット上でこれを実行している場合(example GIF )、配列はアニメーションのフレームの量と同じサイズで、GIFであり、フレームの長さで埋められます。この場合、(BitConverter.ToInt32())に5つの期間変換バイト[20]:MonoMacで

[75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0] 

しかし、このコード行は同じ、例えばGIFのみに変換byte[4]を返します1時間(最初の):

[75,0,0,0] 

私は、10の異なるGIF'sのためにこれをテストし、結果は常に同じです。 Windowsでは、すべての期間は、[]バイトであるMonoMacのみ、最初の期間一覧表示しながら:モノラルSystem.Drawing.Imagesource codeを見てみると

[x,0,0,0] 
[75,0,0,0] 
[50,0,0,0] 
[125,0,0,0] 

を、長さがGDIラッパーである、この方法で設定されているように見える。

status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid,out propSize); 

しかし、実際には問題はありませんが、私の実装ではソースではありません。私は何かを見逃しているのですか、これはバグですか?

+0

私はあなたがMono GDI Plusの実装で答えを見つけると信じています。私はそれを見てみましたが、何が起こっているのかを解読するためのgifコーデックに関する専門知識はありません。以下は、私が見つけたもののいくつかです。 [Image.FromFile](https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs)は、[libgdiplus](https:// github。 com/mono/libgdiplus/tree/master/src)。 libgdiplusの中には画像を読み込む関数があります。ファイル[gifcodec.c](https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c)内の関数 'gdip_load_gif_image'がgifイメージを読み込みます。 –

+0

'gdip_load_gif_image'の内部で何が起こるのか調べる必要があります。私が言及したように、それは画像がロードされ/デコードされ、バグがどこにあるのかがわかる場所です。私は何が起こっているのか把握するためのGIFの専門知識を持っていません。がんばろう。 –

答えて

1

あなたは性質が常にアクティブビットマップから読み込まれることを確認できますlook into libgdiplus場合:

if (gdip_bitmapdata_property_find_id(image->active_bitmap, propID, &index) != Ok) { 

あなたはImage.SelectActiveFrameを呼び出すことにより、アクティブなビットマップを設定することができ、その後、モノが正しい期間、一つ一つを返します。これはウィンドウとの互換性がないので、私はそれをモノのバグと呼んでいます。簡単な回避策として、もちろん、配列の長さをチェックして、両方のケースを処理することができます。これは、モノのチェックよりも優れています。なぜなら、モノが固定されると、これは動作し続けるからです。

+0

これは、プラットフォーム間の互換性のための素晴らしい提案です。 – dsfgsho

2

モノソースに間違いはありません。試したサンプル画像の1つを投稿しておけば助けになります。 GIF画像フォーマットに関する1つの奇妙な点は、フレーム時間を含むグラフィックスコントロール拡張ブロックが(オプション)であり、画像記述子の前に省略される可能性があることです。したがって、すべてのフレームに適用されるGCEファイルが1つしかないGIFファイルを持つことになるので、すべてのフレームに同じフレーム時間を適用することになっています。

4つの値が得られなかったことに注意してください。フレーム時間は32ビットの値としてエンコードされ、バイト[]内にリトルエンディアンのエンコードが表示されます。サンプルコードで正しく行ったとおり、BitConverter.ToInt32()を使用する必要があります。

私はので、おそらく代わりにこれを使うべきだと思う:

//convert 4 bit value to integer 
var duration = BitConverter.ToInt32(times, 4*i % times.Length); 

がGIFのフレームについては、別の厄介な実装の詳細は、だ#2フレームとアップフレーム#と同じサイズである必要はありませんのでご注意ください。 1。各フレームには、前のフレームで次のフレームとマージする必要があることを記述するメタデータフィールドがあります。各フレームのフレームオフセット、サイズ、および取り消しメソッドを取得するために私が知っているプロパティIDはありません。私はあなたがビットマップに自分自身を適切な画像のシーケンスを得るために各フレームをレンダリングする必要があると思う。非常に醜い細部、GIFは死ぬ必要があります。

+0

本当に厄介な細部。これは[GIFSの1つです](http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif)私はWindows上で動作させましたが、MonoMacでは動作しませんでした[コードを貼り付け](http://pastebin.com/Y6iUGDX9)。このGIFの 'times'は です。byte [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'Windowsではだが、' byte [4] = {75,0,0,0} 'である。 先ほど触れたように、私が試したすべてのGIFはWindows上で動作しますので、これはGIFの癖の1つではなく、Monoの問題ですか? – dsfgsho

+0

はい、フロアマットの下に掃除することはできません。 –

関連する問題