Skip to content

Commit 4447ffd

Browse files
author
Philip Niedertscheider
authored
Merge pull request #212 from techprimate/release/2.1.0
Release/2.1.0
2 parents 848d33a + 81a7721 commit 4447ffd

13 files changed

+166
-123
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ env:
99
- PROJECT="Example.xcodeproj"
1010
- EXAMPLE_SCHEME="Example"
1111

12+
- secure: y71ScxtfYr3/DI0XKjGz8Bmia33QF9vO5euPJJbQ6kD5ADhEFkici/YZWxDkYtEZocKaUHIR4KYrKya2kTwJC630s2wLg974gERcUATZkWxeJdKgpfZ2aZtqYNPPDxozMTFtiT4kaw5HiD0usJUgnWKqf/XsTW+3BpTJA58xqXChcXulibs9FJvPz6ZVxW+dNW3F5xtC3GCOWk3Rofrw8GJXdCfie/CaJUvxaQVm9hOwKn0Akpe6rvFKlMtfYOLL9yclaMAM+Um7uFVZwhCPHtAzXvpOhA2U/n7eXy/fNpoXxi9zf+epD1iiFmxJQfc1ZO6jkUJEksLXdO3pEMnoe205Bm70QMO6l9gyuq6Z2cUcCBrd2wDzfLYBoOqapgachpTQifotXX6rapm5pCDhg0pMCRihH5moFnsE7jqz2Lo4n68cvSa9+Irr97HmvH+GdF++VIVGK4/GJOErwGUx0Nh32BIeV3p4D+MNm918mAEO7a66a1RiTKNAr1xnrAtCl0k4XeZPCp0uQQ0TEVOxi/vecIS3k6mNMJw5W9tE0F7fun8kHdv6EKrzKIBkyDxMsh2Z5zVqE3wRcCuD+7FgrcmYDUXyk+t1o2cMNs7iZkKFQAG69+qXviTXnaD9Mq0LGP1sx+OQpQKzde9CAC+tgj+1fqD41jqr6zHJqaEOxvs=
1213
stages:
1314
- Tests
1415
- Examples

CHANGELOG.md

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Change Log
22

33
## [Unreleased](https://github.com/techprimate/TPPDF/tree/HEAD) (2020-??-??)
4-
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.0.0...HEAD)
4+
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.1.0...HEAD)
55

66
**Implemented enhancements:**
77

@@ -11,6 +11,35 @@
1111

1212
**Merged pull requests:**
1313

