Skip to content

Commit 1c7aec0

Browse files
committed
Add ability to customize page size and margins in Markdown renderers
1 parent af78933 commit 1c7aec0

File tree

15 files changed

+229
-103
lines changed

15 files changed

+229
-103
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
- Added conversion options to `WordprocessingDocument.SaveTo` extension methods
44
- Added ability to append to existing Markdown / plain text when converting DOCX
5+
- Markdown to DOCX / RTF converter: added ability to configure page size and margins
6+
- Improved input/output encodings handling
57
- Code refactor for maintainability and extensibility
68
- Remove .NET 6 target, now out of support
79
- Created GitHub Actions workflow for build, test and NuGet publish
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace DocSharp;
2+
3+
public class PageMargins
4+
{
5+
public double LeftMm { get; set; }
6+
public double TopMm { get; set; }
7+
public double RightMm { get; set; }
8+
public double BottomMm { get; set; }
9+
10+
public PageMargins(double leftMm, double topMm, double rightMm, double bottomMm)
11+
{
12+
LeftMm = leftMm;
13+
TopMm = topMm;
14+
RightMm = rightMm;
15+
BottomMm = bottomMm;
16+
}
17+
18+
public static PageMargins FromMillimeters(double leftMm, double topMm, double rightMm, double bottomMm)
19+
=> new PageMargins(leftMm, topMm, rightMm, bottomMm);
20+
21+
public static PageMargins Uniform(double marginMm) => new PageMargins(marginMm, marginMm, marginMm, marginMm);
22+
23+
public static PageMargins FromInches(double leftInch, double topInch, double rightInch, double bottomInch)
24+
=> FromMillimeters(leftInch * 25.4, topInch * 25.4, rightInch * 25.4, bottomInch * 25.4);
25+
26+
public static PageMargins FromPoints(double leftPoints, double topPoints, double rightPoints, double bottomPoints)
27+
=> FromInches(leftPoints / 72.0, topPoints / 72.0, rightPoints / 72.0, bottomPoints / 72.0);
28+
29+
// Default, Narrow and Large margins as defined in Microsoft Word.
30+
public static PageMargins Default => new PageMargins(20, 25, 20, 20);
31+
public static PageMargins Narrow => Uniform(12.7);
32+
public static PageMargins Large => new PageMargins(50.8, 25.4, 50.8, 25.4);
33+
34+
public long LeftTwips() => UnitMetricHelper.ConvertToTwips(LeftMm, UnitMetric.Millimeter);
35+
public long TopTwips() => UnitMetricHelper.ConvertToTwips(TopMm, UnitMetric.Millimeter);
36+
public long RightTwips() => UnitMetricHelper.ConvertToTwips(RightMm, UnitMetric.Millimeter);
37+
public long BottomTwips() => UnitMetricHelper.ConvertToTwips(BottomMm, UnitMetric.Millimeter);
38+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
using System.Globalization;
2+
3+
namespace DocSharp;
4+
5+
public class PageSize
6+
{
7+
private UnitMetric unit = UnitMetric.Millimeter;
8+
9+
public double WidthMm { get; set; }
10+
public double HeightMm { get; set; }
11+
12+
public PageSize(double widthMm, double heightMm)
13+
{
14+
WidthMm = widthMm;
15+
HeightMm = heightMm;
16+
}
17+
18+
public static PageSize FromMillimeters(double widthMm, double heightMm) => new PageSize(widthMm, heightMm);
19+
20+
public static PageSize FromInches(double widthInch, double heightInch)
21+
=> new PageSize(widthInch * 25.4, heightInch * 25.4);
22+
23+
public static PageSize FromPoints(double widthPoints, double heightPoints)
24+
=> FromInches(widthPoints / 72.0, heightPoints / 72.0);
25+
26+
public static PageSize Default => RegionInfo.CurrentRegion.IsMetric ? A4 : Letter;
27+
28+
// Standard sizes (portrait)
29+
public static PageSize A3 => new PageSize(297, 420);
30+
public static PageSize A4 => new PageSize(210, 297);
31+
public static PageSize A5 => new PageSize(148, 210);
32+
public static PageSize Letter => PageSize.FromInches(8.5, 11);
33+
public static PageSize Legal => PageSize.FromInches(8.5, 14);
34+
35+
// Standard sizes (landscape)
36+
public static PageSize A3_Landscape => new PageSize(420, 297);
37+
public static PageSize A4_Landscape => new PageSize(297, 210);
38+
public static PageSize A5_Landscape => new PageSize(210, 148);
39+
public static PageSize Letter_Landscape => PageSize.FromInches(11, 8.5);
40+
public static PageSize Legal_Landscape => PageSize.FromInches(14, 8.5);
41+
42+
public long WidthTwips() => UnitMetricHelper.ConvertToTwips(WidthMm, UnitMetric.Millimeter);
43+
public long HeightTwips() => UnitMetricHelper.ConvertToTwips(HeightMm, UnitMetric.Millimeter);
44+
45+
public void SwapDimensions()
46+
{
47+
double temp = WidthMm;
48+
WidthMm = HeightMm;
49+
HeightMm = temp;
50+
}
51+
52+
public void SetPortrait()
53+
{
54+
if (WidthMm > HeightMm)
55+
SwapDimensions();
56+
}
57+
58+
public void SetLandscape()
59+
{
60+
if (HeightMm > WidthMm)
61+
SwapDimensions();
62+
}
63+
}

src/DocSharp.Docx/Helpers/DocumentSettingsHelpers.cs

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

src/DocSharp.Epub/EpubToDocxConverter.cs

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
using System.Threading.Tasks;
99
using System.Xml.Linq;
1010
using DocSharp.Helpers;
11+
using DocSharp;
1112
using DocumentFormat.OpenXml;
1213
using DocumentFormat.OpenXml.Packaging;
1314
using DocumentFormat.OpenXml.Wordprocessing;
15+
using W = DocumentFormat.OpenXml.Wordprocessing;
1416
using EpubCore;
1517
using HtmlToOpenXml;
1618

@@ -49,34 +51,14 @@ internal class EpubToDocxConverter : IBinaryToDocxConverter
4951
public bool PreserveCssStyles { get; set; } = true;
5052

5153
/// <summary>
52-
/// The page width in millimeters. If not set, the default page size is A4 (210 x 297 mm) for regions using metric units and Letter (8.5 x 11 inches) for regions using imperial units.
54+
/// Page size for the output DOCX document.
5355
/// </summary>
54-
public int PageWidth { get; set; } = -1;
56+
public PageSize PageSize { get; set; } = PageSize.Default;
5557

5658
/// <summary>
57-
/// The page height in millimeters. If not set, the default page size is A4 (210 x 297 mm) for regions using metric units and Letter (8.5 x 11 inches) for regions using imperial units.
59+
/// Page margins for the output DOCX document.
5860
/// </summary>
59-
public int PageHeight { get; set; } = -1;
60-
61-
/// <summary>
62-
/// The page top margin in millimeters. If not set, the default page margins are top = 25 mm, left/right/bottom = 20 mm
63-
/// </summary>
64-
public int PageLeftMargin { get; set; } = -1;
65-
66-
/// <summary>
67-
/// The page top margin in millimeters. If not set, the default page margins are top = 25 mm, left/right/bottom = 20 mm
68-
/// </summary>
69-
public int PageTopMargin { get; set; } = -1;
70-
71-
/// <summary>
72-
/// The page right margin in millimeters. If not set, the default page margins are top = 25 mm, left/right/bottom = 20 mm
73-
/// </summary>
74-
public int PageRightMargin { get; set; } = -1;
75-
76-
/// <summary>
77-
/// The page bottom margin in millimeters. If not set, the default page margins are top = 25 mm, left/right/bottom = 20 mm
78-
/// </summary>
79-
public int PageBottomMargin { get; set; } = -1;
61+
public PageMargins PageMargins { get; set; } = PageMargins.Default;
8062

8163
public async Task BuildDocxAsync(Stream input, WordprocessingDocument targetDocument)
8264
{
@@ -187,20 +169,20 @@ public async Task BuildDocxAsync(Stream input, WordprocessingDocument targetDocu
187169

188170
// Add default section properties
189171
body.AppendChild(new SectionProperties(
190-
new PageSize()
191-
{
192-
Width = (uint)(PageWidth > 0 ? UnitMetricHelper.ConvertToTwips(PageWidth, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageWidth()),
193-
Height = (uint)(PageHeight > 0 ? UnitMetricHelper.ConvertToTwips(PageHeight, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageHeight()),
172+
new W.PageSize()
173+
{
174+
Width = (uint)((PageSize ?? PageSize.Default).WidthTwips()),
175+
Height = (uint)((PageSize ?? PageSize.Default).HeightTwips()),
194176
},
195177
new PageMargin()
196178
{
197179
// Notes:
198180
// - PageMargin uses uint for Left and Right margins, and int for top and bottom (enforced by Open XML SDK)
199181
// - 0 is allowed for margins but not recommended
200-
Left = (uint)(PageLeftMargin >= 0 ? UnitMetricHelper.ConvertToTwips(PageLeftMargin, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageLeftMargin()),
201-
Right = (uint)(PageRightMargin >= 0 ? UnitMetricHelper.ConvertToTwips(PageRightMargin, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageRightMargin()),
202-
Top = (int)(PageTopMargin >= 0 ? UnitMetricHelper.ConvertToTwips(PageTopMargin, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageTopMargin()),
203-
Bottom = (int)(PageBottomMargin >= 0 ? UnitMetricHelper.ConvertToTwips(PageBottomMargin, UnitMetric.Millimeter) : DocumentSettingsHelpers.GetDefaultPageBottomMargin()),
182+
Left = (uint)((PageMargins ?? PageMargins.Default)).LeftTwips(),
183+
Right = (uint)((PageMargins ?? PageMargins.Default)).RightTwips(),
184+
Top = (int)((PageMargins ?? PageMargins.Default)).TopTwips(),
185+
Bottom = (int)((PageMargins ?? PageMargins.Default)).BottomTwips(),
204186
}));
205187

206188
if (targetDocument.CanSave)

src/DocSharp.Markdown/MarkdownUtils.cs renamed to src/DocSharp.Markdown/Common/BookmarkHelpers.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
using System.Text;
55
using System.Threading.Tasks;
66

7-
namespace DocSharp.Markdown;
7+
namespace DocSharp.Markdown.Common;
88

9-
internal static class MarkdownUtils
9+
internal static class BookmarkHelpers
1010
{
1111
internal static string GetBookmarkName(string text)
1212
{

src/DocSharp.Markdown/Common/ImageHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
namespace DocSharp.Markdown.Common;
1616

17-
public static class ImageHelpers
17+
internal static class ImageHelpers
1818
{
1919
public static void GetImageAttributes(LinkInline obj, out long width, out long height)
2020
{

src/DocSharp.Markdown/MarkdownElementExtensions.cs renamed to src/DocSharp.Markdown/Common/MarkdownElementExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
using System.Threading.Tasks;
66
using Markdig.Syntax;
77

8-
namespace DocSharp.Markdown;
8+
namespace DocSharp.Markdown.Common;
99

1010
public static class MarkdownElementExtensions
1111
{

src/DocSharp.Markdown/Common/UriHelpers.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@
1212
using DocSharp.Helpers;
1313
#endif
1414

15-
public static class UriHelpers
15+
namespace DocSharp.Markdown.Common;
16+
17+
internal static class UriHelpers
1618
{
1719
public static Uri? NormalizeImageUri(string url, string? imagesBaseUri)
1820
{

src/DocSharp.Markdown/Docx/Blocks/HeadingRenderer.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
using Markdig.Syntax;
66
using Markdig.Syntax.Inlines;
77
using DocSharp.Markdown;
8+
using DocSharp.Markdown.Common;
89
using DocSharp.Collections;
10+
using DocSharp.Docx;
11+
using BookmarkHelpers = DocSharp.Markdown.Common.BookmarkHelpers;
912

1013
namespace Markdig.Renderers.Docx.Blocks;
1114

@@ -19,7 +22,7 @@ protected override void WriteObject(DocxDocumentRenderer renderer, HeadingBlock
1922
string? bookmarkName = null;
2023
if (obj.Inline?.FindDescendants<LiteralInline>().FirstOrDefault() is LiteralInline literal)
2124
{
22-
bookmarkName = MarkdownUtils.GetBookmarkName(literal.Content.ToString());
25+
bookmarkName = BookmarkHelpers.GetBookmarkName(literal.Content.ToString());
2326
}
2427

2528
WriteAsParagraph(renderer, obj, styleId, bookmarkName);

0 commit comments

Comments
 (0)