2013-07-21 62 views
7

Gần đây, tôi đã cố gắng trả lời một số khác SO question về cách tải các khung (Bitmap và thời lượng) của hoạt ảnh GIFs. Mã này có thể được tìm thấy trên pastenbin.MonoMac System.Drawing.Image.GetPropertyItem (0x5100)

Trong khi làm bài kiểm tra bổ sung đối với mã này trước khi chuyển nó vào thư viện dev của tôi, tôi nhận thấy rằng có một vấn đề với dòng mã này:

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

Khi chạy này trên Windows Net sử dụng này (example GIF), mảng có cùng kích thước với số lượng khung hình trong hoạt ảnh GIF và được lấp đầy với thời lượng của khung. Trong trường hợp này một byte [20] mà chuyển đến (BitConverter.ToInt32()) khoảng thời gian:

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

On MonoMac Tuy nhiên, dòng mã này cho ví dụ tương tự GIF trả về một byte[4] mà chuyển đến chỉ một thời gian (lần đầu tiên):

[75,0,0,0] 

Tôi đã thử nghiệm điều này cho 10 khác nhau GIF's và kết quả luôn như cũ. Trên Windows tất cả các khoảng thời gian đang trong byte [], trong khi MonoMac chỉ liệt kê thời gian đầu tiên:

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

Nhìn vào Mono System.Drawing.Imagesource code, chiều dài dường như được thiết lập trong phương pháp này, mà là một wrapper GDI:

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

Tuy nhiên, tôi không thực sự thấy bất kỳ vấn đề nào, không phải với nguồn như khi triển khai. Tôi đang thiếu một cái gì đó hoặc là một lỗi này?

+0

Tôi tin rằng bạn sẽ tìm thấy câu trả lời trong triển khai Mono GDI Plus. Tôi đã xem xét nó, nhưng tôi không có chuyên môn về codec gif để giải mã những gì đang xảy ra. Sau đây là một số những gì tôi tìm thấy. [Image.FromFile] (https://github.com/mono/mono/blob/master/mcs/class/System.Drawing/System.Drawing/Image.cs) gọi vào [libgdiplus] (https: // github. com/mono/libgdiplus/tree/master/src). Bên trong libgdiplus có chức năng tải hình ảnh. Hàm 'gdip_load_gif_image' bên trong tệp [gifcodec.c] (https://github.com/mono/libgdiplus/blob/master/src/gifcodec.c) tải hình ảnh gif. –

+0

Bạn sẽ cần phải nhìn vào những gì xảy ra bên trong 'gdip_load_gif_image'. Như tôi đã đề cập, đó là nơi hình ảnh được tải/giải mã và nơi tôi đoán được lỗi. Tôi không có chuyên môn gif để tìm ra những gì đang xảy ra. Chúc may mắn. –

Trả lời

1

Nếu bạn look into libgdiplus bạn sẽ thấy rằng các thuộc tính luôn đọc từ bitmap hoạt động:

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

Bạn có thể thiết lập các bitmap hoạt động bằng cách gọi Image.SelectActiveFrame và sau đó mono sẽ trả lại khoảng thời gian chính xác, từng người một. Vì đây là một sự không tương thích với các cửa sổ, tôi gọi nó là một lỗi đơn. Như một giải pháp đơn giản, bạn có thể chỉ cần kiểm tra chiều dài mảng và xử lý cả hai trường hợp. Điều này sẽ tốt hơn một kiểm tra cho mono, bởi vì nếu mono được cố định, điều này sẽ tiếp tục hoạt động.

+0

Điều này rất hữu ích và cảm ơn đề xuất về tính tương thích đa nền tảng. – dsfgsho

2

Tôi cũng không thấy bất kỳ điều gì sai trong nguồn đơn âm. Sẽ rất hữu ích nếu bạn đã đăng một trong những hình ảnh mẫu mà bạn đã thử. Một quirk về định dạng hình ảnh GIF là khối Mở rộng Điều khiển Đồ hoạ có chứa thời gian khung là tùy chọn và có thể bị bỏ qua trước một bộ mô tả hình ảnh. Do đó, bạn có các tệp GIF chỉ có một GCE áp dụng cho tất cả các khung, bạn phải áp dụng cùng một khung thời gian cho mọi khung hình.

Lưu ý rằng bạn không nhận được 4 giá trị, thời gian khung được mã hóa dưới dạng giá trị 32 bit và bạn thấy mã hóa cuối nhỏ cho nó theo byte []. Bạn nên sử dụng BitConverter.ToInt32(), như bạn đã làm đúng trong mã mẫu của bạn.

Vì vậy, tôi nghĩ có lẽ bạn nên sử dụng này để thay thế:

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

Đừng lưu ý rằng có một chi tiết thực hiện khó chịu về khung GIF, khung # 2 trở lên không cần phải có cùng kích thước như khung # 1. Và mỗi khung có một trường siêu dữ liệu mô tả những gì nên được thực hiện với khung trước đó để hợp nhất nó với khung tiếp theo. Không có ID thuộc tính nào mà tôi biết để có được phương thức bù đắp, kích thước và phương thức vẽ khung cho mỗi khung hình. Tôi nghĩ bạn cần phải render từng khung hình thành một bitmap để có được một chuỗi hình ảnh phù hợp. Các chi tiết rất xấu, GIF cần phải chết.

+0

Chi tiết khó chịu thực sự. Đây là [một trong những GIF] (http://upload.wikimedia.org/wikipedia/commons/5/50/Triple-Spiral-Labyrinth-animated.gif) Tôi đã thử làm việc trên Windows nhưng không phải trên MonoMac với [ mã trên pastebin] (http://pastebin.com/Y6iUGDX9). Đối với GIF này, biến 'lần' là ' byte [20] = {75,0,0,0,125,0,0,0,125,0,0,0,125,0,0,0,250,0,0,0} 'trên Windows nhưng ' byte [4] = {75,0,0,0} 'trên MonoMac. Như đã đề cập trước đó, tất cả GIF tôi đã thử làm việc trên Windows vì vậy tôi đoán đây không phải là một trong những quirks GIF mà là một vấn đề với Mono? – dsfgsho

+0

Có, không thể quét dưới thảm sàn. –