PDFKit を使ってみた

iOS11 から使えるようになった PDFKit について簡単に実装を試してみたのでコードを公開します。

# PDFKit

PDFKit は Mac OS では、 2005年の OS X 10.4 から提供されているライブラリで、
今年のWWDCで iOS11 にも提供されることが発表されました。
PDFファイルを簡単に開けたり、変更、描画、保存に加えて、アノテーションの追加なども気軽に行うことができます。


# サンプルコード

PDFKit が使えるのは Xcode9 からです。
Xcode9 をインストールしたらまずプロジェクトを作成し、プロジェクトに PDFKit.framework を追加します。

準備ができたら実際にコードを見ていきましょう。

## PDFDocument の生成

まずは、PDFDocument というクラスのインスタンスを作ります。
準備として、プロジェクトに追加されている "sampleFile.pdf" というファイルの URL を生成します。
そして、その URL を PDFDocument のイニシャライザに渡してやることでインスタンスを生成することができます。

```swift:swift
// PDFDocument
guard let path = Bundle.main.path(forResource: "sampleFile", ofType: "pdf") else {
    print("failed to get path.")
    return
}
let pdfURL = URL(fileURLWithPath: path)
guard let document = PDFDocument(url: pdfURL) else { return }
```

## PDFView に PDFDocument を追加する

続いて画面に表示するために PDFView を作ります。
PDFView を生成し、先ほど作成した PDFDocument を設定してやります。
その後、各種設定をしてやり(説明は省略します)、 UIVIewController の view に addSubView してやります。

ここまでで、先ほどの "sampleFile.pdf" の内容を画面に表示することができます！
PDFView はたくさんの機能を備えており、ここまでのコードだけでスクロールや拡大縮小することができます。

```swift:swift
// PDFView
pdfView = PDFView(frame: view.frame) // UIViewController.view の大きさで生成 pdfView は ViewController のプロパティ
pdfView?.document = document
pdfView?.backgroundColor = .lightGray
pdfView?.autoScales = true
pdfView?.displayMode = .singlePageContinuous

view.addSubview(pdfView!)
```

## ページの移動

次に、ページの移動をやってみましょう。
以下は storyboard 上でボタンに紐づけられた IBAction です。
さきほど生成した pdfView に対して以下のメソッドを実行するだけで先頭ページ、最終ページ、次ページ、前ページへの移動ができてしまいます。

```swift:swift
@IBAction func startTapped(_ sender: Any) {
    pdfView?.goToFirstPage(self)
}
   
@IBAction func lastTapped(_ sender: Any) {
    pdfView?.goToLastPage(self)
}
   
@IBAction func nextTapped(_ sender: Any) {
    pdfView?.goToNextPage(self)
}
   
@IBAction func prevTapped(_ sender: Any) {
    pdfView?.goToPreviousPage(self)
}
```

## ディスプレイモードの変更

次はディスプレイモードの変更のサンプルです。
PDFView には PDFDisplaymode というプロパティがあり、表示方法を変更することができます。
このサンプルではボタンをタップすることで、1列表示 > 1列連続表示 > 2列表示 >  2列連続表示 の順に切り替えています。

```swift:swift
@IBActionfunc changeTapped(_ sender: Any) {
    guard let p = pdfView else { return }
    let mode: PDFDisplayMode
    switch p.displayMode {
    case .singlePage:
        mode = .singlePageContinuous
    case .singlePageContinuous:
        mode = .twoUp
    case .twoUp:
        mode = .twoUpContinuous
    case .twoUpContinuous:
        mode = .singlePage
    }
    p.displayMode = mode
}
```

ここまでで、PDF ファイルを画面に表示して操作するところまでできました。
以降ページを追加してみる処理とサムネイルを表示する処理をみてみます。


## ページを追加する

以下のサンプルは画像ファイルから PDFPage を生成し、最初に生成した PDFDocument に追加するものです。
まずは PDFPage を作成します。ここもファイルから生成した UIImage を渡しているだけです。簡単ですね。
その後、ドキュメントの最終ページに追加しています。

```swift:swift
guard let image = UIImage(named: "someImage.png") else { return }
guard let page = PDFPage(image: image) else { return }
document.insert(page, at: document.pageCount)
```

## サムネイルを表示する

PDFKit には PDFThumbnailView というクラスがあり簡単に PDF のサムネイルを表示することもできます。
PDFThumbnailView を生成して、あとは thumbView.pdfView に先ほど生成した pdfView を設定してやるだけです。
これでサムネイル表示をすることができます。サムネイルはページをタップすることでそのページを表示することができます。

```swift:swift
thumbView = PDFThumbnailView(frame: CGRect(x: 0, y: view.frame.maxY - 100, width: view.frame.width, height: 100))
thumbView?.pdfView = pdfView
view.addSubview(thumbView!)
```

以上、いかがでしたでしょうか。
非常に簡単に PDF を扱えることがおわかりいただけたかと思います。
製品レベルにするには色々チューニングが必要そうですが、採用するメリットは大きいと思います。
(なんでもっと早く iOS に来なかったのか..!)