2013-07-21 3 views
7

Récemment, j'essayais de répondre à un autre SO question sur le chargement des cadres (Bitmap et durée) de GIFs animé. Le code peut être trouvé sur pastenbin.MonoMac System.Drawing.Image.GetPropertyItem (0x5100)

Tout en faisant des tests supplémentaires sur ce code avant de le déplacer dans ma bibliothèque dev, je remarque qu'il ya un problème avec cette ligne de code:

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

Lors de l'exécution de cette sous Windows .Net utilisant ce (example GIF), le tableau est de la même taille que la quantité d'images dans le GIF animé et rempli avec les durées des cadres. Dans ce cas, un octet [20] qui se transforme en (BitConverter.ToInt32()) durées:

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

Sur Monomac cependant, cette ligne de code pour le même exemple GIF retourne un byte[4] qui convertit seulement une durée de (la première):

[75,0,0,0] 

J'ai testé cela pour 10 différents GIF's et le résultat est toujours le même. Sous Windows toutes les durées sont dans l'octet [], alors que Monomac ne répertorie que la première durée:

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

En regardant le Mono System.Drawing.Imagesource code, la longueur semble être définie dans cette méthode, qui est une enveloppe GDI:

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

Cependant, je ne vois vraiment aucun problème, pas avec la source comme avec mon implémentation. Ai-je raté quelque chose ou est-ce un bug?

+0

Je crois que vous trouverez la réponse dans l'implémentation de Mono GDI Plus. Je l'ai regardé, mais je n'ai pas l'expertise sur le codec gif pour déchiffrer ce qui se passe. Voici une partie de ce que j'ai trouvé. [Image.FromFile] (https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs) appelle [libgdiplus] (https: // github. com/mono/libgdiplus/arbre/maître/src). Inside libgdiplus sont des fonctions pour charger des images. La fonction 'gdip_load_gif_image' à l'intérieur du fichier [gifcodec.c] (https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c) charge les images gif. –

+0

Vous aurez besoin de regarder ce qui se passe à l'intérieur de 'gdip_load_gif_image'. Comme je l'ai mentionné, c'est là que l'image est chargée/décodée et où je suppose que le bogue est. Je n'ai pas l'expertise du gif pour comprendre ce qui se passe. Bonne chance. –

Répondre

1

Si vous look into libgdiplus vous verrez que les propriétés sont toujours lues à partir du bitmap actif:

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

Vous pouvez définir le bitmap actif en appelant Image.SelectActiveFrame puis mono retournera les durées correctes, un par un. Comme c'est une incompatibilité avec Windows, je l'appellerais un bug mono. Comme solution de contournement simple, vous pouvez bien sûr simplement vérifier la longueur du tableau et gérer les deux cas. Ce sera mieux qu'une vérification de mono, car si le mono est réparé, cela continuera à fonctionner.

+0

Cela fonctionne très bien et merci pour la suggestion de compatibilité multiplateforme. – dsfgsho

2

Je ne vois rien de mal dans la source mono non plus. Cela aurait été utile si vous aviez posté l'un des exemples d'images que vous avez essayés. Une anomalie concernant le format d'image GIF est que le bloc d'extension de contrôle graphique qui contient l'heure d'image est facultatif et peut être omis avant un descripteur d'image. Cotes non nulles donc que vous avez des fichiers GIF qui ont juste un GCE qui s'applique à tous les cadres, vous êtes censé appliquer le même temps d'image à chaque image. Notez que vous n'avez pas obtenu 4 valeurs, le temps de trame est codé comme une valeur de 32 bits et vous voyez le petit codage endian dans un octet []. Vous devriez utiliser BitConverter.ToInt32(), comme vous l'avez fait dans votre exemple de code.

Je pense donc que vous devriez probablement utiliser cette place:

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

Prenez note qu'il ya un autre méchant détail de mise en œuvre sur les cadres GIF, cadres # 2 et jusqu'à ne pas être la même taille que le cadre # 1. Et chaque cadre a un champ de métadonnées qui décrit ce qui doit être fait avec le cadre précédent pour le fusionner avec le suivant. Il n'y a pas d'ID de propriété que je connaisse pour obtenir le décalage d'image, la taille et la méthode de désalignement pour chaque image. Je pense que vous avez besoin de rendre chaque image dans un bitmap pour obtenir une bonne séquence d'images. Très moche détails, GIF doit mourir.

+0

Nasty détails en effet. Ceci est [l'un des GIFS] (http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif) J'ai essayé cela fonctionne sur Windows mais pas sur MonoMac avec le [ code sur pastebin] (http://pastebin.com/Y6iUGDX9). Pour ce GIF, la variable 'times' var est ' octet [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'sur Windows mais ' byte [4] = {75,0,0,0} 'sur MonoMac. Comme mentionné précédemment, tous les fichiers GIF que j'ai essayé de travailler sur Windows, donc je suppose que ce n'est pas l'un des bizarreries de GIF, mais plutôt un problème avec Mono? – dsfgsho

+0

Oui, impossible de balayer sous un tapis de sol. –

Questions connexes