/// <summary>
        /// Gets the OpenXml ImagePartType associated to an image.
        /// </summary>
        public static ImagePartType?GetImagePartTypeForImageUrl(Uri uri)
        {
            ImagePartType type;
            String        extension = System.IO.Path.GetExtension(uri.IsAbsoluteUri ? uri.Segments[uri.Segments.Length - 1] : uri.OriginalString);

            if (knownExtensions.TryGetValue(extension, out type))
            {
                return(type);
            }

            // extension not recognized, try with checking the query string. Expecting to resolve something like:
            // ./image.axd?picture=img1.jpg
            extension = System.IO.Path.GetExtension(uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.ToString());
            if (knownExtensions.TryGetValue(extension, out type))
            {
                return(type);
            }

            // so, match text of the form: data:image/yyy;base64,zzzzzzzzzzzz...
            // where yyy is the MIME type, zzz is the base64 encoded data
            DataUri dataUri = DataUri.Parse(uri.ToString());

            if (dataUri != null)
            {
                if (knownContentType.TryGetValue(dataUri.Mime, out type))
                {
                    return(type);
                }
            }

            return(null);
        }
        /// <summary>
        /// Decrypt the given DataUri.
        /// </summary>
        public void DownloadData(DataUri dataUri)
        {
            if (dataUri != null)
            {
                ImagePartType type;
                if (knownContentType.TryGetValue(dataUri.Mime, out type))
                {
                    imageInfo.Type = type;
                }

                imageInfo.RawData = dataUri.Data;
            }
        }
        protected Drawing AddImagePart(Uri imageUrl, string imageSource, string alt, Size preferredSize)
        {
            if (imageObjId == UInt32.MinValue)
            {
                // In order to add images in the document, we need to asisgn an unique id
                // to each Drawing object. So we'll loop through all of the existing <wp:docPr> elements
                // to find the largest Id, then increment it for each new image.

                drawingObjId = 1;                 // 1 is the minimum ID set by MS Office.
                imageObjId   = 1;
                foreach (var d in mainPart.Document.Body.Descendants <Drawing>())
                {
                    if (d.Inline == null)
                    {
                        continue;                                       // fix some rare issue where Inline is null (reported by scwebgroup)
                    }
                    if (d.Inline.DocProperties.Id > drawingObjId)
                    {
                        drawingObjId = d.Inline.DocProperties.Id;
                    }

                    var nvPr = d.Inline.Graphic.GraphicData.GetFirstChild <pic.NonVisualPictureProperties>();
                    if (nvPr != null && nvPr.NonVisualDrawingProperties.Id > imageObjId)
                    {
                        imageObjId = nvPr.NonVisualDrawingProperties.Id;
                    }
                }
                if (drawingObjId > 1)
                {
                    drawingObjId++;
                }
                if (imageObjId > 1)
                {
                    imageObjId++;
                }
            }

            // Cache all the ImagePart processed to avoid downloading the same image.
            CachedImagePart imagePart = null;

            // if imageUrl is null, we may consider imageSource is a DataUri.
            // thus, no need to download and cache anything
            if (imageUrl == null || !knownImageParts.TryGetValue(imageUrl, out imagePart))
            {
                HtmlImageInfo iinfo = new HtmlImageInfo()
                {
                    Size = preferredSize
                };
                ImageProvisioningProvider provider = new ImageProvisioningProvider(this.WebProxy, iinfo);

                if (imageUrl == null)
                {
                    provider.DownloadData(DataUri.Parse(imageSource));
                }
                else if (this.ImageProcessing == ImageProcessing.ManualProvisioning)
                {
                    // as HtmlImageInfo is a class, the EventArgs will act as a proxy
                    ProvisionImageEventArgs args = new ProvisionImageEventArgs(imageUrl, iinfo);
                    OnProvisionImage(args);

                    // did the user want to ignore this image?
                    if (args.Cancel)
                    {
                        return(null);
                    }
                }

                // Automatic Processing or the user did not supply himself the image and did not cancel the provisioning.
                // We download ourself the image.
                if (iinfo.RawData == null && imageUrl.IsAbsoluteUri)
                {
                    provider.DownloadData(imageUrl);
                }

                if (iinfo.RawData == null || !provider.Provision(imageUrl))
                {
                    return(null);
                }

                ImagePart ipart = mainPart.AddImagePart(iinfo.Type.Value);
                imagePart = new CachedImagePart()
                {
                    Part = ipart
                };
                imagePart.Width  = iinfo.Size.Width;
                imagePart.Height = iinfo.Size.Height;

                using (Stream outputStream = ipart.GetStream(FileMode.Create))
                {
                    outputStream.Write(iinfo.RawData, 0, iinfo.RawData.Length);
                    outputStream.Seek(0L, SeekOrigin.Begin);
                }

                if (imageUrl != null)                 // don't need to cache inlined-image
                {
                    knownImageParts.Add(imageUrl, imagePart);
                }
            }

            if (preferredSize.IsEmpty)
            {
                preferredSize.Width  = imagePart.Width;
                preferredSize.Height = imagePart.Height;
            }
            else if (preferredSize.Width <= 0 || preferredSize.Height <= 0)
            {
                Size actualSize = new Size(imagePart.Width, imagePart.Height);
                preferredSize = ImageHeader.KeepAspectRatio(actualSize, preferredSize);
            }

            string imagePartId  = mainPart.GetIdOfPart(imagePart.Part);
            long   widthInEmus  = new Unit(UnitMetric.Pixel, preferredSize.Width).ValueInEmus;
            long   heightInEmus = new Unit(UnitMetric.Pixel, preferredSize.Height).ValueInEmus;

            ++drawingObjId;
            ++imageObjId;

            var img = new Drawing(
                new wp.Inline(
                    new wp.Extent()
            {
                Cx = widthInEmus, Cy = heightInEmus
            },
                    new wp.EffectExtent()
            {
                LeftEdge = 19050L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L
            },
                    new wp.DocProperties()
            {
                Id = drawingObjId, Name = imageSource, Description = string.Empty
            },
                    new wp.NonVisualGraphicFrameDrawingProperties {
                GraphicFrameLocks = new a.GraphicFrameLocks()
                {
                    NoChangeAspect = true
                }
            },
                    new a.Graphic(
                        new a.GraphicData(
                            new pic.Picture(
                                new pic.NonVisualPictureProperties {
                NonVisualDrawingProperties = new pic.NonVisualDrawingProperties()
                {
                    Id = imageObjId, Name = imageSource, Description = alt
                },
                NonVisualPictureDrawingProperties = new pic.NonVisualPictureDrawingProperties(
                    new a.PictureLocks()
                {
                    NoChangeAspect = true, NoChangeArrowheads = true
                })
            },
                                new pic.BlipFill(
                                    new a.Blip()
            {
                Embed = imagePartId
            },
                                    new a.SourceRectangle(),
                                    new a.Stretch(
                                        new a.FillRectangle())),
                                new pic.ShapeProperties(
                                    new a.Transform2D(
                                        new a.Offset()
            {
                X = 0L, Y = 0L
            },
                                        new a.Extents()
            {
                Cx = widthInEmus, Cy = heightInEmus
            }),
                                    new a.PresetGeometry(
                                        new a.AdjustValueList()
                                        )
            {
                Preset = a.ShapeTypeValues.Rectangle
            }
                                    )
            {
                BlackWhiteMode = a.BlackWhiteModeValues.Auto
            })
                            )
            {
                Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture"
            })
                    )
            {
                DistanceFromTop = (UInt32Value)0U, DistanceFromBottom = (UInt32Value)0U, DistanceFromLeft = (UInt32Value)0U, DistanceFromRight = (UInt32Value)0U
            }
                );

            return(img);
        }
        //____________________________________________________________________
        //
        // Public Functionality

        #region DownloadData

        /// <summary>
        /// Download the remote or local image located at the specified url.
        /// </summary>
        public void DownloadData(Uri imageUrl)
        {
            // is it a local path?
            if (imageUrl.IsFile)
            {
                // replace string %20 in LocalPath by daviderapicavoli (patch #15938)
                String localPath = Uri.UnescapeDataString(imageUrl.LocalPath);

                try
                {
                    // just read the picture from the file system
                    imageInfo.RawData = File.ReadAllBytes(localPath);
                }
                catch (IOException exc)
                {
                    if (Logging.On)
                    {
                        Logging.PrintError("ImageDownloader.DownloadData(\"" + localPath + "\")", exc);
                    }
                }
                catch (SystemException exc)
                {
                    if (Logging.On)
                    {
                        Logging.PrintError("ImageDownloader.DownloadData(\"" + localPath + "\")", exc);
                    }

                    if (exc is UnauthorizedAccessException || exc is System.Security.SecurityException || exc is NotSupportedException)
                    {
                        return;
                    }
                    throw;
                }

                return;
            }

            // data inline, encoded in base64
            if (imageUrl.Scheme == "data")
            {
                DataUri dataUri = DataUri.Parse(imageUrl.OriginalString);
                DownloadData(dataUri);
                return;
            }

            System.Net.WebClient webClient = new WebClientEx(proxy);
            try
            {
                imageInfo.RawData = webClient.DownloadData(imageUrl);

                // For requested url with no filename, we need to read the media mime type if provided
                imageInfo.Type = InspectMimeType(webClient);
            }
            catch (System.Net.WebException exc)
            {
                if (Logging.On)
                {
                    Logging.PrintError("ImageDownloader.DownloadData(\"" + imageUrl.AbsoluteUri + "\")", exc);
                }
            }
        }