Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
973adce
Bump actions/stale from 9 to 10
dependabot[bot] Sep 8, 2025
d4c8030
Bump actions/setup-dotnet from 4 to 5
dependabot[bot] Sep 8, 2025
3a6ff57
Merge pull request #153 from Codeuctivity/dependabot/github_actions/a…
stesee Sep 8, 2025
6c12b2b
Merge pull request #152 from Codeuctivity/dependabot/github_actions/a…
stesee Sep 8, 2025
6a520ff
Bump System.Configuration.ConfigurationManager from 9.0.8 to 9.0.9
dependabot[bot] Sep 10, 2025
5149500
Add expected diff on windows (probably msising fonts, got no ms offic…
stesee Sep 20, 2025
ef430bc
Add expected diff known to be found on github actions runners
stesee Sep 20, 2025
6399924
Merge pull request #154 from Codeuctivity/dependabot/nuget/OpenXmlPow…
stesee Sep 20, 2025
561e105
Bump SkiaSharp from 3.119.0 to 3.119.1
dependabot[bot] Sep 24, 2025
c0568b3
Merge pull request #155 from Codeuctivity/dependabot/nuget/OpenXmlPow…
stesee Sep 24, 2025
13bd06b
Bump SkiaSharp.NativeAssets.Linux.NoDependencies from 3.119.0 to 3.119.1
dependabot[bot] Sep 24, 2025
819a420
Merge pull request #156 from Codeuctivity/dependabot/nuget/OpenXmlPow…
stesee Oct 6, 2025
0aaa98c
Bump SkiaSharp.NativeAssets.Linux.NoDependencies from 3.119.0 to 3.119.1
dependabot[bot] Oct 7, 2025
10d328e
Merge pull request #157 from Codeuctivity/dependabot/nuget/OpenXmlPow…
stesee Oct 7, 2025
d406630
Update dependencies and add new test diff images
stesee Oct 10, 2025
73e9069
Replace SixLabors.Fonts with SkiaSharp for font metrics
stesee Oct 10, 2025
a2623a2
Update OpenXML SDK to 3.3.0 and adjust tests
stesee Oct 10, 2025
f8d9fea
Remove pull_request trigger from dotnet workflow
stesee Oct 10, 2025
4e9dc57
Update OpenXmlPowerTools/FontMetric/FontStyle.cs
stesee Oct 10, 2025
57f4709
Update OpenXmlPowerTools/FontMetric/FontStyle.cs
stesee Oct 10, 2025
5fa6d97
added acceptable diff
stesee Oct 10, 2025
d3d211a
Merge pull request #158 from Codeuctivity/HousekeepingDependencies
stesee Oct 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ env:

on:
push:
pull_request:

jobs:
build:
Expand All @@ -16,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
- name: Restore dependencies
Expand All @@ -39,7 +38,7 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
- name: Restore dependencies
Expand Down Expand Up @@ -67,7 +66,7 @@ jobs:
steps:
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: 8.0.x
- name: Restore dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
pull-requests: write

steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Stale issue message'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ internal static async Task AssertImageIsEqual(string actualImagePath, string exp
await File.WriteAllBytesAsync(allowedDiffInfo.NewDiffImageFileName, png.ToArray());
}

// Uncomment following line to add an allowed diff file
// Uncomment following two lines to add an allowed diff file
//var expectedDirectoryPath = Path.GetDirectoryName(expectFullPath);
//File.Copy(allowedDiffInfo.NewDiffImageFileName, Path.Combine(expectedDirectoryPath, allowedDiffInfo.NewDiffImageFileName), true);

