ObjecTips

Swift & Objective-C で iOS とか macOS とか

iOS 11 PDFKit

iOS 11 関連記事
iOS 11 UIKit の変更点 - ObjecTips
iOS 11 Foundation の変更点 - ObjecTips
iOS 11 Messages Framework の変更点 - ObjecTips
iOS 11 Core Image の変更点 - ObjecTips
Vision Framework でテキスト検出 Text Detection - ObjecTips
Vision Framework で水平角検出(傾き) Horizon Detection - ObjecTips

koze.hatenablog.jp

PDFKit について

PDFKit | Apple Developer Documentation

iOS 11 で登場した PDFKit は macOS では 10.4 Tiger から存在しているPDF周りの高レベルの Framework で、ただの Core Graphics 関数のラップではなくかなり高機能になっている。

NSURLPDFDocument を初期化するだけでPDF内の文字列が取得できて、文字列検索もできて、ページの入れ替え差し替え、書き出し、アウトライン情報の取得まで出来る。
(アウトライン情報は階層構造を持つリンク付きの目次のようなもので、辞書構造の中にはタイトルと階層情報、リンクの飛び先の情報が入っている。)

PDFViewPDFDocument を設定すればページ移動、拡大縮小、文字列選択、リンク移動の機能を持つ高機能ビューアが出来てしまう。見開き表示もにも対応。PDFThumbnailView によるサムネイル一覧表示までサポートされている。

PDFDocument から取り出したページ情報 PDFPage を使ってアノテーションの追加や指定箇所の文字列の選択、1文字毎の bounds の取得なんかも出来てしまう。

今からPDFビューアを作る人は絶対にこの Framework を使った方がいい。(ていうか何で今まで iOS に持ってきてくれなかったんだ、、)
さらに今回のアップデートでは macOS でも初出の機能があるのでその辺を中心に見ていく。

PDFView
@property (nonatomic) PDFDisplayDirection displayDirection PDFKIT_AVAILABLE(10_13, 11_0);
// Display direction.
PDFKIT_ENUM_AVAILABLE(10_13, 11_0)
typedef NS_ENUM(NSInteger, PDFDisplayDirection)
{
    kPDFDisplayDirectionVertical = 0,
    kPDFDisplayDirectionHorizontal = 1,
};

縦書きPDF対応
多分文字選択時のキャレットの向きとかをよしなにやってくれる。最高
※APIを試してみたところ、displayModekPDFDisplaySinglePageContinuouskPDFDisplayTwoUpContinuous の際に縦スクロールにするか横スクロールにするかを指定できる機能でした。

// Specifies presentation of pages from right-to-left. Defaults to NO.
@property (nonatomic) BOOL displaysRTL PDFKIT_AVAILABLE(10_13, 11_0);

ページの右送り、左送りの変更もこれでやってくれる。最高
※APIを試してみたところ、displayModekPDFDisplayTwoUpkPDFDisplayTwoUpContinuous の時に右側に若番のページを表示してその次のページを左側に表示する機能でした。

@property (nonatomic) CGFloat minScaleFactor PDFKIT_AVAILABLE(10_13, 11_0);
@property (nonatomic) CGFloat maxScaleFactor PDFKIT_AVAILABLE(10_13, 11_0);
@property (nonatomic, readonly) CGFloat sizeToFitScaleFactor PDFKIT_AVAILABLE(10_13, 11_0);

拡大縮小のパラメータ設定等

@property (nonatomic) PDFEdgeInsets pageBreakMargins PDFKIT_AVAILABLE(10_13, 11_0);

マージン

- (void)usePageViewController:(BOOL)enable withViewOptions:(nullable NSDictionary*)viewOptions PDFKIT_AVAILABLE(NA, 11_0);
- (BOOL)isUsingPageViewController PDFKIT_AVAILABLE(NA, 11_0);

これは iOS のみ。
UIPageViewController を使ったレイアウトとナビゲーションにしてくれるらしい。

PDFThumbnailView
@property (nonatomic) UIEdgeInsets contentInset;

iOS のみとドキュメントには書いてあるけど、ヘッダでは特に指定なし。

PDFDocumentDelegate

PDFDocumentDelegate - PDFKit | Apple Developer Documentation

既存で用意されている各種通知の delegate 版が追加されている。

