Skip to content

Commit 4e71c53

Browse files
committed
Add partial support for paragraph formatting in DOCX renderer
1 parent 271de63 commit 4e71c53

File tree

15 files changed

+709
-191
lines changed

15 files changed

+709
-191
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace DocSharp.Helpers;
2+
3+
public static class MathHelpers
4+
{
5+
public static float? Negate(float? val)
6+
{
7+
if (val == null)
8+
return null;
9+
else
10+
return -val.Value;
11+
}
12+
}

src/DocSharp.Docx/DocxToHtml/DocxToHtmlConverter.Run.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -233,19 +233,10 @@ internal override void ProcessRun(Run run, HtmlTextWriter sb)
233233
}
234234

235235
// Highlight and shading (highlight has priority over shading)
236-
var highlight = OpenXmlHelpers.GetEffectiveProperty<Highlight>(run);
237-
if (highlight?.Val != null && highlight.Val != HighlightColorValues.None)
236+
string? hex = run.GetEffectiveBackgroundColor();
237+
if (!string.IsNullOrWhiteSpace(hex))
238238
{
239-
string? hex = RtfHighlightMapper.GetHexColor(highlight.Val);
240-
if (!string.IsNullOrEmpty(hex))
241-
{
242-
styles.Add($"background-color: #{hex};");
243-
}
244-
}
245-
else if (OpenXmlHelpers.GetEffectiveProperty<Shading>(run) is Shading shading &&
246-
ColorHelpers.EnsureHexColor(shading.Fill?.Value) is string fill)
247-
{
248-
styles.Add($"background-color: #{fill};");
239+
styles.Add($"background-color: #{hex};");
249240
}
250241

251242
if (border?.Val != null)

