2013-07-21 8 views
7

Ostatnio próbowałem odpowiedzieć na kolejne SO question dotyczące ładowania klatek (bitmapa i czas trwania) animowanego GIFs. Kod można znaleźć pod adresem pastenbin.MonoMac System.Drawing.Image.GetPropertyItem (0x5100)

Podczas wykonywania dodatkowych badań na temat tego kodu przed przeniesieniem go do mojej biblioteki dev, zauważyłem, że jest problem z tej linii kodu:

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

Uruchamiając ten Windows .NET przy użyciu tego (example GIF), tablica ma taki sam rozmiar, jak liczba klatek w animowanym pliku GIF i jest wypełniona czasami trwania klatek. W tym przypadku bajt [20], w którym przekształca się (BitConverter.ToInt32()) trwania:

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

Na Monoman Jednakże ta linia kodu w tym samym przykładzie GIF zwraca byte[4] który przekształca się tylko jeden okres (pierwszy)

[75,0,0,0] 

i badane w tym 10 różnych GIF's a wynik jest zawsze taki sam. W systemie Windows wszystkie okresy są w byte [], natomiast Monoman wymienia tylko pierwszy czas trwania:

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

Patrząc na Mono System.Drawing.Imagesource code długość wydają się być ustawione w tej metodzie, która jest GDI wrapper:

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

Jednak naprawdę nie widzę żadnych problemów, nie ze źródłem, jak z moją implementacją. Czy brakuje mi czegoś lub jest to błąd?

+0

Wierzę, że znajdziesz odpowiedź w implementacji Mono GDI Plus. Rzuciłem okiem na to, ale nie mam wiedzy na temat kodeku gif, żeby rozszyfrować to, co się dzieje. Oto niektóre z tego, co znalazłem. [Image.FromFile] (https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs) wywołuje funkcję [libgdiplus] (https: // github. com/mono/libgdiplus/drzewo/master/src). Wewnątrz libgdiplus są funkcje do ładowania obrazów. Funkcja 'gdip_load_gif_image' wewnątrz pliku [gifcodec.c] (https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c) ładuje obrazy gif. –

+0

Będziesz musiał sprawdzić, co dzieje się wewnątrz 'gdip_load_gif_image'. Jak już wspomniałem, jest to miejsce, w którym obraz jest ładowany/dekodowany i gdzie zgaduję, że jest to błąd. Nie mam wiedzy na temat gif, aby dowiedzieć się, co się dzieje. Powodzenia. –

Odpowiedz

1

Jeśli look into libgdiplus widać, że właściwości są zawsze odczytywane z aktywnej mapy bitowej:

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

Można ustawić aktywną bitmapę poprzez wywołanie Image.SelectActiveFrame a następnie mono powróci prawidłowe trwania, jeden po drugim. Ponieważ jest to niekompatybilność z oknami, nazwałbym to monobusem. Jako proste obejście możesz oczywiście sprawdzić długość tablicy i obsłużyć oba przypadki. To będzie lepsze niż sprawdzanie dla mono, ponieważ jeśli mono zostanie naprawione, to będzie działało dalej.

+0

Działa to świetnie i dzięki za sugestie zgodności między platformami. – dsfgsho

2

Nie widzę też niczego złego w monofonicznym źródle. Byłoby pomocne, gdyby opublikowałeś jeden z przykładowych obrazów, które wypróbowałeś. Jednym z dziwactw dotyczących formatu obrazu GIF jest to, że blok rozszerzenia grafiki, który zawiera czas ramki, jest opcjonalny opcjonalnie i można go pominąć przed deskryptorem obrazu. Niezerowe kursy powodują, że masz pliki GIF, które mają tylko jeden GCE, który dotyczy wszystkich ramek, powinieneś zastosować ten sam czas ramkowania do każdej klatki.

Zauważ, że nie dostałeś 4 wartości, czas ramki jest zakodowany jako 32-bitowa wartość i widzisz kodowanie małego endianu w bajcie []. Powinieneś użyć BitConverter.ToInt32(), tak jak poprawnie zrobiłeś w swoim przykładowym kodzie.

dlatego myślę, że powinieneś to wykorzystać zamiast:

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

Należy pamiętać, że istnieje inny paskudny realizacja szczegółów na temat klatek GIF, ramki nr 2, a nawet nie muszą być tego samego rozmiaru jak ramki # 1. Każda klatka ma pole metadanych, które opisuje, co należy zrobić z poprzednią ramką, aby połączyć ją z kolejną. Nie ma identyfikatorów właściwości, które znam, aby uzyskać przesunięcie ramki, rozmiar i metodę cofania dla każdej ramki. Myślę, że musisz wyrenderować każdą klatkę w bitmapę, aby uzyskać odpowiednią sekwencję obrazów. Bardzo brzydkie szczegóły, GIF musi umrzeć.

+0

Rzeczywiście są paskudne. To jest [jeden z GIF] (http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif) Próbowałem, który działa w systemie Windows, ale nie na MonoMac z [ kod na pastebinie] (http://pastebin.com/Y6iUGDX9). W przypadku tego GIF warunek 'times' jest równy ' bajt [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'na Windows ale ' bajt [4] = {75,0,0,0} 'na MonoMac. Jak już wspomniano, wszystkie GIF-y, które próbowałem pracować w systemie Windows, więc myślę, że to nie jest jeden z dziwactw GIF-a, ale raczej problem z Mono? – dsfgsho

+0

Tak, nie można tego zamiatać pod matą podłogową. –