简体   繁体   English

MonoMac System.Drawing.Image.GetPropertyItem(0x5100)

[英]MonoMac System.Drawing.Image.GetPropertyItem(0x5100)

Recently, I was trying to answer another SO question about loading the frames (Bitmap and duration) of animated GIFs . 最近,我试图回答关于加载动画GIFs的帧(位图和持续时间)的另一个问题 The code can be found on pastenbin . 代码可以在pastenbin找到

While doing additional tests on this code before moving it into my dev library, I noticed that there is a problem with this line of 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;

When running this on Windows .Net using this ( example GIF ), the array is of the same size as the amount of frames in the animated GIF and filled with the durations of the frames. 使用此( 例如GIF )在Windows .Net上运行此数组时,该数组的大小与动画GIF的帧数相同,并填充帧的持续时间。 In this case a byte[20] which converts to (BitConverter.ToInt32()) 5 durations: 在这种情况下,一个字节[20]转换为(BitConverter.ToInt32()) 5个持续时间:

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

On MonoMac however, this line of code for the same example GIF returns a byte[4] which converts to only one duration (the first): 但是,在MonoMac上,同一个示例GIF的这行代码返回一个byte[4] ,它只转换为一个持续时间(第一个):

[75,0,0,0]

I tested this for 10 different GIF's and the result is always the same. 我测试了10个不同的GIF's ,结果总是一样的。 On Windows all durations are in the byte[], while MonoMac only lists the first duration: 在Windows上,所有持续时间都在byte []中,而MonoMac仅列出第一个持续时间:

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

Looking at the Mono System.Drawing.Image source code , the length seem to be set in this method, which is a GDI wrapper: 查看Mono System.Drawing.Image 源代码 ,这个方法的长度似乎是设置的,这是一个GDI包装器:

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

However, I don't really see any problems, not with the source as with my implementation. 但是,我没有看到任何问题,不像我的实现那样使用源代码。 Am I missing something or is this a bug? 我错过了什么或这是一个错误吗?

I don't see anything wrong in the mono source either. 我也没有看到单音源中的任何错误。 It would have been helpful if you would have posted one of the sample images you tried. 如果您要发布您尝试过的示例图像之一,那将会很有帮助。 One quirk about the GIF image format is that the Graphics Control Extension block that contains the frame time is optional and may be omitted before an image descriptor. 关于GIF图像格式的一个怪癖是包含帧时间的图形控制扩展块是可选的,并且可以在图像描述符之前省略。 Non-zero odds therefore that you have GIF files that just have one GCE that applies to all the frames, you are supposed to apply the same frame time to every frame. 因此,非零赔率你有GIF文件只有一个适用于所有帧的GCE,你应该对每一帧应用相同的帧时间。

Do note that you didn't get 4 values, the frame time is encoded as a 32-bit value and you are seeing the little endian encoding for it in a byte[]. 请注意,您没有获得4个值,帧时间被编码为32位值,您在字节[]中看到它的小端编码。 You should use BitConverter.ToInt32(), as you correctly did in your sample code. 您应该使用BitConverter.ToInt32(),正如您在示例代码中所做的那样。

I therefore think you should probably use this instead: 因此,我认为你应该使用它:

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

Do note that there's another nasty implementation detail about GIF frames, frames #2 and up do not have to be the same size as the frame #1. 请注意,有关GIF帧的另一个讨厌的实现细节,帧#2和up不必与帧#1的大小相同。 And each frame has a metadata field that describes what should be done with the previous frame to merge it with the next one. 每个帧都有一个元数据字段,用于描述应该对前一帧进行的操作以将其与下一帧合并。 There are no property IDs that I know of to obtain the frame offset, size and undraw method for each frame. 我知道没有属性ID来获取每帧的帧偏移,大小和未描绘方法。 I think you need to render each frame into a bitmap yourself to get a proper sequence of images. 我认为您需要自己将每个帧渲染成位图以获得正确的图像序列。 Very ugly details, GIF needs to die. 非常难看的细节,GIF需要死。

If you look into libgdiplus you will see that the properties are always read from the active bitmap: 如果查看libgdiplus,您将看到始终从活动位图读取属性:

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

You can set the active bitmap by calling Image.SelectActiveFrame and then mono will return the correct durations, one by one. 您可以通过调用Image.SelectActiveFrame来设置活动位图,然后mono将逐个返回正确的持续时间。 Since this is an incompatibility with windows, I'd call it a mono bug. 由于这与windows不兼容,我称之为单声道bug。 As a simple workaround, you can of course just check the array length and handle both cases. 作为一种简单的解决方法,您当然可以检查数组长度并处理这两种情况。 This will be better than a check for mono, because if mono gets fixed this will continue to work. 这将比检查单声道更好,因为如果单声道固定,这将继续工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM