【PDFKit】Swiftでプレゼン資料を作る

この記事は [リクルートライフスタイル Advent Calendar 2017](http://qiita.com/advent-calendar/2017/recruitlifestyle) の3日目の記事です。

# はじめに

ホットペッパービューティーでアプリの開発を担当してる@sotozakiです。

最近は資料を作る機会も増えてきました。
iOSエンジニアだったら、普段書いてるSwiftでプレゼン資料も作りたいはず（？）

今回はSwiftでプレゼン資料を作ってみます！


# 環境

||バージョン|
|:-:|:-:|
|Swift|4.0|
|Xcode|9.1|

# 完成したもの

![output.jpg](https://qiita-image-store.s3.amazonaws.com/0/55415/02fad3e6-d1ee-8ae0-825a-201513b8b86e.jpeg)

このようなPDFの資料を作ることが出来ます。

# プレゼン資料の作り方
PDFKitを使ってPDFを出力することでプレゼン資料を作ります。
今年のWWDCでもPDFKitが取り上げられ、MacOSのみだったものがiOSにも対応しました。

- https://developer.apple.com/documentation/pdfkit
- https://developer.apple.com/videos/play/wwdc2017/241/

# PDFKit
PDFKitのPDFViewというClassを利用することでPDFViewerのようなアプリは簡単に実装することができるようになりました。
今回はViewerではなくプレゼン資料としてPDFを出力したいため、PDFDocument, PDFPageといたClassを利用していきます。


<img width="1310" alt="Screen Shot 2017-11-12 at 10.19.46.png" src="https://qiita-image-store.s3.amazonaws.com/0/55415/d4997cd3-b03a-7dcb-6bc0-2595f2c0c18d.png">
https://devstreaming-cdn.apple.com/videos/wwdc/2017/241iivj8rn2fo3ft0r/241/241_introducing_pdfkit_on_ios.pdf

# PDFDocument, PDFPage
Swift PlayGroundで書いていきます。
まずはPDFKitをimportします。

```Swift
import PDFKit
```

PDFPageを継承したクラスを作成し、iOSエンジニア（の一部）には馴染みのあるdrawメソッドをoverrideして文字や線を描画しています。

```Swift

final class SamplePage: PDFPage {
    private let width = 1024
    private let height = 768
    private let title: String
    private let contents: String
    
    init(title: String, contents: String) {
        self.title = title
        self.contents = contents
        super.init()
    }
    
    override func draw(with box: PDFDisplayBox, to context: CGContext) {
        super.draw(with: box, to: context)
        UIGraphicsPushContext(context)
        context.translateBy(x: 0.0, y: CGFloat(height))
        context.scaleBy(x: 1.0, y: -1.0)
        let rect = CGRect(x: 25, y: 25, width: width, height: 100)
        let attributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 50),
                          NSAttributedStringKey.foregroundColor: UIColor.black]
        title.draw(in: rect, withAttributes: attributes)
        
        let rect2 = CGRect(x: 25, y: 200, width: width, height: 600)
        contents.draw(in: rect2, withAttributes: attributes)
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 100))
        path.addLine(to: CGPoint(x: width, y: 100))
        path.lineWidth = 5.0
        path.stroke()
        UIGraphicsPopContext()
    }
    
    override func bounds(for box: PDFDisplayBox) -> CGRect {
        return CGRect(x: 0, y: 0, width: width, height: height)
    }
}
```

あとはPDFDocumetクラスのインスタンスにPDFPageをinsertしていけば良いです。

```Swift
let pdf = PDFDocument()
let contents = """
・ここにコンテンツを入力します。
"""
let firstPage = SamplePage(title: "タイトル", contents:contents)
pdf.insert(firstPage, at: 0)
```
複数ページ作成する時は同様にinsertを複数回呼ぶとできます。
ここまででpdfの準備はできました。

最後にファイルに書き出します。

```Swift
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
    let path = url.appendingPathComponent("output.pdf")
    print(path)
    pdf.write(to: path)
}
```

出力されたpathにPDFが出力されます 🎉

# 最後に
PDFKitを利用することで、簡単にSwiftでPDF資料を作ることができました！
テーマに対応したり、他のレイアウトでも作れるようになると本格的にSwiftで資料作ることが出来るようになりますね。
最後にソースコードを載せておきます！


# ソースコード

```swift
import UIKit
import PDFKit

final class SamplePage: PDFPage {
    private let width = 1024
    private let height = 768
    private let title: String
    private let contents: String
    
    init(title: String, contents: String) {
        self.title = title
        self.contents = contents
        super.init()
    }
    
    override func draw(with box: PDFDisplayBox, to context: CGContext) {
        super.draw(with: box, to: context)
        UIGraphicsPushContext(context)
        context.translateBy(x: 0.0, y: CGFloat(height))
        context.scaleBy(x: 1.0, y: -1.0)
        let rect = CGRect(x: 25, y: 25, width: width, height: 100)
        let attributes = [NSAttributedStringKey.font: UIFont.systemFont(ofSize: 50),
                          NSAttributedStringKey.foregroundColor: UIColor.black]
        title.draw(in: rect, withAttributes: attributes)
        
        let rect2 = CGRect(x: 25, y: 200, width: width, height: 600)
        contents.draw(in: rect2, withAttributes: attributes)
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 0, y: 100))
        path.addLine(to: CGPoint(x: width, y: 100))
        path.lineWidth = 5.0
        path.stroke()
        UIGraphicsPopContext()
    }
    
    override func bounds(for box: PDFDisplayBox) -> CGRect {
        return CGRect(x: 0, y: 0, width: width, height: height)
    }
}

let pdf = PDFDocument()
let contents = """
・PDFKitをimportする。
・PDFPageのdrawをoverrideする。
・PDFDocumentにPDFPageをinsertする。
・PDFDocumentをファイル書き出し。
"""
let firstPage = SamplePage(title: "【PDFKit】Swiftでプレゼン資料を作る", contents:contents)
pdf.insert(firstPage, at: 0)
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
    let path = url.appendingPathComponent("output.pdf")
    print(path)
    pdf.write(to: path)
}


```