2013-07-21 12 views
7

Son zamanlarda, animasyonlu GIFs çerçevelerinin (Bit eşlem ve süresinin) yüklenmesi hakkında bir SO question numaralı yanıt vermeye çalışıyordum. Kod pastenbin adresinde bulunabilir.MonoMac System.Drawing.Image.GetPropertyItem (0x5100)

benim dev kütüphane içine geçmeden önce bu kodun üzerinde ilave testler yaparken, ben bu kod satırı ile bir sorun olduğunu fark ettik:

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

bu kullanarak, Windows .NET bu çalışan (example GIF), dizi, animasyonlu GIF'daki karelerin miktarı ile aynı boyuttadır ve çerçevelerin süreleriyle doldurulur. (BitConverter.ToInt32()) sürelere dönüştüren bu durumda bir bayt [20]: Monomac üzerinde

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

Ancak aynı örnek için kod bu hat sadece GIF dönüştüren bir byte[4] döndürür bir süresi (birinci):

[75,0,0,0] 

I10 farklı GIF's için test edilmiş ve sonuç her zaman aynıdır. MonoMac sadece ilk süresini listelerken Windows'ta bütün süreler, byte [] içindedir:

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

Mono System.Drawing.Image source code baktığımızda, uzunluğu GDI sarıcı bu yöntemde, ayarlanabilir görünmektedir:

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

Bununla birlikte, gerçekten, uygulamamdaki gibi kaynak ile ilgili herhangi bir sorun görmüyorum. Bir şeyi mi özledim yoksa bu bir böcek mi?

+0

Mono GDI Plus uygulamasında cevabı bulacağınıza inanıyorum. Şuna bir baktım ama ne olup bittiğini deşifre etmek için gif kodeki uzmanlığım yok. Aşağıda bulduğum şeylerden bazıları. [Image.FromFile] (https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs) [libgdiplus] 'a (https: // github. com/mono/libgdiplus/ağaç/ana/src). İç libgdiplus görüntüleri yüklemek için fonksiyonlardır. [Gifcodec.c] dosyasının içinde gdip_load_gif_image işlevi (https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c) gif görüntüleri yükler. –

+0

"gdip_load_gif_image" öğesinin içinde neler olduğuna bakmanız gerekecek. Bahsettiğim gibi, resmin yüklendiği/kodu çözüldüğü ve hatanın nerede olduğunu tahmin edeceğim yer burasıdır. Neler olup bittiğini anlamak için GIF uzmanlığım yok. İyi şanslar. –

cevap

1

Eğer özelliklerini daima aktif bitmap okunur göreceksiniz look into libgdiplus ise:

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

Sen Image.SelectActiveFrame arayarak aktif bitmap ayarlayabilirsiniz ve sonra mono bir bir doğru süreleri dönecektir. Bu, pencerelerle uyumsuzluk olduğundan, buna mono bir hata derim. Basit bir çözüm olarak, elbette dizi uzunluğunu kontrol edebilir ve her iki durumu da ele alabilirsiniz. Bu mono için bir kontrolden daha iyi olacaktır, çünkü eğer mono sabitlenirse, bu çalışmaya devam edecektir.

+0

Bu harika çalışıyor ve platformlar arası uyumluluk önerisi için teşekkürler. – dsfgsho

2

Mono kaynağında yanlış bir şey göremiyorum. Denediğin örnek görüntülerden birini yayınlarsan, yardımcı olurdu. GIF görüntü formatı hakkında bir tuhaflık, kare zamanını içeren Grafik Kontrol Uzantısı bloğunun opsiyonel olmasıdır ve bir resim tanımlayıcısından önce ihmal edilebilir. Bu nedenle, sıfır olmayan oranlar, sadece tüm karelere uygulanan bir GCE'ye sahip GIF dosyalarına sahip olmanız durumunda, her kare için aynı çerçeve süresini uygulamanız gerekir.

4 değer almadınız, çerçeve süresinin 32 bitlik bir değer olarak kodlandığını ve bunun için küçük bir endian kodlamanın bir bayt [] olduğunu görüyorsunuz. Örnek kodunuzda doğru yaptığınız gibi BitConverter.ToInt32() kullanmalısınız. Çerçeve # aynı boyutta olması gerekmez yukarı 2. çerçeveleri,

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

GIF çerçeveler hakkında da feci uygulama detay daha var unutmayın yapın ve:

Bu nedenle muhtemelen yerine bunu kullanmak gerektiğini düşünüyorum 1. Her çerçevede, bir önceki kareyle bir sonraki ile birleştirmek için yapılması gerekenleri açıklayan bir meta veri alanı vardır. Her çerçeve için çerçeve ofsetini, boyutunu ve undraw yöntemini almak için bildiğim bir özellik kimliği yoktur. Doğru bir görüntü dizisi elde etmek için her kareyi kendinize bir bitmap haline getirmeniz gerektiğini düşünüyorum. Çok çirkin detaylar, GIF'in ölmesi gerekiyor.

+0

Gerçekten de iğrenç detaylar. Bu [GIFS] biridir (http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif) Ben Windows üzerinde çalışır ancak MonoMac ile değil çalıştı [ pastebin kodu] (http://pastebin.com/Y6iUGDX9). Bu GIF için 'times' var ' bayttır [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'Windows üzerinde ancak ' bayt [4] = {75,0,0,0}' MonoMac’te. Daha önce de bahsettiğim gibi, Windows üzerinde çalıştığım tüm GIF'ler bu yüzden GIF'in sıkıntılarından biri değil, Mono ile ilgili bir problem olduğunu düşünüyorum. – dsfgsho

+0

Evet, bir zemin paspasının altında süpürme yapamayız. –