2013-07-21 10 views
7

Kürzlich habe ich versucht, eine andere SO question über das Laden der Frames (Bitmap und Dauer) von animierten GIFs zu beantworten. Der Code kann auf pastenbin gefunden werden. dabei zusätzliche Tests auf diesem CodeMonoMac System.Drawing.Image.GetPropertyItem (0x5100)

Während bevor sie in meine dev Bibliothek bewegen, bemerkte ich, dass es ein Problem mit dieser Codezeile:

//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; 

Wenn diese auf Windows .Net dies mit (example GIF), das Array hat die gleiche Größe wie die Anzahl der Frames in der animierten GIF und mit der Dauer der Frames gefüllt. In diesem Fall wird ein Byte [20], die umwandelt (BitConverter.ToInt32()) Dauern:

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

On MonoMac jedoch diese Codezeile für das gleiche Beispiel gibt einen GIF byte[4] die nur umwandelt eine Dauer (die erste):

[75,0,0,0] 

getestet habe ich diese für 10 verschiedene GIF's und das Ergebnis ist immer das gleiche. Unter Windows alle Dauern im byte [] sind, während MonoMac nur die erste Dauer aufgeführt:

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

am Mono Suche System.Drawing.Imagesource code, scheint die Länge in diesem Verfahren festgelegt werden, die ein GDI Wrapper:

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

Allerdings sehe ich wirklich keine Probleme, nicht mit der Quelle wie mit meiner Implementierung. Fehle ich etwas oder ist das ein Fehler?

+0

Ich glaube, Sie werden die Antwort in der Mono GDI Plus-Implementierung finden. Ich habe es mir angeschaut, aber ich habe nicht die Expertise über den Gif-Codec, um zu entziffern, was vor sich geht. Folgendes ist etwas von dem, was ich gefunden habe. [Image.FromFile] (https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs) ruft in [libgdiplus] auf (https: // github. com/mono/libgdiplus/Baum/Master/src). Inside libgdiplus sind Funktionen zum Laden von Bildern. Die Funktion 'gdip_load_gif_image' innerhalb der Datei [gifcodec.c] (https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c) lädt Gif-Bilder. –

+0

Sie müssen prüfen, was innerhalb von 'gdip_load_gif_image' passiert. Wie ich bereits erwähnt habe, ist das der Ort, wo das Bild geladen/decodiert wird und wo ich den Fehler vermute. Ich habe nicht die Gif-Expertise, um herauszufinden, was vor sich geht. Viel Glück. –

Antwort

1

Wenn Sie look into libgdiplus Sie werden sehen, dass die Eigenschaften sind immer von der aktiven Bitmap lesen:

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

Sie können die aktive Bitmap gesetzt durch Image.SelectActiveFrame aufrufen und dann Mono die richtigen Dauern zurückkehren, eins nach dem anderen. Da dies eine Inkompatibilität mit Windows ist, würde ich es als Mono-Bug bezeichnen. Als eine einfache Problemumgehung können Sie natürlich nur die Array-Länge überprüfen und beide Fälle behandeln. Das ist besser als ein Mono-Test, denn wenn Mono repariert wird, wird es weiter funktionieren.

+0

Das funktioniert super und danke für den plattformübergreifenden Kompatibilitätsvorschlag. – dsfgsho

2

Ich sehe auch nichts in der Mono-Quelle falsch. Es wäre hilfreich gewesen, wenn Sie eines der Beispielbilder gepostet hätten, die Sie ausprobiert haben. Eine Besonderheit des GIF-Bildformats ist, dass der Grafiksteuerungs-Erweiterungsblock, der die Bildzeit enthält, optional ist und vor einem Bilddeskriptor weggelassen werden kann. Nicht-Null-Quoten, also dass Sie GIF-Dateien haben, die nur ein GCE haben, das für alle Bilder gilt, sollten Sie die gleiche Bildzeit auf jedes Bild anwenden.

Beachten Sie, dass Sie nicht 4 Werte erhalten haben, die Frame-Zeit ist als 32-Bit-Wert codiert und Sie sehen die Little-Endian-Codierung für sie in einem Byte []. Sie sollten BitConverter.ToInt32() verwenden, wie Sie in Ihrem Beispielcode korrekt getan haben.

Ich denke, also Sie wahrscheinlich diese stattdessen verwenden sollten:

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

beachten Sie, dass es eine andere böse Implementierung ausführlich über GIF Bilder, Bilderrahmen # 2 und höher müssen nicht die gleiche Größe wie der Rahmen sein # 1. Und jeder Rahmen hat ein Metadatenfeld, das beschreibt, was mit dem vorherigen Rahmen gemacht werden soll, um ihn mit dem nächsten zu verbinden. Es gibt keine Eigenschafts-IDs, die ich kenne, um die Frame-Offset-, Size- und Undraw-Methode für jeden Frame zu erhalten. Ich denke, Sie müssen jeden Frame selbst in eine Bitmap umwandeln, um eine richtige Sequenz von Bildern zu erhalten. Sehr hässliche Details, GIF muss sterben.

+0

Böse Details in der Tat. Das ist [eines der GIFS] (http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif) Ich habe versucht das funktioniert unter Windows aber nicht auf MonoMac mit dem [ Code auf Pastebin] (http://pastebin.com/Y6iUGDX9). Für dieses GIF ist die 'Zeit' var 'byte [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'unter Windows aber ' Byte [4] = {75,0,0,0} 'auf MonoMac. Wie bereits erwähnt, funktionieren alle GIFs, die ich ausprobiert habe, unter Windows, also denke ich, dass dies nicht eine der Eigenheiten von GIF ist, sondern eher ein Problem mit Mono? – dsfgsho

+0

Ja, kann nicht unter einer Bodenmatte kehren. –