Skip to content

Commit

Permalink
Merge pull request #212 from techprimate/release/2.1.0
Browse files Browse the repository at this point in the history
Release/2.1.0
  • Loading branch information
Philip Niedertscheider committed Jun 15, 2020
2 parents 848d33a + 81a7721 commit 4447ffd
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 123 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ env:
- PROJECT="Example.xcodeproj"
- EXAMPLE_SCHEME="Example"

- secure: y71ScxtfYr3/DI0XKjGz8Bmia33QF9vO5euPJJbQ6kD5ADhEFkici/YZWxDkYtEZocKaUHIR4KYrKya2kTwJC630s2wLg974gERcUATZkWxeJdKgpfZ2aZtqYNPPDxozMTFtiT4kaw5HiD0usJUgnWKqf/XsTW+3BpTJA58xqXChcXulibs9FJvPz6ZVxW+dNW3F5xtC3GCOWk3Rofrw8GJXdCfie/CaJUvxaQVm9hOwKn0Akpe6rvFKlMtfYOLL9yclaMAM+Um7uFVZwhCPHtAzXvpOhA2U/n7eXy/fNpoXxi9zf+epD1iiFmxJQfc1ZO6jkUJEksLXdO3pEMnoe205Bm70QMO6l9gyuq6Z2cUcCBrd2wDzfLYBoOqapgachpTQifotXX6rapm5pCDhg0pMCRihH5moFnsE7jqz2Lo4n68cvSa9+Irr97HmvH+GdF++VIVGK4/GJOErwGUx0Nh32BIeV3p4D+MNm918mAEO7a66a1RiTKNAr1xnrAtCl0k4XeZPCp0uQQ0TEVOxi/vecIS3k6mNMJw5W9tE0F7fun8kHdv6EKrzKIBkyDxMsh2Z5zVqE3wRcCuD+7FgrcmYDUXyk+t1o2cMNs7iZkKFQAG69+qXviTXnaD9Mq0LGP1sx+OQpQKzde9CAC+tgj+1fqD41jqr6zHJqaEOxvs=
stages:
- Tests
- Examples
Expand Down
31 changes: 30 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Change Log

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

**Implemented enhancements:**

Expand All @@ -11,6 +11,35 @@

**Merged pull requests:**

## [2.1.0](https://github.com/techprimate/TPPDF/tree/HEAD) (2020-06-15)
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.0.1...2.1.0)

**Implemented enhancements:**

