Skip to content

Commit 5ba83c9

Browse files
committedMar 23, 2025·
Support percentage size for image #188
1 parent d3606b9 commit 5ba83c9

File tree

7 files changed

+40
-17
lines changed

7 files changed

+40
-17
lines changed
 

‎examples/Demo/Demo.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
<ItemGroup>
2323
<EmbeddedResource Include="Resources\*" />
24+
<Content Include="images\*" CopyToOutputDirectory="PreserveNewest"/>
2425
</ItemGroup>
2526

2627
</Project>

‎examples/Demo/Resources/LargeImg.html

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<img src="The-Song-of-the-World.jpg" style="max-width:100%"/>

‎examples/Demo/app.config

-13
This file was deleted.
254 KB
Loading

‎src/Html2OpenXml/Expressions/Image/ImageExpression.cs

+25-1
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node)
5656
}
5757
if (imgNode.DisplayHeight > 0)
5858
{
59-
// Image perspective skewed. Bug fixed by ddeforge on github.com/onizet/html2openxml/discussions/350500
6059
preferredSize.Height = imgNode.DisplayHeight;
6160
}
61+
if (preferredSize.IsEmpty)
62+
{
63+
var styles = imgNode.GetStyles();
64+
preferredSize.Width = GetDimension(styles, "width", "max-width", 642);
65+
preferredSize.Height = GetDimension(styles, "height", "max-height", 428);
66+
}
6267

6368
HtmlImageInfo? iinfo = context.ImageLoader.Download(src, CancellationToken.None)
6469
.ConfigureAwait(false).GetAwaiter().GetResult();
@@ -85,6 +90,7 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node)
8590
else if (preferredSize.Width <= 0 || preferredSize.Height <= 0)
8691
{
8792
Size actualSize = iinfo.Size;
93+
// Image perspective skewed. Bug fixed by ddeforge on github.com/onizet/html2openxml/discussions/350500
8894
preferredSize = ImageHeader.KeepAspectRatio(actualSize, preferredSize);
8995
}
9096

@@ -130,4 +136,22 @@ class ImageExpression(IHtmlImageElement node) : ImageExpressionBase(node)
130136

131137
return img;
132138
}
139+
140+
private static int GetDimension(HtmlAttributeCollection styles, string primaryStyle, string fallbackStyle, int percentageBase)
141+
{
142+
var unit = styles.GetUnit(primaryStyle);
143+
if (!unit.IsValid)
144+
{
145+
unit = styles.GetUnit(fallbackStyle);
146+
}
147+
148+
if (unit.IsValid)
149+
{
150+
return unit.Type == UnitMetric.Percent?
151+
(int)(unit.Value * percentageBase / 100) :
152+
unit.ValueInPx;
153+
}
154+
155+
return 0;
156+
}
133157
}

‎test/HtmlToOpenXml.Tests/ImgTests.cs

+13-3
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ namespace HtmlToOpenXml.Tests
1616
public class ImgTests : HtmlConverterTestBase
1717
{
1818
[TestCase("https://www.w3schools.com/tags/smiley.gif", "image/gif")]
19-
[TestCase("https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Introduction/dino.svg", "image/svg+xml")]
19+
[TestCase("https://upload.wikimedia.org/wikipedia/commons/b/b0/Mozilla_dinosaur_head_logo.svg", "image/svg+xml")]
2020
public async Task AbsoluteUri_ReturnsDrawing_WithDownloadedData(string imageUri, string contentType)
2121
{
2222
await converter.ParseBody(
23-
@$"<img src='{imageUri}' alt='Smiley face' width='42' height='42'>",
23+
@$"<img src='{imageUri}' width='42' height='42'>",
2424
TestContext.CurrentContext.CancellationToken);
2525

2626
var paragraphs = mainPart.Document.Body!.Elements<Paragraph>();
@@ -40,14 +40,24 @@ public void DataUri_ReturnsDrawing_WithDecryptedData()
4040
[Test]
4141
public void WithBorder_ReturnsRunWithBorder()
4242
{
43-
var elements = converter.Parse(@"<img src='https://www.w3schools.com/tags/smiley.gif' border='1'>");
43+
var elements = converter.Parse(@"<img border='1' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='>");
4444
AssertIsImg(mainPart, elements[0]);
4545
var run = elements[0].GetFirstChild<Run>();
4646
var runProperties = run?.GetFirstChild<RunProperties>();
4747
Assert.That(runProperties, Is.Not.Null);
4848
Assert.That(runProperties.Border, Is.Not.Null);
4949
}
5050

51+
[Test]
52+
public void PercentageSize_ReturnsDrawing_WithSizeRelativeToPage()
53+
{
54+
var elements = converter.Parse(@"<img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==' style='max-width:100%'>");
55+
AssertIsImg(mainPart, elements[0]);
56+
var drawing = elements[0].GetFirstChild<Run>()!.GetFirstChild<Drawing>()!;
57+
Assert.That(drawing.Inline?.Extent?.Cx?.Value, Is.EqualTo(6115050));
58+
Assert.That(drawing.Inline?.Extent?.Cy?.Value, Is.EqualTo(6115050));
59+
}
60+
5161
[Test]
5262
public void ManualProvisioning_ReturnsDrawing_WithProvidedData()
5363
{
Loading

0 commit comments

Comments
 (0)
Please sign in to comment.