private async Task<FrameProperties> RetrieveFramePropertiesAsync(uint index, BitmapFrame frame) { const string leftProperty = "/imgdesc/Left"; const string topProperty = "/imgdesc/Top"; const string widthProperty = "/imgdesc/Width"; const string heightProperty = "/imgdesc/Height"; const string delayProperty = "/grctlext/Delay"; const string disposalProperty = "/grctlext/Disposal"; var propertiesView = frame.BitmapProperties; var requiredProperties = new[] { leftProperty, topProperty, widthProperty, heightProperty }; var properties = await propertiesView.GetPropertiesAsync(requiredProperties).AsTask().ConfigureAwait(false); ; var left = (ushort)properties[leftProperty].Value; var top = (ushort)properties[topProperty].Value; var width = (ushort)properties[widthProperty].Value; var height = (ushort)properties[heightProperty].Value; var delayMilliseconds = 30.0; var shouldDispose = false; try { var extensionProperties = new[] { delayProperty, disposalProperty }; properties = await propertiesView.GetPropertiesAsync(extensionProperties).AsTask().ConfigureAwait(false); ; if (properties.ContainsKey(delayProperty)) { if (properties[delayProperty].Type == PropertyType.UInt16) { var delayInHundredths = (ushort)properties[delayProperty].Value; if (delayInHundredths >= 3u) // Prevent degenerate frames with no delay time { delayMilliseconds = delayInHundredths * 10.0d; } if (delayInHundredths == 0u) // Prevent degenerate frames with no delay time { delayMilliseconds = 100.0d; } } } if (properties.ContainsKey(disposalProperty) && properties[disposalProperty].Type == PropertyType.UInt8) { var disposal = (byte)properties[disposalProperty].Value; if (disposal == 2) { // 0 = undefined 不使用处置方法 // 1 = none (compose next frame on top of this one, default) 不处置图形,把图形从当前位置移去 // 2 = dispose 回复到背景色 // 3 = revert to previous (not supported) 回复到先前状态 shouldDispose = true; } } } catch { // These properties are not required, so it's okay to ignore failure. } return new FrameProperties(index, new Rect(left, top, width, height), delayMilliseconds, shouldDispose ); }
private static async Task<ImageProperties> RetrieveImagePropertiesAsync(BitmapDecoder bitmapDecoder) { // Properties not currently supported: background color, pixel aspect ratio. const string widthProperty = "/logscrdesc/Width"; const string heightProperty = "/logscrdesc/Height"; const string applicationProperty = "/appext/application"; const string dataProperty = "/appext/data"; var propertiesView = bitmapDecoder.BitmapContainerProperties; var requiredProperties = new[] { widthProperty, heightProperty }; var properties = await propertiesView.GetPropertiesAsync(requiredProperties).AsTask().ConfigureAwait(false); var pixelWidth = (ushort)properties[widthProperty].Value; var pixelHeight = (ushort)properties[heightProperty].Value; var loopCount = 0; // Repeat forever by default var isAnimated = true; try { var extensionProperties = new[] { applicationProperty, dataProperty }; properties = await propertiesView.GetPropertiesAsync(extensionProperties); if (properties.ContainsKey(applicationProperty) && properties[applicationProperty].Type == PropertyType.UInt8Array) { var bytes = (byte[])properties[applicationProperty].Value; var applicationName = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (applicationName == "NETSCAPE2.0" || applicationName == "ANIMEXTS1.0") { if (properties.ContainsKey(dataProperty) && properties[dataProperty].Type == PropertyType.UInt8Array) { // The data is in the following format: // byte 0: extsize (must be > 1) // byte 1: loopType (1 == animated gif) // byte 2: loop count (least significant byte) // byte 3: loop count (most significant byte) // byte 4: set to zero var data = (byte[])properties[dataProperty].Value; loopCount = data[2] | data[3] << 8; isAnimated = data[1] == 1; } } } } catch (Exception ex) { // These properties are not required, so it's okay to ignore failure. } return new ImageProperties(pixelWidth, pixelHeight, isAnimated, loopCount); }