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);
        }