Expand Down
10 changes: 5 additions & 5 deletions OpenXmlPowerTools.Tests/OpenXmlPowerTools.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Codeuctivity.HtmlRenderer" Version="4.0.438" />
<PackageReference Include="Codeuctivity.HtmlRenderer" Version="4.0.458" />
<PackageReference Include="Codeuctivity.SkiaSharpCompare" Version="3.0.165-PreRelease" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.0" />
<PackageReference Include="coverlet.collector" Version="6.0.0">
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1" />
<PackageReference Include="coverlet.collector" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.2">
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
10 changes: 6 additions & 4 deletions OpenXmlPowerTools.Tests/PowerToolsBlockExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,20 +97,22 @@ public void MustEndPowerToolsBlockToUseStronglyTypedClasses()
bodyElement.Add(new XElement(W.p, new XElement(W.r, new XElement(W.t, "Added through PowerTools"))));
part.PutXDocument();

// Get the part's content through the SDK. However, we will only see what we
// added through the SDK, not what we added through the PowerTools functionality.
// Get the part's content through the SDK.
// Note: In OpenXML SDK 3.3.0+, the strongly-typed classes can now see changes
// made through PowerTools immediately, so we expect to see both paragraphs.
body = part.Document.Body;
var paragraphs = body.Elements<Paragraph>().ToList();
Assert.Single(paragraphs);
Assert.Equal(2, paragraphs.Count);
Assert.Equal("Added through SDK", paragraphs[0].InnerText);
Assert.Equal("Added through PowerTools", paragraphs[1].InnerText);

// Now, let's end the PowerTools Block, which reloads the root element of this
// one part. Reloading those root elements this way is fine if you know exactly
// which parts had their content changed by the Open XML PowerTools.
wordDocument.EndPowerToolsBlock();

// Get the part's content through the SDK. Having reloaded the root element,
// we should now see both paragraphs.
// we should still see both paragraphs.
body = part.Document.Body;
paragraphs = body.Elements<Paragraph>().ToList();
Assert.Equal(2, paragraphs.Count);
Expand Down
12 changes: 12 additions & 0 deletions OpenXmlPowerTools/FontMetric/FontStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;

namespace Codeuctivity.OpenXmlPowerTools.FontMetric
{
[Flags]
public enum FontStyle
{
Regular = 0,
Bold = 1,
Italic = 2
}
}
10 changes: 5 additions & 5 deletions OpenXmlPowerTools/HtmlToWmlConverterCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@
// then need to make sure that all of the cells below the caption have the border on the appropriate sides so that it looks as if the table
// has a border.

using Codeuctivity.OpenXmlPowerTools.FontMetric;
using DocumentFormat.OpenXml.Packaging;
using SixLabors.Fonts;
using SkiaSharp;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -1293,10 +1293,10 @@ private enum NextExpected
}

