Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
sgade committed Jun 12, 2024
0 parents commit 40a0e6d
Show file tree
Hide file tree
Showing 18 changed files with 1,448 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
8 changes: 8 additions & 0 deletions Example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm/configuration/registries.json
.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
.netrc
22 changes: 22 additions & 0 deletions Example/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// swift-tools-version: 5.10

import PackageDescription

let package = Package(
name: "Example",
platforms: [
.macOS(.v13)
],
dependencies: [
.package(
name: "PDFViewKit",
path: ".."
)
],
targets: [
.executableTarget(
name: "Example",
dependencies: ["PDFViewKit"]
)
]
)
28 changes: 28 additions & 0 deletions Example/Sources/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import SwiftUI
import PDFViewKit

struct MyPDFContent: View {

var body: some View {
Text("Hello, World")
}

}

let destination = FileManager.default.temporaryDirectory.appending(path: "MyPDF.pdf")

let document = PDFDocument {
MyPDFContent()
}

do {
try PDFRenderer.render(
document: document,
to: destination,
atPageSize: .a4
)

print("PDF written to \(destination.absoluteString).")
} catch {
print("Failed to render PDF: \(error)")
}
621 changes: 621 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// swift-tools-version: 5.10

import PackageDescription

let package = Package(
name: "PDFViewKit",
platforms: [
.macOS(.v13)
],
products: [
.library(
name: "PDFViewKit",
targets: ["PDFViewKit"]
)
],
targets: [
.target(name: "PDFViewKit")
]
)
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# PDFViewKit

Create PDF files using SwiftUI views.

## Usage

First, define the views that make up the content of your PDF. Since PDF pages are fixed size, you need to make sure
that your content fits your page size.

```swift
import SwiftUI

struct MyPDFContent: View {

var body: some View {
Text("Hello, World")
}

}
```

Then, use the `render(document:to:atPageSize:)` function on `PDFRenderer`.
This function expects a `PDFDocument` which can be created by passing it a set of views that each make up a single page.

```swift
let document = PDFDocument {
MyPDFContent()
}

do {
try PDFRenderer.render(
document: document,
at: destination,
atPageSize: .a4
)
} catch {
...
}
```

That's it! Your PDF file will be generated into the given `destination` URL.

## Important notes

SwiftUI is a framework for creating dynamic user interfaces. PDFs are not dynamic and their pages have a fixed size.
Therefore, no interactivity is possible in your views, and using certain property wrappers will generate runtime
warnings since the views are not part of any view hierarchy in a scene.

Interactive views are not rendered with their default look. Instead, they will appear as a red crossed out area.
For these views, you will need to provide a non-interactive view that mimics the original view's appearance.

The following alternative views are already provided:

- [`Link`](https://developer.apple.com/documentation/swiftui/link): `PDFLink`

### Implementing your own PDF-compatible views

To create views that react to being rendered into a PDF file, you can use the `@Environment(\.renderingEnvironment)` to
determine if the view is currently being rendered into a PDF. This allows you to switch out the implementation of your
view, and make it interactive if used inside of an actual application window hierarchy.

Similarly, you can get the PDF rendering DPI using `@Environment(\.pdfRenderingDPI)`.
The PDF's page size is provided using `@Environment(\.pdfPageSize)`.
188 changes: 188 additions & 0 deletions Sources/PDFViewKit/DIN.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
//
// DIN.swift
// PDFViewKit
//
// Copyright (C) 2024 Sören Gade
// See LICENSE for full license.
//

import Foundation

// Source: https://de.wikipedia.org/wiki/Papierformat#Internationale_Papierformate_(ISO/DIN)
public enum DIN {

case a0
case a1
case a2
case a3
case a4
case a5
case a6
case a7
case a8
case a9
case a10

}

// MARK: Physical page sizes

public extension DIN {

var width: Measurement<UnitLength> {
switch self {
case .a0:
Measurement(
value: 841,
unit: .millimeters
)

case .a1:
Measurement(
value: 594,
unit: .millimeters
)

case .a2:
Measurement(
value: 420,
unit: .millimeters
)

case .a3:
Measurement(
value: 297,
unit: .millimeters
)

case .a4:
Measurement(
value: 210,
unit: .millimeters
)

case .a5:
Measurement(
value: 148,
unit: .millimeters
)

case .a6:
Measurement(
value: 105,
unit: .millimeters
)

case .a7:
Measurement(
value: 74,
unit: .millimeters
)

case .a8:
Measurement(
value: 52,
unit: .millimeters
)

case .a9:
Measurement(
value: 37,
unit: .millimeters
)

case .a10:
Measurement(
value: 26,
unit: .millimeters
)
}
}

var height: Measurement<UnitLength> {
switch self {
case .a0:
Measurement(
value: 1189,
unit: .millimeters
)

case .a1:
Measurement(
value: 841,
unit: .millimeters
)

case .a2:
Measurement(
value: 594,
unit: .millimeters
)

case .a3:
Measurement(
value: 420,
unit: .millimeters
)
case .a4:
Measurement(
value: 297,
unit: .millimeters
)

case .a5:
Measurement(
value: 210,
unit: .millimeters
)

case .a6:
Measurement(
value: 148,
unit: .millimeters
)

case .a7:
Measurement(
value: 105,
unit: .millimeters
)

case .a8:
Measurement(
value: 74,
unit: .millimeters
)

case .a9:
Measurement(
value: 52,
unit: .millimeters
)

case .a10:
Measurement(
value: 37,
unit: .millimeters
)
}
}

}

// MARK: Calculated properties based on physical sizes

public extension DIN {

var aspectRatio: CGFloat {
width.converted(to: .millimeters).value / height.converted(to: .millimeters).value
}

func size(atDPI dpi: DPI) -> CGSize {
CGSize(
width: width.converted(to: .inches).value * dpi.rawValue,
height: height.converted(to: .inches).value * dpi.rawValue
)
}

}
20 changes: 20 additions & 0 deletions Sources/PDFViewKit/DPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// DPI.swift
// PDFViewKit
//
// Copyright (C) 2024 Sören Gade
// See LICENSE for full license.
//

import Foundation

public enum DPI: CGFloat {

// based on https://www.adobe.com/uk/creativecloud/photography/discover/dots-per-inch-dpi-resolution.html
case display = 96
case displayHigh = 144 // 150%

case print = 300
case printArtwork = 600

}
Loading

0 comments on commit 40a0e6d

Please sign in to comment.