PDFDocument
@property (nonatomic, readonly) BOOL allowsPrinting;                            // Printing the document
@property (nonatomic, readonly) BOOL allowsCopying;                             // Extract content (text, images, etc.)
@property (nonatomic, readonly) BOOL allowsDocumentChanges;                     // Modify the document contents except for page management (document attrubutes)
@property (nonatomic, readonly) BOOL allowsDocumentAssembly;                    // Page management: insert, delete, and rotate pages
@property (nonatomic, readonly) BOOL allowsContentAccessibility;                // Extract content, but only for the purpose of accessibility
@property (nonatomic, readonly) BOOL allowsCommenting;                          // Create or modify annotations, including form field entries
@property (nonatomic, readonly) BOOL allowsFormFieldEntry;                      // Modify form field entries

既存APIではPDFがロックされているか、ロック解除後はプリントが許可されているか、コピーが許可されているかといった権限の取得が出来た。
新しいAPIでは上記のように、ドキュメントの変更許可、アクセシビリティ(スクリーンリーダー等)のみで利用可能か、フォームを編集出来るかなど細かく権限を取得できるようになっている。
ちなみに後述の Core Graphics ではもう少し細かく権限を取得できる。

PDFPage
- (PDFKitPlatformImage *)thumbnailOfSize:(PDFSize)size forBox:(PDFDisplayBox)box PDFKIT_AVAILABLE(10_13, 11_0);

サムネイル取得APIが追加された。PDFKitPlatformImage は iOS では UIImage macOS では NSImage が返される。
PDFSize は iOS では CGSize macOS では NSSize を渡す。

PDFSelection
- (void)extendSelectionForLineBoundaries PDFKIT_AVAILABLE(10_13, 11_0);

現在選択中のテキスト範囲をよしなに拡張してくれる。

PDFAnnotation

多いのでドキュメントを参照

PDFAnnotation - PDFKit | Apple Developer Documentation

PDFAppearanceCharacteristics

これもアノテーション周りのAPIらしい。必要になったら調査。

Core Graphics

Core Graphics のPDF周りのAPIも少し追加になっている。

CGPDFDocumentGetAccessPermissions
CG_EXTERN CGPDFAccessPermissions CGPDFDocumentGetAccessPermissions(CGPDFDocumentRef document)
    CG_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);
typedef CF_OPTIONS(uint32_t, CGPDFAccessPermissions) {
    kCGPDFAllowsLowQualityPrinting    = (1 << 0),   // Print at up to 150 DPI
    kCGPDFAllowsHighQualityPrinting   = (1 << 1),   // Print at any DPI
    kCGPDFAllowsDocumentChanges       = (1 << 2),   // Modify the document contents except for page management
    kCGPDFAllowsDocumentAssembly      = (1 << 3),   // Page management: insert, delete, and rotate pages
    kCGPDFAllowsContentCopying        = (1 << 4),   // Extract content (text, images, etc.)
    kCGPDFAllowsContentAccessibility  = (1 << 5),   // Extract content, but only for the purpose of accessibility
    kCGPDFAllowsCommenting            = (1 << 6),   // Create or modify annotations, including form field entries
    kCGPDFAllowsFormFieldEntry        = (1 << 7)    // Modify form field entries
};

上記の様に PDFKit では取得出来ないプリント品質によるプリント許可ついての権限が取得出来る。

CGPDFDocumentGetOutline
CG_EXTERN __nullable CFDictionaryRef CGPDFDocumentGetOutline(CGPDFDocumentRef document)
    CG_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);

アウトライン情報の取得が出来る。 アウトラインの辞書情報には以下の情報が入っている。

  • Title - CFString型のタイトル
  • Children - CFArray of CFDictionaries型の子アウトライン情報の配列
  • Destination - CFNumber型のページ番号、または CFURL型のファイルURL
  • DestinationRect - Destination がページ番号の時のみリンク先を示す CFDictionary 型に変換された CGRect の座標
CG_EXTERN void CGPDFContextSetOutline(CGContextRef context, __nullable CFDictionaryRef outline)
  CG_AVAILABLE_STARTING(__MAC_10_13, __IPHONE_11_0);

PDFデータを作成する際にこのアウトライン情報を書き込む事も出来るらしい。
この2つの Core Graphics API は iOS だけでなく macOS でも初出のAPIとなっている。

まとめ

PDFKit 最高、使いましょう。