diff --git a/src/Html2OpenXml/Expressions/ImageExpression.cs b/src/Html2OpenXml/Expressions/ImageExpression.cs index e23ed61..286de70 100644 --- a/src/Html2OpenXml/Expressions/ImageExpression.cs +++ b/src/Html2OpenXml/Expressions/ImageExpression.cs @@ -11,6 +11,7 @@ */ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using AngleSharp.Html.Dom; using DocumentFormat.OpenXml; @@ -117,12 +118,31 @@ private Border ComposeStyles () drawingObjId = 1; // 1 is the minimum ID set by MS Office. imageObjId = 1; - foreach (var d in context.MainPart.Document.Body!.Descendants()) + + foreach (var part in new[] { + context.MainPart.Document.Body!.Descendants(), + context.MainPart.HeaderParts.SelectMany(f => f.Header.Descendants()), + context.MainPart.FooterParts.SelectMany(f => f.Footer.Descendants()) + }) + foreach (Drawing d in part) { - if (d.Inline == null) continue; // fix some rare issue where Inline is null (reported by scwebgroup) - if (d.Inline!.DocProperties?.Id?.Value > drawingObjId) drawingObjId = d.Inline.DocProperties.Id; + wp.DocProperties? docProperties = null; + pic.NonVisualPictureProperties? nvPr = null; + + if (d.Anchor != null) + { + docProperties = d.Anchor.GetFirstChild(); + nvPr = d.Anchor.GetFirstChild()?.GraphicData?.GetFirstChild()?.GetFirstChild(); + } + else if (d.Inline != null) + { + docProperties = d.Inline!.DocProperties; + nvPr = d.Inline!.Graphic?.GraphicData?.GetFirstChild(); + } + + if (docProperties?.Id != null && docProperties.Id.Value > drawingObjId) + drawingObjId = docProperties.Id.Value; - var nvPr = d.Inline!.Graphic?.GraphicData?.GetFirstChild(); if (nvPr != null && nvPr.NonVisualDrawingProperties?.Id?.Value > imageObjId) imageObjId = nvPr.NonVisualDrawingProperties.Id; } diff --git a/test/HtmlToOpenXml.Tests/ImgTests.cs b/test/HtmlToOpenXml.Tests/ImgTests.cs index d79cd01..f1fe8a6 100644 --- a/test/HtmlToOpenXml.Tests/ImgTests.cs +++ b/test/HtmlToOpenXml.Tests/ImgTests.cs @@ -6,6 +6,7 @@ namespace HtmlToOpenXml.Tests { using pic = DocumentFormat.OpenXml.Drawing.Pictures; + using wp = DocumentFormat.OpenXml.Drawing.Wordprocessing; /// /// Tests images. @@ -86,9 +87,37 @@ public async Task LoadRemoteImage_BaseUri() AssertIsImg(elements.First()); } - private void AssertIsImg (OpenXmlCompositeElement elements) + [Test(Description = "Image ID must be unique, amongst header, body and footer parts")] + public async Task UniqueImageIdAcrossPackagingParts() { - var run = elements.GetFirstChild(); + using var generatedDocument = new MemoryStream(); + using (var buffer = ResourceHelper.GetStream("Resources.DocWithImgHeaderFooter.docx")) + buffer.CopyTo(generatedDocument); + + generatedDocument.Position = 0L; + using WordprocessingDocument package = WordprocessingDocument.Open(generatedDocument, true); + MainDocumentPart mainPart = package.MainDocumentPart; + + var beforeMaxDocPropId = new[] { + mainPart.Document.Body!.Descendants(), + mainPart.HeaderParts.SelectMany(x => x.Header.Descendants()), + mainPart.FooterParts.SelectMany(x => x.Footer.Descendants()) + }.SelectMany(x => x).MaxBy(x => x.Id?.Value ?? 0).Id.Value; + + HtmlConverter converter = new(mainPart); + await converter.ParseHtml(""); + mainPart.Document.Save(); + + var img = mainPart.Document.Body!.Descendants().FirstOrDefault(); + Assert.That(img, Is.Not.Null); + Assert.That(img.Inline.DocProperties.Id.Value, + Is.GreaterThan(beforeMaxDocPropId), + "New image id is incremented considering existing images in header, body and footer"); + } + + private Drawing AssertIsImg (OpenXmlCompositeElement element) + { + var run = element.GetFirstChild(); Assert.That(run, Is.Not.Null); var img = run.GetFirstChild(); Assert.That(img, Is.Not.Null); @@ -99,6 +128,7 @@ private void AssertIsImg (OpenXmlCompositeElement elements) var imagePartId = pic.BlipFill.Blip.Embed.Value; var part = mainPart.GetPartById(imagePartId); Assert.That(part, Is.TypeOf(typeof(ImagePart))); + return img; } } } \ No newline at end of file diff --git a/test/HtmlToOpenXml.Tests/Resources/DocWithImgHeaderFooter.docx b/test/HtmlToOpenXml.Tests/Resources/DocWithImgHeaderFooter.docx new file mode 100644 index 0000000..99790b2 Binary files /dev/null and b/test/HtmlToOpenXml.Tests/Resources/DocWithImgHeaderFooter.docx differ