14+
## [2.1.0](https://github.com/techprimate/TPPDF/tree/HEAD) (2020-06-15)
15+
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.0.1...2.1.0)
16+
17+
**Implemented enhancements:**
18+
19+
- Added raw representable values to `PDFPageFormat`
20+
- Added raw representable type to `PDFLineType`
21+
- Added constant `none` to `PDFTableCellStyle` and `PDFTableCellBorders`
22+
- Added background color to `PDFSectionColumn` (Issue #122)
23+
24+
**Fixed bugs:**
25+
26+
- Added note to documentation about not reusing `PDFSection` instances (Issue #122)
27+
- Added missing font and text color reset to generator
28+
29+
**Closed issues:**
30+
31+
- #73
32+
- #122
33+
- #204
34+
- #197
35+
- #189
36+
- #186
37+
- #184
38+
- #183
39+
40+
**Merged pull requests:**
41+
42+
- #211
1443

1544
## [2.0.1](https://github.com/techprimate/TPPDF/tree/2.0.1) (2020-05-31)
1645
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.0.0...2.0.1)

Documentation/Usage.md

+2
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,8 @@ section.columns[2].addText(.center, text: "center")
497497
document.add(sectiion: section)
498498
```
499499

500+
**Attention:** Do not add a `PDFSection` multiple times, as they hold some internal state, which will lead to collisions and unpredictable framing calculations
501+
500502
#### Column Wrap Sections
501503

502504
A column wrap section allows you to split your page into multiple columns and fill it up starting at the left. All you have to do is enable it, add content, and then disable it. When disabling it you can set the flag `addPageBreak` if you want it to continue on a fresh page (defaults to true).

Shared/Examples/MultiSectionExampleFactory.swift

+6-1
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,24 @@ class MultiSectionExampleFactory: ExampleFactory {
1515
let document = PDFDocument(format: .a4)
1616

1717
// Add multi column section
18-
let section = PDFSection(columnWidths: [0.33, 0.34, 0.33])
18+
let section = PDFSection(columnWidths: [0.30, 0.40, 0.30])
19+
section.columns[0].backgroundColor = UIColor.red
1920
section.columns[0].add(.left, text: "left")
2021
section.columns[0].add(.center, text: "center")
2122
section.columns[0].add(.right, text: "right")
2223
section.columns[0].add(text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.")
2324
section.columns[0].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))
2425
section.columns[0].add(text: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
26+
27+
section.columns[1].backgroundColor = UIColor.orange
2528
section.columns[1].add(.left, text: "left")
2629
section.columns[1].add(.center, text: "center")
2730
section.columns[1].add(.right, text: "right")
2831
section.columns[1].add(text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
2932
section.columns[1].add(.center, text: "center")
3033
section.columns[1].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))
34+
35+
section.columns[2].backgroundColor = UIColor.yellow
3136
section.columns[2].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))
3237
section.columns[2].add(text: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
3338
section.columns[2].add(.left, text: "left")

Source/API/Graphics/PDFLineType.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,26 @@
1212
- dashed: Line consists out of short dashes
1313
- dotted: Lines consists out of dots
1414
*/
15-
public enum PDFLineType {
15+
public enum PDFLineType: String {
1616

1717
/**
1818
No visible line
1919
*/
20-
case none
20+
case none = "none"
2121

2222
/**
2323
Full line
2424
*/
25-
case full
25+
case full = "full"
2626

2727
/**
2828
Line is dashed, dash length and spacing is three times the line width
2929
*/
30-
case dashed
30+
case dashed = "dashed"
3131

3232
/**
3333
Line is dotted. Dot spacing is twice the line width
3434
*/
35-
case dotted
35+
case dotted = "dotted"
3636

3737
}

Source/API/PDFGenerator.swift

+6
Original file line numberDiff line numberDiff line change
@@ -102,5 +102,11 @@ public class PDFGenerator: PDFGeneratorProtocol, CustomStringConvertible {
102102
layout.reset()
103103
columnState.reset()
104104
currentPage = 1
105+
fonts = fonts.mapValues { _ in
106+
UIFont.systemFont(ofSize: UIFont.systemFontSize)
107+
}
108+
textColor = textColor.mapValues { _ in
109+
UIColor.black
110+
}
105111
}
106112
}

Source/API/Page Format/PDFPageFormat.swift

+44-6
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,73 @@ import UIKit
1111
* Source for page sizes: https://www.papersizes.org
1212
* All sizes are calculated using 72 points/inch
1313
*/
14-
public enum PDFPageFormat {
14+
public enum PDFPageFormat: String {
1515

1616
/**
1717
Page formats mostly used in the USA
1818
*/
19-
case usHalfLetter, usLetter, usLegal, usJuniorLegal, usLedger
19+
case usHalfLetter = "us.half-letter",
20+
usLetter = "us.letter",
21+
usLegal = "us.legal",
22+
usJuniorLegal = "us.junior-legal",
23+
usLedger = "us.ledger"
2024

2125
/**
2226
Page formats according to the American National Standards Institute
2327
*/
24-
case ansiA, ansiB, ansiC, ansiD, ansiE
28+
case ansiA = "ansi.a",
29+
ansiB = "ansi.b",
30+
ansiC = "ansi.c",
31+
ansiD = "ansi.d",
32+
ansiE = "ansi.e"
2533

2634
/**
2735
A-Series of paper standard DIN 476
2836
For more detail: https://en.wikipedia.org/wiki/Paper_size#A_series
2937
*/
30-
case a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10
38+
case a0 = "a0",
39+
a1 = "a1",
40+
a2 = "a2",
41+
a3 = "a3",
42+
a4 = "a4",
43+
a5 = "a5",
44+
a6 = "a6",
45+
a7 = "a7",
46+
a8 = "a8",
47+
a9 = "a9",
48+
a10 = "a10"
3149

3250
/**
3351
B-Series is the geometric mean of the A-series
3452
For more detail: https://en.wikipedia.org/wiki/Paper_size#B_series
3553
*/
36-
case b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10
54+
case b0 = "b0",
55+
b1 = "b1",
56+
b2 = "b2",
57+
b3 = "b3",
58+
b4 = "b4",
59+
b5 = "b5",
60+
b6 = "b6",
61+
b7 = "b7",
62+
b8 = "b8",
63+
b9 = "b9",
64+
b10 = "b10"
3765

3866
/**
3967
C-Series is ususally used for envelopes. Definition is written in ISO 269
4068
For more detail: https://en.wikipedia.org/wiki/Paper_size#C_series
4169
*/
42-
case c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
70+
case c0 = "c0",
71+
c1 = "c1",
72+
c2 = "c2",
73+
c3 = "c3",
74+
c4 = "c4",
75+
c5 = "c5",
76+
c6 = "c6",
77+
c7 = "c7",
78+
c8 = "c8",
79+
c9 = "c9",
80+
c10 = "c10"
4381

4482
/**
4583
Size defined in constants

Source/API/Section/PDFSectionColumn.swift

+5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ public class PDFSectionColumn: PDFDocumentObject {
1919
*/
2020
public private(set) var width: CGFloat
2121

22+
/**
23+
Background color of this section
24+
*/
25+
public var backgroundColor: UIColor?
26+
2227
// MARK: - INTERNAL VARS
2328

2429
/**

Source/API/Table/Style/PDFTableCellBorders.swift

+6
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,9 @@ public struct PDFTableCellBorders {
4343
self.bottom = bottom
4444
}
4545
}
46+
47+
extension PDFTableCellBorders {
48+
49+
public static let none = PDFTableCellBorders(left: .none, top: .none, right: .none, bottom: .none)
50+
51+
}

Source/API/Table/Style/PDFTableCellStyle.swift

+5
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@ public struct PDFTableCellStyle {
3838
self.font = font
3939
}
4040
}
41+
42+
extension PDFTableCellStyle {
43+
44+
public static let none = PDFTableCellStyle(colors: (fill: UIColor.clear, text: UIColor.black), borders: .none, font: UIFont.systemFont(ofSize: UIFont.systemFontSize))
45+
}

Source/Internal/Section/PDFSectionObject.swift

+53-26
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import UIKit
1212
*/
1313
internal class PDFSectionObject: PDFRenderObject {
1414

15+
internal struct PDFSectionColumnMetadata {
16+
let minX: CGFloat
17+
let width: CGFloat
18+
let backgroundColor: UIColor?
19+
}
20+
1521
/**
1622
TODO: Documentation
1723
*/
@@ -30,45 +36,45 @@ internal class PDFSectionObject: PDFRenderObject {
3036
override internal func calculate(generator: PDFGenerator, container: PDFContainer) throws -> [PDFLocatedRenderObject] {
3137
var result: [PDFLocatedRenderObject] = []
3238

39+
// Save state of layout
3340
let originalIndent = generator.layout.indentation.content
3441
let originalContentOffset = generator.getContentOffset(in: container)
3542

36-
var indentationLeft: CGFloat = 0.0
37-
var columnWidthSum: CGFloat = 0.0
43+
var leftColumnGuide: CGFloat = 0.0
3844
var objectsPerColumn: [Int: [PDFLocatedRenderObject]] = [:]
3945

40-
let contentWidth = generator.document.layout.width
46+
let availableWidth = generator.document.layout.width
4147
- generator.layout.margin.left
4248
- generator.layout.margin.right
49+
let contentWidth = availableWidth - max(0, CGFloat(section.columns.count - 1) * section.columnMargin)
4350

51+
var columnMetadata = [PDFSectionColumnMetadata]()
4452
for (columnIndex, column) in section.columns.enumerated() {
45-
columnWidthSum += column.width
46-
47-
let columnLeftMargin = columnIndex == 0 ? 0 : section.columnMargin / 2
48-
let columnRightMargin = columnIndex == section.columns.count - 1 ? 0 : section.columnMargin / 2
53+
let columnWidth = column.width * contentWidth
54+
let rightColumnGuide = leftColumnGuide + columnWidth
4955

5056
for container in [PDFContainer.contentLeft, .contentCenter, .contentRight] {
5157
generator.setContentOffset(in: container, to: originalContentOffset)
52-
generator.layout.indentation.setLeft(indentation: indentationLeft + columnLeftMargin, in: container)
53-
generator.layout.indentation.setRight(indentation: contentWidth
54-
- columnWidthSum * contentWidth
55-
+ columnRightMargin, in: container)
58+
generator.layout.indentation.setLeft(indentation: leftColumnGuide, in: container)
59+
generator.layout.indentation.setRight(indentation: availableWidth - rightColumnGuide, in: container)
5660
}
5761

58-
let object = PDFSectionColumnObject(column: column)
59-
objectsPerColumn[columnIndex] = try object.calculate(generator: generator, container: container)
62+
objectsPerColumn[columnIndex] = try PDFSectionColumnObject(column: column)
63+
.calculate(generator: generator, container: container)
64+
65+
columnMetadata.append(.init(minX: generator.layout.margin.left + leftColumnGuide,
66+
width: columnWidth,
67+
backgroundColor: column.backgroundColor))
6068

61-
indentationLeft += column.width * contentWidth
69+
leftColumnGuide = rightColumnGuide + section.columnMargin
6270
}
63-
result += calulatePageBreakPositions(objectsPerColumn)
71+
result += calulatePageBreakPositions(objectsPerColumn, metadata: columnMetadata, container: container)
6472
generator.layout.indentation.content = originalIndent
6573

6674
var contentMinY: CGFloat?
6775
var contentMaxY: CGFloat?
6876

69-
for current in result.reversed() {
70-
let currentObject = current.1
71-
77+
for (_, currentObject) in result.reversed() {
7278
if currentObject is PDFPageBreakObject {
7379
break
7480
}
@@ -112,7 +118,7 @@ internal class PDFSectionObject: PDFRenderObject {
112118
...
113119
```
114120
*/
115-
internal func calulatePageBreakPositions(_ objectsPerColumn: [Int: [PDFLocatedRenderObject]]) -> [PDFLocatedRenderObject] {
121+
internal func calulatePageBreakPositions(_ objectsPerColumn: [Int: [PDFLocatedRenderObject]], metadata: [PDFSectionColumnMetadata], container: PDFContainer) -> [PDFLocatedRenderObject] {
116122
// stores how many objects are in one column at max
117123
let maxObjectsPerColumn = objectsPerColumn.reduce(0) { max($0, $1.value.count) }
118124

@@ -129,22 +135,43 @@ internal class PDFSectionObject: PDFRenderObject {
129135

130136
// loop through all objects, row by row for each column
131137
for objectIndex in 0..<maxObjectsPerColumn {
138+
// track the result elements per column, so we can calculate the section column frames
139+
var resultPerColumn = [Int: [PDFLocatedRenderObject]]()
140+
132141
for (columnIndex, columnObjects) in objectsPerColumn where columnObjects.count > objectIndex {
133142
let columnObject = columnObjects[objectIndex]
134143

135-
// if we already began to stack objects for this column, we simply put all subsequent objects onto the stack
136144
if var columnStack = stackedObjectsPerColumn[columnIndex], !columnStack.isEmpty {
145+
// if we already began to stack objects for this column, we simply put all subsequent objects onto the stack
137146
columnStack.append(columnObject)
138147
stackedObjectsPerColumn[columnIndex] = columnStack
139-
140-
// if the column is requesting a page break, we start stacking the objects
141148
} else if columnObject.1 is PDFPageBreakObject {
149+
// if the column is requesting a page break, we start stacking the objects
142150
stackedObjectsPerColumn[columnIndex] = [columnObject]
143-
144-
// if the column does not have a stack and is not requesting a page break we just add the object to the result
145151
} else {
146-
result += [columnObject]
152+
// if the column does not have a stack and is not requesting a page break we just add the object to the result
153+
resultPerColumn[columnIndex] = (resultPerColumn[columnIndex] ?? []) + [columnObject]
154+
}
155+
}
156+
157+
// swiftlint:disable multiline_function_chains
158+
let sectionMinY = resultPerColumn.values.reduce([], +)
159+
.map(\.1.frame).map({ $0.minY })
160+
.reduce(CGFloat.greatestFiniteMagnitude, min)
161+
let sectionMaxY = resultPerColumn.values.reduce([], +)
162+
.map(\.1.frame).map({ $0.maxY })
163+
.reduce(CGFloat.leastNormalMagnitude, max)
164+
165+
for (idx, columnObjects) in resultPerColumn {
166+
let met = metadata[idx]
167+
guard let backgroundColor = met.backgroundColor else {
168+
result += columnObjects
169+
continue
147170
}
171+
let frame = CGRect(x: met.minX, y: sectionMinY, width: met.width, height: sectionMaxY - sectionMinY)
172+
let rect = PDFRectangleObject(lineStyle: .none, size: frame.size, fillColor: backgroundColor)
173+
rect.frame = frame
174+
result += [(container, rect)] + columnObjects
148175
}
149176

150177
// does any of the columns request a page break?
@@ -174,7 +201,7 @@ internal class PDFSectionObject: PDFRenderObject {
174201
result += [(.contentLeft, PDFPageBreakObject())]
175202

176203
// ... and process the stacked objects first
177-
result += calulatePageBreakPositions(stackedObjectsPerColumn)
204+
result += calulatePageBreakPositions(stackedObjectsPerColumn, metadata: metadata, container: container)
178205

179206
// now we can empty the column stacks and keep going
180207
// with the objects which still need to be processed

TPPDF.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'TPPDF'
3-
s.version = '2.0.1'
3+
s.version = '2.1.0'
44
s.summary = 'TPPDF is a simple-to-use PDF builder for iOS'
55
s.description = <<-DESC
66
TPPDF is an object-based PDF builder, completely built in Swift.

0 commit comments

Comments
 (0)