// in theory, all unknown fonts are found by the above test, but if not...
FontFamily ff;
SKTypeface ff;
try
{
ff = SystemFonts.Families.Single(font => font.Name == fontName);
ff = SKTypeface.FromFamilyName(fontName);
}
catch (ArgumentException)
{
Expand Down Expand Up @@ -2039,9 +2039,9 @@ private static HashSet<string> KnownFamilies
if (_knownFamilies == null)
{
_knownFamilies = new HashSet<string>();
foreach (var fam in SystemFonts.Families)
foreach (var fam in SKFontManager.Default.FontFamilies)
{
_knownFamilies.Add(fam.Name);
_knownFamilies.Add(fam);
}
}
return _knownFamilies;
Expand Down
40 changes: 25 additions & 15 deletions OpenXmlPowerTools/MetricsGetter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using DocumentFormat.OpenXml.Packaging;
using Codeuctivity.OpenXmlPowerTools.FontMetric;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Validation;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Globalization;
Expand Down Expand Up @@ -106,47 +108,55 @@ public static XElement GetDocxMetrics(WmlDocument wmlDoc, MetricsGetterSettings
return metrics;
}

private static int _getTextWidth(SixLabors.Fonts.FontFamily ff, SixLabors.Fonts.FontStyle fs, decimal sz, string text)
private static int _getTextWidth(SKTypeface typeface, FontStyle fs, decimal sz, string text)
{
try
{
var font = new SixLabors.Fonts.Font(ff, (float)sz / 2f, fs);
var textOptions = new SixLabors.Fonts.TextOptions(font);
var size = SixLabors.Fonts.TextMeasurer.MeasureSize(text, textOptions);

return (int)size.Width;
var skFontStyle = SKFontStyle.Normal;
if (fs.HasFlag(FontStyle.Bold) && fs.HasFlag(FontStyle.Italic))
skFontStyle = new SKFontStyle(SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Italic);
else if (fs.HasFlag(FontStyle.Bold))
skFontStyle = new SKFontStyle(SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright);
else if (fs.HasFlag(FontStyle.Italic))
skFontStyle = new SKFontStyle(SKFontStyleWeight.Normal, SKFontStyleWidth.Normal, SKFontStyleSlant.Italic);

using var font = new SKFont(typeface, (float)sz / 2f);
using var paint = new SKPaint(font);
var bounds = new SKRect();
paint.MeasureText(text, ref bounds);
return (int)bounds.Width;
}
catch
{
return 0;
}
}

public static int GetTextWidth(SixLabors.Fonts.FontFamily ff, SixLabors.Fonts.FontStyle fs, decimal sz, string text)
public static int GetTextWidth(SKTypeface typeface, FontStyle fs, decimal sz, string text)
{
try
{
return _getTextWidth(ff, fs, sz, text);
return _getTextWidth(typeface, fs, sz, text);
}
catch (ArgumentException)
{
try
{
const SixLabors.Fonts.FontStyle fs2 = SixLabors.Fonts.FontStyle.Regular;
return _getTextWidth(ff, fs2, sz, text);
const FontStyle fs2 = FontStyle.Regular;
return _getTextWidth(typeface, fs2, sz, text);
}
catch (ArgumentException)
{
const SixLabors.Fonts.FontStyle fs2 = SixLabors.Fonts.FontStyle.Bold;
const FontStyle fs2 = FontStyle.Bold;
try
{
return _getTextWidth(ff, fs2, sz, text);
return _getTextWidth(typeface, fs2, sz, text);
}
catch (ArgumentException)
{
// if both regular and bold fail, then get metrics for Times New Roman the original FontStyle (in fs)
var ff2 = SixLabors.Fonts.SystemFonts.Families.Single(font => font.Name == "Times New Roman");
return _getTextWidth(ff2, fs, sz, text);
using var timesTypeface = SKTypeface.FromFamilyName("Times New Roman");
return _getTextWidth(timesTypeface ?? typeface, fs, sz, text);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using DocumentFormat.OpenXml.Packaging;
using Codeuctivity.OpenXmlPowerTools.FontMetric;
using DocumentFormat.OpenXml.Packaging;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Globalization;
Expand Down Expand Up @@ -2466,10 +2468,10 @@ private static HashSet<string> KnownFamilies
if (_knownFamilies == null)
{
_knownFamilies = new HashSet<string>();
var families = SixLabors.Fonts.SystemFonts.Families;
var families = SKFontManager.Default.FontFamilies;
foreach (var fam in families)
{
_knownFamilies.Add(fam.Name);
_knownFamilies.Add(fam);
}
}
return _knownFamilies;
Expand Down Expand Up @@ -2505,11 +2507,11 @@ private static int CalcWidthOfRunInTwips(XElement r)
}

// in theory, all unknown fonts are found by the above test, but if not...
SixLabors.Fonts.FontFamily ff;
SKTypeface ff;

try
{
ff = SixLabors.Fonts.SystemFonts.Families.Single(font => font.Name == fontName);
ff = SKTypeface.FromFamilyName(fontName);
}
catch (ArgumentException)
{
Expand All @@ -2518,15 +2520,15 @@ private static int CalcWidthOfRunInTwips(XElement r)
return 0;
}

var fs = SixLabors.Fonts.FontStyle.Regular;
var fs = FontStyle.Regular;
if (GetBoolProp(rPr, W.b) || GetBoolProp(rPr, W.bCs))
{
fs |= SixLabors.Fonts.FontStyle.Bold;
fs |= FontStyle.Bold;
}

if (GetBoolProp(rPr, W.i) || GetBoolProp(rPr, W.iCs))
{
fs |= SixLabors.Fonts.FontStyle.Italic;
fs |= FontStyle.Italic;
}

// Appended blank as a quick fix to accommodate &nbsp; that will get appended to some layout-critical runs such as list item numbers. In some cases, this might not be required or even wrong, so this must be revisited.
Expand Down Expand Up @@ -3618,4 +3620,4 @@ private static bool ConvertTrueFalseValueToBool(string? trueFalseValue)
return returnValue;
}
}
}
}
9 changes: 4 additions & 5 deletions OpenXmlPowerTools/OpenXmlPowerTools.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@
<None Remove="Properties\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DocumentFormat.OpenXml" Version="3.0.2" />
<PackageReference Include="SixLabors.Fonts" Version="1.0.1" />
<PackageReference Include="SkiaSharp" Version="3.119.0" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.0" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.7.0.110445">
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="SkiaSharp" Version="3.119.1" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="10.15.0.120848">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
30 changes: 16 additions & 14 deletions OpenXmlPowerTools/PtOpenXmlUtil.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using DocumentFormat.OpenXml.Packaging;
using Codeuctivity.OpenXmlPowerTools.FontMetric;
using DocumentFormat.OpenXml.Packaging;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -697,10 +699,10 @@ public static int CalcWidthOfRunInTwips(XElement r)
if (KnownFamilies == null)
{
KnownFamilies = new HashSet<string>();
var families = SixLabors.Fonts.SystemFonts.Families;
var families = SKFontManager.Default.FontFamilies;
foreach (var fam in families)
{
KnownFamilies.Add(fam.Name);
KnownFamilies.Add(fam);
}
}

