From 5d183f3e06b217801ed9faa38ff1b53efa435691 Mon Sep 17 00:00:00 2001 From: Bryan Jones Date: Sun, 2 Aug 2026 09:05:20 -0700 Subject: [PATCH 1/2] Page Size and Margins Add support for customizing document page size and margins --- Sources/SwiftDocX/Document/Document.swift | 4 ++ .../SwiftDocX/Document/DocumentWriter.swift | 13 +++-- Sources/SwiftDocX/Model/PageAttributes.swift | 56 +++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 Sources/SwiftDocX/Model/PageAttributes.swift diff --git a/Sources/SwiftDocX/Document/Document.swift b/Sources/SwiftDocX/Document/Document.swift index dd68095..b6c9fc6 100644 --- a/Sources/SwiftDocX/Document/Document.swift +++ b/Sources/SwiftDocX/Document/Document.swift @@ -72,6 +72,9 @@ public class Document { /// Document properties (metadata and accessibility) public var properties: DocumentProperties + /// Page size and margins + public var pageAttributes: PageAttributes + /// Document header (appears at top of pages) public var header: Header? @@ -84,6 +87,7 @@ public class Document { self.tables = [] self.elements = [] self.properties = DocumentProperties() + self.pageAttributes = PageAttributes() self.header = nil self.footer = nil } diff --git a/Sources/SwiftDocX/Document/DocumentWriter.swift b/Sources/SwiftDocX/Document/DocumentWriter.swift index 34520b8..87c3be7 100644 --- a/Sources/SwiftDocX/Document/DocumentWriter.swift +++ b/Sources/SwiftDocX/Document/DocumentWriter.swift @@ -126,7 +126,7 @@ public class DocumentWriter { // Build document XML with header/footer references let documentXML = buildDocumentXMLWithHeaderFooter( - elements: document.elements, + document: document, headerRelId: headerRelId, footerRelId: footerRelId ) @@ -210,7 +210,7 @@ public class DocumentWriter { // MARK: - Private Helpers private func buildDocumentXMLWithHeaderFooter( - elements: [DocumentElement], + document: Document, headerRelId: String?, footerRelId: String? ) -> String { @@ -220,7 +220,7 @@ public class DocumentWriter { """ - for element in elements { + for element in document.elements { switch element { case .paragraph(let paragraph): xml += buildParagraphXML(paragraph) @@ -237,8 +237,11 @@ public class DocumentWriter { if let footerRelId = footerRelId { xml += "" } - xml += "" - xml += "" + + // Page size and margins + let margins = document.pageAttributes.margins + xml += "" + xml += "" xml += "" xml += """ diff --git a/Sources/SwiftDocX/Model/PageAttributes.swift b/Sources/SwiftDocX/Model/PageAttributes.swift new file mode 100644 index 0000000..963a574 --- /dev/null +++ b/Sources/SwiftDocX/Model/PageAttributes.swift @@ -0,0 +1,56 @@ +import Foundation + + +/// Represents attributes of a page, including paper size and margins. +public struct PageAttributes: Equatable, Sendable { + /// The page width, in points. (72 pts per inch). Defaults to 8.5" (612 pts). + public var width: Double = 612.0 + + /// The page height, in points (72 pts per inch). Defaults to 11" (792 pts). + public var height: Double = 792.0 + + /// The margins of the page, including margins for the page header/footer. + public var margins: PageMargins + + /// Initializes a `PageAttributes` with the default 8.5 x 11" page size, 1" margins, and 0.5" margins for the header/footer. + public init(width: Double = 612.0, height: Double = 792.0, margins: PageMargins = .init()) { + self.width = width + self.height = height + self.margins = margins + } +} + + +/// Represents the margins of a page. +public struct PageMargins: Equatable, Sendable { + /// The page's top margin, in points (1 inch = 72 points). Defaults to 72. + public var top: Double = 72.0 + + /// The page's bottom margin, in points (1 inch = 72 points). Defaults to 72. + public var bottom: Double = 72.0 + + /// The page's left margin, in points (1 inch = 72 points). Defaults to 72. + public var left: Double = 72.0 + + /// The page's right margin, in points (1 inch = 72 points). Defaults to 72. + public var right: Double = 72.0 + + /// The margin for the page header, in points (1 inch = 72 points). Defaults to 36. + public var header: Double = 36.0 + + /// The margin for the page footer, in points (1 inch = 72 points). Defaults to 36. + public var footer: Double = 36.0 + + /// Initializes a `PageMargins`. By default, all edges are 1" margins (72 points) and the page header and footer have 0.5" margins (36 points). + public init(top: Double = 72.0, bottom: Double = 72.0, left: Double = 72.0, right: Double = 72.0, header: Double = 36.0, footer: Double = 36.0) + { + self.top = top + self.bottom = bottom + self.left = left + self.right = right + self.header = header + self.footer = footer + } +} + + From 5f5b3c7cae85fe103121904bae3fd57a2ea0e745 Mon Sep 17 00:00:00 2001 From: Bryan Jones Date: Mon, 3 Aug 2026 15:04:12 -0700 Subject: [PATCH 2/2] Table and Cell Margins Support specifying margins for all and/or specific cells in a table. --- .../SwiftDocX/Document/DocumentWriter.swift | 2 +- Sources/SwiftDocX/Model/PageAttributes.swift | 46 +++++++++---------- Sources/SwiftDocX/Model/Table.swift | 8 ++++ .../SwiftDocX/XML/DocumentXMLBuilder.swift | 19 ++++++++ 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/Sources/SwiftDocX/Document/DocumentWriter.swift b/Sources/SwiftDocX/Document/DocumentWriter.swift index 87c3be7..1f27ad7 100644 --- a/Sources/SwiftDocX/Document/DocumentWriter.swift +++ b/Sources/SwiftDocX/Document/DocumentWriter.swift @@ -241,7 +241,7 @@ public class DocumentWriter { // Page size and margins let margins = document.pageAttributes.margins xml += "" - xml += "" + xml += "" xml += "" xml += """ diff --git a/Sources/SwiftDocX/Model/PageAttributes.swift b/Sources/SwiftDocX/Model/PageAttributes.swift index 963a574..edbd52d 100644 --- a/Sources/SwiftDocX/Model/PageAttributes.swift +++ b/Sources/SwiftDocX/Model/PageAttributes.swift @@ -9,47 +9,47 @@ public struct PageAttributes: Equatable, Sendable { /// The page height, in points (72 pts per inch). Defaults to 11" (792 pts). public var height: Double = 792.0 - /// The margins of the page, including margins for the page header/footer. - public var margins: PageMargins + /// The margins of the page (top, bottom, left, right). + public var margins: Margins + + /// The margin for the page header, in points (1 inch = 72 points). Defaults to 36. + public var headerMargin: Double = 36.0 + + /// The margin for the page footer, in points (1 inch = 72 points). Defaults to 36. + public var footerMargin: Double = 36.0 /// Initializes a `PageAttributes` with the default 8.5 x 11" page size, 1" margins, and 0.5" margins for the header/footer. - public init(width: Double = 612.0, height: Double = 792.0, margins: PageMargins = .init()) { + public init(width: Double = 612.0, height: Double = 792.0, margins: Margins = .init(top: 72.0, bottom: 72.0, left: 72.0, right: 72.0), headerMargin: Double = 36.0, footerMargin: Double = 36.0) { self.width = width self.height = height self.margins = margins + self.headerMargin = headerMargin + self.footerMargin = footerMargin } } -/// Represents the margins of a page. -public struct PageMargins: Equatable, Sendable { - /// The page's top margin, in points (1 inch = 72 points). Defaults to 72. - public var top: Double = 72.0 +/// Represents the margins of an element such as a page or table cell. +public struct Margins: Equatable, Sendable { + /// The element's top margin, in points (1 inch = 72 points). Defaults to 0. + public var top: Double - /// The page's bottom margin, in points (1 inch = 72 points). Defaults to 72. - public var bottom: Double = 72.0 + /// The element's bottom margin, in points (1 inch = 72 points). Defaults to 0. + public var bottom: Double - /// The page's left margin, in points (1 inch = 72 points). Defaults to 72. - public var left: Double = 72.0 + /// The element's left margin, in points (1 inch = 72 points). Defaults to 0. + public var left: Double - /// The page's right margin, in points (1 inch = 72 points). Defaults to 72. - public var right: Double = 72.0 - - /// The margin for the page header, in points (1 inch = 72 points). Defaults to 36. - public var header: Double = 36.0 - - /// The margin for the page footer, in points (1 inch = 72 points). Defaults to 36. - public var footer: Double = 36.0 + /// The element's right margin, in points (1 inch = 72 points). Defaults to 0. + public var right: Double - /// Initializes a `PageMargins`. By default, all edges are 1" margins (72 points) and the page header and footer have 0.5" margins (36 points). - public init(top: Double = 72.0, bottom: Double = 72.0, left: Double = 72.0, right: Double = 72.0, header: Double = 36.0, footer: Double = 36.0) + /// Initializes a `Margins`. By default, all edges are set to 0 points. + public init(top: Double = 0, bottom: Double = 0, left: Double = 0, right: Double = 0) { self.top = top self.bottom = bottom self.left = left self.right = right - self.header = header - self.footer = footer } } diff --git a/Sources/SwiftDocX/Model/Table.swift b/Sources/SwiftDocX/Model/Table.swift index 371e4a2..17c2892 100644 --- a/Sources/SwiftDocX/Model/Table.swift +++ b/Sources/SwiftDocX/Model/Table.swift @@ -81,6 +81,9 @@ public class TableCell { /// Cell width in points (nil for auto) public var width: Double? + /// The inset from the cell edges to the content of the cell. This value overrides the value of `Table.cellMargins` if both are set. + public var margins: Margins? + /// Background/shading color public var backgroundColor: Color? @@ -99,6 +102,7 @@ public class TableCell { public init() { self.paragraphs = [] self.width = nil + self.margins = nil self.backgroundColor = nil self.verticalAlignment = nil self.columnSpan = 1 @@ -178,6 +182,9 @@ public class Table { /// Table width in points (nil for auto) public var width: Double? + /// The margins (insets) to use for each cell in this `Table`. Can be overriden for a particular cell by setting `TableCell.margins`. + public var cellMargins: Margins? + /// Table alignment public var alignment: ParagraphAlignment? @@ -192,6 +199,7 @@ public class Table { self.borders = .single self.columnWidths = [] self.width = nil + self.cellMargins = nil self.alignment = nil self.accessibilityCaption = nil self.accessibilitySummary = nil diff --git a/Sources/SwiftDocX/XML/DocumentXMLBuilder.swift b/Sources/SwiftDocX/XML/DocumentXMLBuilder.swift index 42e11ca..c0995da 100644 --- a/Sources/SwiftDocX/XML/DocumentXMLBuilder.swift +++ b/Sources/SwiftDocX/XML/DocumentXMLBuilder.swift @@ -300,6 +300,16 @@ public class DocumentXMLBuilder { xml += "" } + // Table cell margins + if let margins = table.cellMargins { + xml += "" + xml += "" + xml += "" + xml += "" + xml += "" + xml += "" + } + // Accessibility: Caption (visible title) and Description (for screen readers) if let caption = table.accessibilityCaption { xml += "" @@ -413,6 +423,15 @@ public class DocumentXMLBuilder { xml += "" } + if let margins = cell.margins { + xml += "" + xml += "" + xml += "" + xml += "" + xml += "" + xml += "" + } + if cell.columnSpan > 1 { xml += "" }