[iOS 11] PDFKit入門
はじめに
iOS11から新しくPDFKitが追加されました。以前からMac用のSDKにはPDFKitが含まれていましたが、iOSにはありませんでした。PDFKitの登場前はWebViewなどで表示しており、細かい制御はできませんでした。それが今回のPDFKit追加によって、表示だけではなくて色々な制御ができるようになります。
この記事では、PDFKitの概要と基本的な機能のサンプルをご紹介します。
PDFKitの概要
PDFKitはいくつかのユーティリティクラスに分かれています。
PDFView
ビューアー的な機能を持ちます。
PDFDocument
PDFデータまたはPDFファイルを指します。PDFデータの書き込み、検索、選択などの機能があります。
PDFPage
ページ単位の制御部分です。テキストや注釈、描画にまつわる機能があります。
PDFAnnotation
ページの中の注釈部分です。リンクやフォームなどの機能があります。
PDFOutline
PDFドキュメントの構造です。ツリー構造で表されます。
PDFSelection
PDFドキュメント内のテキスト選択を識別します。
PDFDestination
PDFページ上のポイントを記述します。
PDFThumbnailView
PDFのサムネイル機能を持ちます。
サンプルコード
この記事内のサンプルは以下の下記環境で試しています。
Xcode | 9.0 |
---|---|
Swift | 4.0 |
PDFを表示する (PDFView)
まずは基本の表示からです。Resources内にあるsample01.pdfを表示させる手順です。
1. Storyboard上にUIViewを配置
PDFを表示させたいUIViewControllerにUIViewを配置します。
配置したら適宜制約を付けます。
2. PDFViewクラスの設定
配置したUIViewのCustom ClassにPDFViewを設定します。
3. Outlet接続
PDFViewをOutletで接続します。接続する前に、
import PDFKit
を追加します。
4. コード記載
PDFをPDFViewに表示させます。PDFViewの.documentプロパティにPDFDocumentを設定すればOKです。
import UIKit import PDFKit class ViewController: UIViewController { @IBOutlet weak var pdfView: PDFView! override func viewDidLoad() { super.viewDidLoad() if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.document = document } } }
実行結果
背景色を変える (PDFView)
ビューアーの背景色はPdfViewの.backgroundColorプロパティで設定できます。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.backgroundColor = UIColor.lightGray pdfView.document = document } }
実行結果
それぞれ、
pdfView.backgroundColor = UIColor.lightGray
pdfView.backgroundColor = UIColor.orange
とした時の表示です。
オートスケール (PDFView)
オートスケールをtrueにすると、初期表示が画面サイズにピッタリ入るように表示されます。PdfViewの.autoScalesプロパティにBool値を入れます。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.autoScales = true pdfView.backgroundColor = UIColor.lightGray pdfView.document = document } }
実行結果
それぞれ、
pdfView.autoScales = true
pdfView.autoScales = false
とした時の表示です。
余白 (PDFView)
余白を消す場合
PDFViewで表示する際に余白を消すには、.displaysPageBreakプロパティをfalseにします。設定しない(デフォルト値)はtrueになります。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.autoScales = true pdfView.backgroundColor = UIColor.lightGray pdfView.displaysPageBreaks = false pdfView.document = document } }
任意の余白をいれる
PDFViewに任意の余白を入れるには、.pageBreakMarginsプロパティにUIEdgeInsetsを設定します。この時、.displaysPageBreaksプロパティをfalseにすると.pageBreakMarginsは常に{0.0、0.0、0.0、0.0}を返すようになるので注意が必要です。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.autoScales = true pdfView.backgroundColor = UIColor.lightGray pdfView.displaysPageBreaks = true pdfView.pageBreakMargins = UIEdgeInsets(top: 10.0, left: 40.0, bottom: 10.0, right: 0.0) pdfView.document = document } }
実行結果
それぞれ、
pdfView.displaysPageBreaks = false
pdfView.displaysPageBreaks = true
pdfView.displaysPageBreaks = true
pdfView.pageBreakMargins = UIEdgeInsets(top: 10.0, left: 40.0, bottom: 10.0, right: 0.0)
とした時の表示です。
表示モード (PDFView)
PDFの仕様として5種類のボックス値を持っています。表示用にそれらのどれを使うか設定することができます。デフォルトではCropBoxです。
- Crop Box
- Trim Box
- Art Box
- Media Box
- Bleed Box
// Crop Box pdfView.displayBox = .cropBox // Trim Box pdfView.displayBox = .trimBox // Art Box pdfView.displayBox = .artBox // Media Box pdfView.displayBox = .mediaBox // Bleed Box pdfView.displayBox = .bleedBox
参考
スクロールの方向を変更する (PDFView)
ビューアーのスクロール方向を変更するには.displayDirectionプロパティを変更します。縦の場合は.vertical
、横の場合は.horizontal
を設定します。デフォルト値は.verticalです。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.autoScales = true pdfView.backgroundColor = UIColor.lightGray pdfView.displayDirection = .horizontal // 横スクロール pdfView.document = document } }
実行結果
それぞれ、
pdfView.displayDirection = .vertical
pdfView.displayDirection = .horizontal
とした時の表示です。
表示モードを変更する (PDFView)
PDFViewの表示モードには以下の4パターンがあります。
- 単一ページ/全ページをスクロールで表示 .singlePageContinuous
- 単一ページのみ .singlePage
- 見開きページ/前ページをスクロールで表示 .twoUpContinuous
- 見開きページのみ .twoUp
デフォルトでは.singlePageContinuousとなります。表示モードを変更するには、.displayModeプロパティを設定します。
// 単一/全ページをスクロール表示(デフォルト) pdfView.displayMode = .singlePageContinuous // 単一ページのみ pdfView.displayMode = .singlePage // 見開き/全ページをスクロール表示 pdfView.displayMode = .twoUpContinuous // 見開きページのみ pdfView.displayMode = .twoUp
見開きの順番を変える (.twoUpContinuous/.twoUp)
.twoUpContinuousまたは.twoUpの見開きにした時に、ベージの順番を右から左にするには.displaysRTLプロパティをtrueにします。
// ページの表示を左から右のままにする(デフォルト) pdfView.displaysRTL = false // ページの表示を右から左にする pdfView.displaysRTL = true
見開きの時に最初のページを表紙として扱う (.twoUpContinuous/.twoUp)
.twoUpContinuousまたは.twoUpの見開きにした時に、最初のページを本の表紙として扱い、単独表示をするには.displaysAsBookプロパティをtrueにします。
// 最初のページから見開きを適用する(デフォルト) pdfView.displaysAsBook = false // 最初のページを表紙として扱い、単独で表示させる pdfView.displaysAsBook = true
PageViewControllerを利用する
usePageViewController(true)メソッドを呼び出すとビューアーの方でpageViewControllerを利用して表示するようになります。その際、displayModeは無視されます。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.usePageViewController(true) pdfView.document = document } }
ページ遷移 (PDFView)
PDFViewにはページを遷移するメソッドが用意されています。下記はボタンを押した時にページ遷移させるサンプルです。
次のページ
PDFViewの.canGoToNextPage()で次のページへ遷移できるかどうかのBool値が返ってきます。 .goToNextPage()で次のページに遷移することができます。
@IBAction func didTapNextButton(_ sender: Any) { if pdfView.canGoToNextPage() { pdfView.goToNextPage(nil) } }
前のページ
PDFViewの.canGoToPreviousPage()で前のページへ遷移できるかどうかのBool値が返ってきます。 .goToPreviousPage()で前のページに遷移することができます。
@IBAction func didTapPreviousButton(_ sender: Any) { if pdfView.canGoToPreviousPage() { pdfView.goToPreviousPage(nil) } }
最初のページ
PDFViewの.canGoToFirstPage()で最初のページへ遷移できるかどうかのBool値が返ってきます。 .goToFirstPage()で最初のページに遷移することができます。
@IBAction func didTapFirstButton(_ sender: Any) { if pdfView.canGoToFirstPage() { pdfView.goToFirstPage(nil) } }
最後のページ
PDFViewの.canGoToLastPage()で最後のページへ遷移できるかどうかのBool値が返ってきます。 .goToLastPage()で最後のページに遷移することができます。
@IBAction func didTapLastButton(_ sender: Any) { if pdfView.canGoToLastPage() { pdfView.goToLastPage(nil) } }
サムネイルを表示させる (PDFThumbnail)
PDFViewと同じようにStoryboard上にViewを配置して、Custom ClassにPDFThumbnailを設定します。
そして、PDFThumbnailをOutletで接続します。
そして、PDFThumbnailViewの.pdfViewにPDFViewを設定します。.layoutModeでサムネイルのレイアウト(方向)を設定、.thumbnailSizeでサムネイルのサイズを指定、.backgroundColorでサムネイルの背景色を設定することができます。
import UIKit import PDFKit class ViewController: UIViewController { @IBOutlet weak var pdfView: PDFView! @IBOutlet weak var pdfThumbnailView: PDFThumbnailView! override func viewDidLoad() { super.viewDidLoad() if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.autoScales = true pdfView.backgroundColor = UIColor.lightGray pdfView.document = document } } pdfThumbnailView.pdfView = pdfView pdfThumbnailView.layoutMode = .horizontal pdfThumbnailView.backgroundColor = UIColor.gray pdfThumbnailView.thumbnailSize = CGSize(width: 40, height: 40) }
実行結果
画面の下に横向きのサムネイルを入れました。
パスワードが設定されているPDFの扱い (PDFDocument)
パスワードが設定されているPDFを表示しようとすると、標準でパスワード入力フォームが表示されます。ここに正しいパスワードを入れると通常通りファイルを見ることができます。
また、コード内でパスワードを入れることもできます。documentに対して.unlock(withPassword:)でパスワードを入れておくと、通常通りにPDFが表示されます。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { document.unlock(withPassword: "password") // passwordの部分にパスワードを入れる pdfView.document = document } }
なお、PDFにパスワードが設定さているかどうかはdocument.isEncryptedで調べらることが可能です。
ドキュメントの操作 (PDFDocument)
PDFKitではPDFドキュメント自体の編集もすることができます。
ページの入れ替え
ドキュメントのページを入れ替えるには、documentの.exchangePage(at: withPageAt:)メソッドを呼び出します。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { document.exchangePage(at: 0, withPageAt: 1) // 最初のページと次のページを入れ替える pdfView.document = document } }
ページの削除
ドキュメントのページを削除するには、documentのdocument.removePage(at:)メソッドを呼び出します。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { pdfView.displayMode = .twoUpContinuous document.removePage(at: 3) // indexが3のページを削除する pdfView.document = document } }
ファイルの保存 (PDFDocument)
PDFDocumentにはファイ居るを書き込むためのwrite(to:)メソッドが存在します。引数には保存するファイルのパスを入れます。
以下はドキュメントディレクトリにoutput.pdfというファイルを書き出すサンプルです。(documentはPDFDocumentクラスです)
if let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first { let path = url.appendingPathComponent("output.pdf") document.write(to: path) }
検索 (PDFDocument)
PDFKitでは、文字列でドキュメント内を検索できます。
一番簡単なのは、findString()メソッドでヒットしたPDFSelectionの一覧が返ってきます。
// [PDFSelection]の配列が返る。ヒット知ない時は空のリスト let selections = findString("検索文字列", withOptions: .caseInsensitive)
また、beginFindString()、beginFindStrings()はPDFDocumentのDelegateでヒットする度にdidMatchString()が呼び出されます。 この2つの違いは検索文字列が複数指定するかしないかです。
if let documentURL = Bundle.main.url(forResource: "sample01", withExtension: "pdf") { if let document = PDFDocument(url: documentURL) { document.delegate = self document.beginFindString("abc", withOptions: .caseInsensitive) // abcという文字列を検索 pdfView.document = document } } } // 〜 中略 〜 } extension ViewController: PDFDocumentDelegate { // 検索にヒットしたら呼ばれる(引数はヒットした文字列のPDFSelection) public func didMatchString(_ instance: PDFSelection) { } // ドキュメントの検索終了 public func documentDidEndDocumentFind(_ notification: Notification) { } }
検索オプションについての詳細は、こちらをご覧ください。
さいごに
今回紹介した以外にも色々な機能があります。 次回、この記事に入れられなかった機能を紹介できればと思います。