前回の記事: SwiftUIのレイアウトでPDFを作成する
今回はSwiftUIで作成したView同士を結合したPDFを作成してみた。
ViewからPDFのDataオブジェクトを作成
let page1 = try! Page1().getPdfData(width: 200, height: 200)
...
let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: width, height: height))
let pdf = pdfRenderer.pdfData(actions: { (context) in
context.beginPage()
rootVC?.view.layer.render(in: context.cgContext)
})
PDFを結合する
- PDFKitでPDFのDataオブジェクトをPDFDocumentとして取り込む
- PDFDocumentからPDFのページを抽出して最初のPDFDocumentに結合
let document1 = PDFDocument(data: page1)
let document2 = PDFDocument(data: page2)
let page = document2?.page(at: 0)
document1?.insert(page!, at: 1)
結果画像

評価コード
PDFCombineView.swift
import SwiftUI
import PDFKit
struct PDFCombineView: View {
@State var pdfDocument: PDFDocument?
var body: some View {
VStack {
if let pdfDocument = pdfDocument {
PdfView(pdfDocument: pdfDocument)
}
}
.onAppear {
let page1 = try! Page1().getPdfData(width: 200, height: 200)
let page2 = try! Page2().getPdfData(width: 200, height: 200)
let document1 = PDFDocument(data: page1)
let document2 = PDFDocument(data: page2)
let page = document2?.page(at: 0)
document1?.insert(page!, at: 1)
pdfDocument = document1
}
}
}
struct Page1: View {
var body: some View {
Text("Page1")
}
}
struct Page2: View {
var body: some View {
Text("Page2")
}
}
struct PdfView : UIViewRepresentable {
let pdfDocument: PDFDocument
func makeUIView(context: Context) -> some PDFView {
let pdfView = PDFView()
pdfView.document = pdfDocument
return pdfView
}
func updateUIView(_ uiView: UIViewType, context: Context) {}
}
extension View {
func getPdfData(width:CGFloat=595.2, height:CGFloat=841.8) throws -> Data {
let pdfVC = UIHostingController(rootView: self)
pdfVC.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
let scenes = UIApplication.shared.connectedScenes
let windowScene = scenes.first as? UIWindowScene
let window = windowScene?.windows.first
let rootVC = window?.rootViewController
rootVC?.addChild(pdfVC)
rootVC?.view.insertSubview(pdfVC.view, at: 0)
let pdfRenderer = UIGraphicsPDFRenderer(bounds: CGRect(x: 0, y: 0, width: width, height: height))
let pdf = pdfRenderer.pdfData(actions: { (context) in
context.beginPage()
rootVC?.view.layer.render(in: context.cgContext)
})
pdfVC.removeFromParent()
pdfVC.view.removeFromSuperview()
return pdf
}
}
おまけ
作成したdocumentはdocument.write(to: url)
でPDFファイルに保存します。
let url = try write("sample.pdf", pdfDocument: document1)
print(url.path)
...
func write(_ fileName: String, pdfDocument: PDFDocument) throws -> URL {
let url = try createUrl(fileName: fileName)
let options = [
kCGPDFContextCreator: "@mbotsu",
kCGPDFContextAuthor: "@mbotsu",
kCGPDFContextTitle: "SwiftUIのレイアウトでPDFを作成して結合する",
kCGPDFContextSubject: "ImageRendererは諦めてUIGraphicsPDFRendererでPDFを作成する",
]
pdfDocument.write(to: url,
withOptions: options as [PDFDocumentWriteOption : Any])
return url
}
func createUrl(fileName: String) throws -> URL {
let fileManager = FileManager.default
let url = fileManager.temporaryDirectory.appendingPathComponent(fileName, conformingTo: .pdf)
if fileManager.fileExists(atPath: url.path) {
try fileManager.removeItem(at: url)
}
return url
}
Inspectorで見るとこんな感じ(A4サイズ指定)

References
-
- documentからのpage、insert
-
- documentの書き込み write
実用的に一部書き直したコード