7

最近、私は別のSO の質問に答えようとしていましたGIFs。コードはpastenbinにあります。

このコードを開発ライブラリに移動する前に追加のテストを行っているときに、次のコード行に問題があることに気付きました。

//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 .Net で実行する場合 ( GIF の例)、配列はアニメーションのフレーム数と同じサイズになりGIF、フレームの持続時間で埋められます。この場合、(BitConverter.ToInt32()) 5期間に変換される byte[20]:

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

ただし、MonoMac では、同じ例の GIF に対する次のコード行は、byte[4]1 つの期間 (最初) のみに変換される を返します。

[75,0,0,0]

これを 10 種類テストしましGIF'sたが、結果は常に同じです。Windows ではすべてのデュレーションが byte[] に含まれますが、MonoMac では最初のデュレーションのみがリストされます。

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

MonoSystem.Drawing.Image ソース コードを見ると、長さはGDIラッパーであるこのメソッドで設定されているようです。

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

ただし、実装のようにソースに問題はありません。何か不足していますか、それともバグですか?

4

2 に答える 2

2

モノラルソースにも問題はありません。試したサンプル画像のいずれかを掲載していただけると助かります。GIF 画像形式に関する 1 つの癖は、フレーム時間を含む Graphics Control Extension ブロックがオプションであり、画像記述子の前に省略される可能性があることです。したがって、すべてのフレームに適用される 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 は死ぬ必要があります。

于 2013-12-24T17:26:09.190 に答える
1

libgdiplusを調べると、プロパティが常にアクティブなビットマップから読み取られることがわかります。

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

Image.SelectActiveFrameを呼び出してアクティブなビットマップを設定すると、mono は正しいデュレーションを 1 つずつ返します。これは Windows との非互換性であるため、mono バグと呼びます。簡単な回避策として、もちろん、配列の長さを確認して両方のケースを処理することができます。モノが修正された場合、これは引き続き機能するため、これはモノのチェックよりも優れています。

于 2014-06-10T14:30:33.983 に答える