Skip to content

Commit 9b01c5d

Browse files
committed
Ensure to count existing images from header and footer too #113
1 parent a97bdfa commit 9b01c5d

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

src/Html2OpenXml/Expressions/ImageExpression.cs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
using System;
1313
using System.Collections.Generic;
14+
using System.Linq;
1415
using System.Threading;
1516
using AngleSharp.Html.Dom;
1617
using DocumentFormat.OpenXml;
@@ -117,12 +118,31 @@ private Border ComposeStyles ()
117118

118119
drawingObjId = 1; // 1 is the minimum ID set by MS Office.
119120
imageObjId = 1;
120-
foreach (var d in context.MainPart.Document.Body!.Descendants<Drawing>())
121+
122+
foreach (var part in new[] {
123+
context.MainPart.Document.Body!.Descendants<Drawing>(),
124+
context.MainPart.HeaderParts.SelectMany(f => f.Header.Descendants<Drawing>()),
125+
context.MainPart.FooterParts.SelectMany(f => f.Footer.Descendants<Drawing>())
126+
})
127+
foreach (Drawing d in part)
121128
{
122-
if (d.Inline == null) continue; // fix some rare issue where Inline is null (reported by scwebgroup)
123-
if (d.Inline!.DocProperties?.Id?.Value > drawingObjId) drawingObjId = d.Inline.DocProperties.Id;
129+
wp.DocProperties? docProperties = null;
130+
pic.NonVisualPictureProperties? nvPr = null;
131+
132+
if (d.Anchor != null)
133+
{
134+
docProperties = d.Anchor.GetFirstChild<wp.DocProperties>();
135+
nvPr = d.Anchor.GetFirstChild<a.Graphic>()?.GraphicData?.GetFirstChild<pic.Picture>()?.GetFirstChild<pic.NonVisualPictureProperties>();
136+
}
137+
else if (d.Inline != null)
138+
{
139+
docProperties = d.Inline!.DocProperties;
140+
nvPr = d.Inline!.Graphic?.GraphicData?.GetFirstChild<pic.NonVisualPictureProperties>();
141+
}
142+
143+
if (docProperties?.Id != null && docProperties.Id.Value > drawingObjId)
144+
drawingObjId = docProperties.Id.Value;
124145

125-
var nvPr = d.Inline!.Graphic?.GraphicData?.GetFirstChild<pic.NonVisualPictureProperties>();
126146
if (nvPr != null && nvPr.NonVisualDrawingProperties?.Id?.Value > imageObjId)
127147
imageObjId = nvPr.NonVisualDrawingProperties.Id;
128148
}

test/HtmlToOpenXml.Tests/ImgTests.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace HtmlToOpenXml.Tests
77
{
88
using pic = DocumentFormat.OpenXml.Drawing.Pictures;
9+
using wp = DocumentFormat.OpenXml.Drawing.Wordprocessing;
910

1011
/// <summary>
1112
/// Tests images.
@@ -86,9 +87,37 @@ public async Task LoadRemoteImage_BaseUri()
8687
AssertIsImg(elements.First());
8788
}
8889

89-
private void AssertIsImg (OpenXmlCompositeElement elements)
90+
[Test(Description = "Image ID must be unique, amongst header, body and footer parts")]
91+
public async Task UniqueImageIdAcrossPackagingParts()
9092
{
91-
var run = elements.GetFirstChild<Run>();
93+
using var generatedDocument = new MemoryStream();
94+
using (var buffer = ResourceHelper.GetStream("Resources.DocWithImgHeaderFooter.docx"))
95+
buffer.CopyTo(generatedDocument);
96+
97+
generatedDocument.Position = 0L;
98+
using WordprocessingDocument package = WordprocessingDocument.Open(generatedDocument, true);
99+
MainDocumentPart mainPart = package.MainDocumentPart;
100+
101+
var beforeMaxDocPropId = new[] {
102+
mainPart.Document.Body!.Descendants<wp.DocProperties>(),
103+
mainPart.HeaderParts.SelectMany(x => x.Header.Descendants<wp.DocProperties>()),
104+
mainPart.FooterParts.SelectMany(x => x.Footer.Descendants<wp.DocProperties>())
105+
}.SelectMany(x => x).MaxBy(x => x.Id?.Value ?? 0).Id.Value;
106+
107+
HtmlConverter converter = new(mainPart);
108+
await converter.ParseHtml("<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' width='42' height='42'>");
109+
mainPart.Document.Save();
110+
111+
var img = mainPart.Document.Body!.Descendants<Drawing>().FirstOrDefault();
112+
Assert.That(img, Is.Not.Null);
113+
Assert.That(img.Inline.DocProperties.Id.Value,
114+
Is.GreaterThan(beforeMaxDocPropId),
115+
"New image id is incremented considering existing images in header, body and footer");
116+
}
117+
118+
private Drawing AssertIsImg (OpenXmlCompositeElement element)
119+
{
120+
var run = element.GetFirstChild<Run>();
92121
Assert.That(run, Is.Not.Null);
93122
var img = run.GetFirstChild<Drawing>();
94123
Assert.That(img, Is.Not.Null);
@@ -99,6 +128,7 @@ private void AssertIsImg (OpenXmlCompositeElement elements)
99128
var imagePartId = pic.BlipFill.Blip.Embed.Value;
100129
var part = mainPart.GetPartById(imagePartId);
101130
Assert.That(part, Is.TypeOf(typeof(ImagePart)));
131+
return img;
102132
}
103133
}
104134
}
Binary file not shown.

0 commit comments

Comments
 (0)