Expand Down Expand Up @@ -750,33 +752,33 @@ public static int CalcWidthOfRunInTwips(XElement r)
return 0;
}
// in theory, all unknown fonts are found by the above test, but if not...
SixLabors.Fonts.FontFamily ff;
SKTypeface ff;
try
{
ff = SixLabors.Fonts.SystemFonts.Families.Single(font => font.Name == fontName);
ff = SKTypeface.FromFamilyName(fontName);
}
catch (ArgumentException)
{
UnknownFonts.Add(fontName);

return 0;
}
var fs = SixLabors.Fonts.FontStyle.Regular;
var fs = FontStyle.Regular;
var bold = GetBoolProp(rPr, W.b) || GetBoolProp(rPr, W.bCs);
var italic = GetBoolProp(rPr, W.i) || GetBoolProp(rPr, W.iCs);
if (bold && !italic)
{
fs = SixLabors.Fonts.FontStyle.Bold;
fs = FontStyle.Bold;
}

if (italic && !bold)
{
fs = SixLabors.Fonts.FontStyle.Italic;
fs = FontStyle.Italic;
}

if (bold && italic)
{
fs = SixLabors.Fonts.FontStyle.Bold | SixLabors.Fonts.FontStyle.Italic;
fs = FontStyle.Bold | FontStyle.Italic;
}

var runText = r.DescendantsTrimmed(W.txbxContent)
Expand Down Expand Up @@ -1178,19 +1180,19 @@ public static XElement CoalesceAdjacentRunsWithIdenticalFormatting(XElement runC
{ W.clrSchemeMapping, 860},
{ W.doNotIncludeSubdocsInStats, 870},
{ W.doNotAutoCompressPictures, 880},
{ W.forceUpgrade, 890},
//{W.captions, 900},
{ W.forceUpgrade, 890},
//{W.captions, 900},
{ W.readModeInkLockDown, 910},
{ W.smartTagType, 920},
//{W.sl:schemaLibrary, 930},
{ W.smartTagType, 920},
//{W.sl:schemaLibrary, 930},
{ W.doNotEmbedSmartTags, 940},
{ W.decimalSymbol, 950},
{ W.listSeparator, 960},
};

#if false
// from the schema in the standard

writeProtection
view
zoom
Expand Down
Loading
Loading