- Added raw representable values to `PDFPageFormat`
- Added raw representable type to `PDFLineType`
- Added constant `none` to `PDFTableCellStyle` and `PDFTableCellBorders`
- Added background color to `PDFSectionColumn` (Issue #122)

**Fixed bugs:**

- Added note to documentation about not reusing `PDFSection` instances (Issue #122)
- Added missing font and text color reset to generator

**Closed issues:**

- #73
- #122
- #204
- #197
- #189
- #186
- #184
- #183

**Merged pull requests:**

- #211

## [2.0.1](https://github.com/techprimate/TPPDF/tree/2.0.1) (2020-05-31)
[Full Changelog](https://github.com/techprimate/TPPDF/compare/2.0.0...2.0.1)
Expand Down
2 changes: 2 additions & 0 deletions Documentation/Usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,8 @@ section.columns[2].addText(.center, text: "center")
document.add(sectiion: section)
```

**Attention:** Do not add a `PDFSection` multiple times, as they hold some internal state, which will lead to collisions and unpredictable framing calculations

#### Column Wrap Sections

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).
Expand Down
7 changes: 6 additions & 1 deletion Shared/Examples/MultiSectionExampleFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@ class MultiSectionExampleFactory: ExampleFactory {
let document = PDFDocument(format: .a4)

// Add multi column section
let section = PDFSection(columnWidths: [0.33, 0.34, 0.33])
let section = PDFSection(columnWidths: [0.30, 0.40, 0.30])
section.columns[0].backgroundColor = UIColor.red
section.columns[0].add(.left, text: "left")
section.columns[0].add(.center, text: "center")
section.columns[0].add(.right, text: "right")
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.")
section.columns[0].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))
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.")

section.columns[1].backgroundColor = UIColor.orange
section.columns[1].add(.left, text: "left")
section.columns[1].add(.center, text: "center")
section.columns[1].add(.right, text: "right")
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.")
section.columns[1].add(.center, text: "center")
section.columns[1].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))

section.columns[2].backgroundColor = UIColor.yellow
section.columns[2].add(.center, image: PDFImage(image: UIImage(named: "Icon.png")!, size: CGSize(width: 40, height: 40), quality: 0.9))
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.")
section.columns[2].add(.left, text: "left")
Expand Down
10 changes: 5 additions & 5 deletions Source/API/Graphics/PDFLineType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,26 @@
- dashed: Line consists out of short dashes
- dotted: Lines consists out of dots
*/
public enum PDFLineType {
public enum PDFLineType: String {

/**
No visible line
*/
case none
case none = "none"

/**
Full line
*/
case full
case full = "full"

/**
Line is dashed, dash length and spacing is three times the line width
*/
case dashed
case dashed = "dashed"

/**
Line is dotted. Dot spacing is twice the line width
*/
case dotted
case dotted = "dotted"

}
6 changes: 6 additions & 0 deletions Source/API/PDFGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,11 @@ public class PDFGenerator: PDFGeneratorProtocol, CustomStringConvertible {
layout.reset()
columnState.reset()
currentPage = 1
fonts = fonts.mapValues { _ in
UIFont.systemFont(ofSize: UIFont.systemFontSize)
}
textColor = textColor.mapValues { _ in
UIColor.black
}
}
}
50 changes: 44 additions & 6 deletions Source/API/Page Format/PDFPageFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,73 @@ import UIKit
* Source for page sizes: https://www.papersizes.org
* All sizes are calculated using 72 points/inch
*/
public enum PDFPageFormat {
public enum PDFPageFormat: String {

/**
Page formats mostly used in the USA
*/
case usHalfLetter, usLetter, usLegal, usJuniorLegal, usLedger
case usHalfLetter = "us.half-letter",
usLetter = "us.letter",
usLegal = "us.legal",
usJuniorLegal = "us.junior-legal",
usLedger = "us.ledger"

/**
Page formats according to the American National Standards Institute
*/
case ansiA, ansiB, ansiC, ansiD, ansiE
case ansiA = "ansi.a",
ansiB = "ansi.b",
ansiC = "ansi.c",
ansiD = "ansi.d",
ansiE = "ansi.e"

/**
A-Series of paper standard DIN 476
For more detail: https://en.wikipedia.org/wiki/Paper_size#A_series
*/
case a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10
case a0 = "a0",
a1 = "a1",
a2 = "a2",
a3 = "a3",
a4 = "a4",
a5 = "a5",
a6 = "a6",
a7 = "a7",
a8 = "a8",
a9 = "a9",
a10 = "a10"

/**
B-Series is the geometric mean of the A-series
For more detail: https://en.wikipedia.org/wiki/Paper_size#B_series
*/
case b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10
case b0 = "b0",
b1 = "b1",
b2 = "b2",
b3 = "b3",
b4 = "b4",
b5 = "b5",
b6 = "b6",
b7 = "b7",
b8 = "b8",
b9 = "b9",
b10 = "b10"

/**
C-Series is ususally used for envelopes. Definition is written in ISO 269
For more detail: https://en.wikipedia.org/wiki/Paper_size#C_series
*/
case c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10
case c0 = "c0",
c1 = "c1",
c2 = "c2",
c3 = "c3",
c4 = "c4",
c5 = "c5",
c6 = "c6",
c7 = "c7",
c8 = "c8",
c9 = "c9",
c10 = "c10"

/**
Size defined in constants
Expand Down
5 changes: 5 additions & 0 deletions Source/API/Section/PDFSectionColumn.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public class PDFSectionColumn: PDFDocumentObject {
*/
public private(set) var width: CGFloat

/**
Background color of this section
*/
public var backgroundColor: UIColor?

// MARK: - INTERNAL VARS

/**
Expand Down
6 changes: 6 additions & 0 deletions Source/API/Table/Style/PDFTableCellBorders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ public struct PDFTableCellBorders {
self.bottom = bottom
}
}

extension PDFTableCellBorders {

public static let none = PDFTableCellBorders(left: .none, top: .none, right: .none, bottom: .none)

}
5 changes: 5 additions & 0 deletions Source/API/Table/Style/PDFTableCellStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,8 @@ public struct PDFTableCellStyle {
self.font = font
}
}

extension PDFTableCellStyle {

public static let none = PDFTableCellStyle(colors: (fill: UIColor.clear, text: UIColor.black), borders: .none, font: UIFont.systemFont(ofSize: UIFont.systemFontSize))
}
79 changes: 53 additions & 26 deletions Source/Internal/Section/PDFSectionObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import UIKit
*/
internal class PDFSectionObject: PDFRenderObject {

internal struct PDFSectionColumnMetadata {
let minX: CGFloat
let width: CGFloat
let backgroundColor: UIColor?
}

/**
TODO: Documentation
*/
Expand All @@ -30,45 +36,45 @@ internal class PDFSectionObject: PDFRenderObject {
override internal func calculate(generator: PDFGenerator, container: PDFContainer) throws -> [PDFLocatedRenderObject] {
var result: [PDFLocatedRenderObject] = []

// Save state of layout
let originalIndent = generator.layout.indentation.content
let originalContentOffset = generator.getContentOffset(in: container)

var indentationLeft: CGFloat = 0.0
var columnWidthSum: CGFloat = 0.0
var leftColumnGuide: CGFloat = 0.0
var objectsPerColumn: [Int: [PDFLocatedRenderObject]] = [:]

let contentWidth = generator.document.layout.width
let availableWidth = generator.document.layout.width
- generator.layout.margin.left
- generator.layout.margin.right
let contentWidth = availableWidth - max(0, CGFloat(section.columns.count - 1) * section.columnMargin)

var columnMetadata = [PDFSectionColumnMetadata]()
for (columnIndex, column) in section.columns.enumerated() {
columnWidthSum += column.width

let columnLeftMargin = columnIndex == 0 ? 0 : section.columnMargin / 2
let columnRightMargin = columnIndex == section.columns.count - 1 ? 0 : section.columnMargin / 2
let columnWidth = column.width * contentWidth
let rightColumnGuide = leftColumnGuide + columnWidth

for container in [PDFContainer.contentLeft, .contentCenter, .contentRight] {
generator.setContentOffset(in: container, to: originalContentOffset)
generator.layout.indentation.setLeft(indentation: indentationLeft + columnLeftMargin, in: container)
generator.layout.indentation.setRight(indentation: contentWidth
- columnWidthSum * contentWidth
+ columnRightMargin, in: container)
generator.layout.indentation.setLeft(indentation: leftColumnGuide, in: container)
generator.layout.indentation.setRight(indentation: availableWidth - rightColumnGuide, in: container)
}

let object = PDFSectionColumnObject(column: column)
objectsPerColumn[columnIndex] = try object.calculate(generator: generator, container: container)
objectsPerColumn[columnIndex] = try PDFSectionColumnObject(column: column)
.calculate(generator: generator, container: container)

columnMetadata.append(.init(minX: generator.layout.margin.left + leftColumnGuide,
width: columnWidth,
backgroundColor: column.backgroundColor))

indentationLeft += column.width * contentWidth
leftColumnGuide = rightColumnGuide + section.columnMargin
}
result += calulatePageBreakPositions(objectsPerColumn)
result += calulatePageBreakPositions(objectsPerColumn, metadata: columnMetadata, container: container)
generator.layout.indentation.content = originalIndent

var contentMinY: CGFloat?
var contentMaxY: CGFloat?

for current in result.reversed() {
let currentObject = current.1

for (_, currentObject) in result.reversed() {
if currentObject is PDFPageBreakObject {
break
}
Expand Down Expand Up @@ -112,7 +118,7 @@ internal class PDFSectionObject: PDFRenderObject {
...
```
*/
internal func calulatePageBreakPositions(_ objectsPerColumn: [Int: [PDFLocatedRenderObject]]) -> [PDFLocatedRenderObject] {
internal func calulatePageBreakPositions(_ objectsPerColumn: [Int: [PDFLocatedRenderObject]], metadata: [PDFSectionColumnMetadata], container: PDFContainer) -> [PDFLocatedRenderObject] {
// stores how many objects are in one column at max
let maxObjectsPerColumn = objectsPerColumn.reduce(0) { max($0, $1.value.count) }

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

// loop through all objects, row by row for each column
for objectIndex in 0..<maxObjectsPerColumn {
// track the result elements per column, so we can calculate the section column frames
var resultPerColumn = [Int: [PDFLocatedRenderObject]]()

for (columnIndex, columnObjects) in objectsPerColumn where columnObjects.count > objectIndex {
let columnObject = columnObjects[objectIndex]

// if we already began to stack objects for this column, we simply put all subsequent objects onto the stack
if var columnStack = stackedObjectsPerColumn[columnIndex], !columnStack.isEmpty {
// if we already began to stack objects for this column, we simply put all subsequent objects onto the stack
columnStack.append(columnObject)
stackedObjectsPerColumn[columnIndex] = columnStack

// if the column is requesting a page break, we start stacking the objects
} else if columnObject.1 is PDFPageBreakObject {
// if the column is requesting a page break, we start stacking the objects
stackedObjectsPerColumn[columnIndex] = [columnObject]

// if the column does not have a stack and is not requesting a page break we just add the object to the result
} else {
result += [columnObject]
// if the column does not have a stack and is not requesting a page break we just add the object to the result
resultPerColumn[columnIndex] = (resultPerColumn[columnIndex] ?? []) + [columnObject]
}
}

// swiftlint:disable multiline_function_chains
let sectionMinY = resultPerColumn.values.reduce([], +)
.map(\.1.frame).map({ $0.minY })
.reduce(CGFloat.greatestFiniteMagnitude, min)
let sectionMaxY = resultPerColumn.values.reduce([], +)
.map(\.1.frame).map({ $0.maxY })
.reduce(CGFloat.leastNormalMagnitude, max)

for (idx, columnObjects) in resultPerColumn {
let met = metadata[idx]
guard let backgroundColor = met.backgroundColor else {
result += columnObjects
continue
}
let frame = CGRect(x: met.minX, y: sectionMinY, width: met.width, height: sectionMaxY - sectionMinY)
let rect = PDFRectangleObject(lineStyle: .none, size: frame.size, fillColor: backgroundColor)
rect.frame = frame
result += [(container, rect)] + columnObjects
}

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

// ... and process the stacked objects first
result += calulatePageBreakPositions(stackedObjectsPerColumn)
result += calulatePageBreakPositions(stackedObjectsPerColumn, metadata: metadata, container: container)

// now we can empty the column stacks and keep going
// with the objects which still need to be processed
Expand Down
2 changes: 1 addition & 1 deletion TPPDF.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TPPDF'
s.version = '2.0.1'
s.version = '2.1.0'
s.summary = 'TPPDF is a simple-to-use PDF builder for iOS'
s.description = <<-DESC
TPPDF is an object-based PDF builder, completely built in Swift.
Expand Down

0 comments on commit 4447ffd

Please sign in to comment.