src/DocSharp.Docx/DocxToRtf/DocxToRtfConverter.Run.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ internal void ProcessRunFormatting(OpenXmlElement? run, RtfStringWriter sb)
218218
}
219219
else
220220
{
221-
string? hex = RtfHighlightMapper.GetHexColor(highlight.Val);
222-
if (!string.IsNullOrEmpty(hex))
221+
string? hex = highlight.ToHexColor();
222+
if (!string.IsNullOrWhiteSpace(hex))
223223
{
224224
colors.TryAddAndGetIndex(hex!, out int highlightIndex);
225225
sb.WriteWordWithValue("highlight", highlightIndex);

src/DocSharp.Docx/DocxToRtf/RtfHighlightMapper.cs

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/DocSharp.Docx/Helpers/ColorHelpers.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,113 @@
88
using DocumentFormat.OpenXml.Office2010.Word;
99
using DocumentFormat.OpenXml.Packaging;
1010
using A = DocumentFormat.OpenXml.Drawing;
11+
using W = DocumentFormat.OpenXml.Wordprocessing;
12+
using W14 = DocumentFormat.OpenXml.Office2010.Word;
1113

1214
namespace DocSharp.Docx;
1315

1416
public static class ColorHelpers
1517
{
18+
public static string? ToHexColor(this W.Highlight? highlight)
19+
{
20+
if (highlight == null || highlight.Val == null || highlight.Val.Value == W.HighlightColorValues.None)
21+
return null;
22+
else if (highlight.Val == W.HighlightColorValues.Black)
23+
return "000000";
24+
else if (highlight.Val == W.HighlightColorValues.White)
25+
return "FFFFFF";
26+
else if (highlight.Val == W.HighlightColorValues.Red)
27+
return "FF0000";
28+
else if (highlight.Val == W.HighlightColorValues.Green)
29+
return "00FF00";
30+
else if (highlight.Val == W.HighlightColorValues.Blue)
31+
return "0000FF";
32+
else if (highlight.Val == W.HighlightColorValues.Yellow)
33+
return "FFFF00";
34+
else if (highlight.Val == W.HighlightColorValues.Cyan)
35+
return "00FFFF";
36+
else if (highlight.Val == W.HighlightColorValues.Magenta)
37+
return "FF00FF";
38+
else if (highlight.Val == W.HighlightColorValues.DarkRed)
39+
return "800000";
40+
else if (highlight.Val == W.HighlightColorValues.DarkGreen)
41+
return "008000";
42+
else if (highlight.Val == W.HighlightColorValues.DarkBlue)
43+
return "000080";
44+
else if (highlight.Val == W.HighlightColorValues.DarkYellow)
45+
return "808000";
46+
else if (highlight.Val == W.HighlightColorValues.DarkMagenta)
47+
return "800080";
48+
else if (highlight.Val == W.HighlightColorValues.DarkCyan)
49+
return "008080";
50+
else if (highlight.Val == W.HighlightColorValues.DarkGray)
51+
return "808080";
52+
else if (highlight.Val == W.HighlightColorValues.LightGray)
53+
return "C0C0C0";
54+
else
55+
return null;
56+
}
57+
58+
public static string? ToHexColor(this W.Shading? shading)
59+
{
60+
if (shading == null || (shading.Val != null && shading.Val.Value == W.ShadingPatternValues.Nil))
61+
return null;
62+
63+
// Patterns in Open XML work in this way:
64+
// - The pure primary color (Fill) is displayed for ShadingPatternValues.Clear
65+
// or if no pattern (Shading.Val) is specified.
66+
// - The pure secondary color (Color) is displayed for ShadingPatternValues.Solid.
67+
// - Other values are displayed as a combination of the two (stripes, checkerboard, ...)
68+
// This functions returns the primary color (Fill) in all cases,
69+
// except Solid (for which the secondary color is returned) and Nil (for which null is returned).
70+
// If a converter supports pattern types (for example DOCX --> RTF),
71+
// it should map them properly rather than using this method.
72+
73+
if (shading.Val != null && shading.Val.Value == W.ShadingPatternValues.Solid)
74+
{
75+
return EnsureHexColor(shading.Color?.Value); // try to get secondary color as hex string
76+
}
77+
else
78+
{
79+
return EnsureHexColor(shading.Fill?.Value); // try to get primary color as hex string
80+
}
81+
}
82+
83+
public static string? ToHexColor(this W14.FillTextEffect? fillEffect)
84+
{
85+
if (fillEffect == null)
86+
return null;
87+
88+
string? fillColor = null;
89+
if (fillEffect.Elements<W14.SolidColorFillProperties>().FirstOrDefault() is W14.SolidColorFillProperties solidFill)
90+
{
91+
fillColor = ColorHelpers.GetColor(solidFill);
92+
if (string.IsNullOrWhiteSpace(fillColor))
93+
fillColor = null;
94+
}
95+
else if (fillEffect.Elements<W14.GradientFillProperties>().FirstOrDefault() is W14.GradientFillProperties gradientFill &&
96+
gradientFill.GradientStopList?.Elements<W14.GradientStop>().FirstOrDefault() is W14.GradientStop firstGradientStop)
97+
{
98+
// Extract the first color from the gradient
99+
fillColor = ColorHelpers.GetColor(firstGradientStop);
100+
if (string.IsNullOrWhiteSpace(fillColor))
101+
fillColor = null;
102+
}
103+
else if (fillEffect.Elements<W14.NoFillEmpty>().FirstOrDefault() is W14.NoFillEmpty)
104+
{
105+
fillColor = null;
106+
}
107+
return EnsureHexColor(fillColor);
108+
}
109+
110+
public static string? ToHexColor(this W.Color? color)
111+
{
112+
if (color == null || color.Val == null || !color.Val.HasValue)
113+
return null;
114+
else
115+
return EnsureHexColor(color.Val.Value);
116+
}
117+
16118
public static string ToHexString(this System.Drawing.Color color)
17119
{
18120
return $"#{color.R:X2}{color.G:X2}{color.B:X2}";

src/DocSharp.Docx/Helpers/OpenXmlDataTypeHelpers.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ public static class OpenXmlDataTypeHelpers
3333
}
3434
}
3535

36+
public static float? ToFloat(this StringValue? stringValue)
37+
{
38+
if (stringValue?.Value != null &&
39+
float.TryParse(stringValue.Value, NumberStyles.Number, CultureInfo.InvariantCulture, out float val))
40+
{
41+
return val;
42+
}
43+
else
44+
{
45+
return null;
46+
}
47+
}
48+
3649
public static decimal? ToDecimal(this StringValue? stringValue)
3750
{
3851
if (stringValue?.Value != null &&

0 commit comments

Comments
 (0)