View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

WWDC22に戻る

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • コード
  • PDFKitの新機能

    PDFKitはあなたのAppに、PDFドキュメントの表示・編集・保存の機能を提供するフル機能のフレームワークです。Live Textやフォームのサポート、画像からのPDF作成、インタラクティブオーバーレイの構築、注釈の保存など、PDFKitの最新機能を紹介します。

    リソース

    • PDFAnnotationWidgetsAdvanced
      • HDビデオ
      • SDビデオ

    関連ビデオ

    WWDC22

    • WWDC22 Day 4 recap

    WWDC19

    • PencilKitの紹介
  • このビデオを検索

    Conrad Carlenです PDFKitの新機能についてお話します 議題はこちら まずPDFKitの簡単なおさらい 次にLive Textとフォームなどの新機能 画像からPDFを作成する 新しい方法 最後にオーバーレイビューについて まずPDFKitの機能を見直してみましょう PDFKitはAppのフレームワークで 閲覧や編集を可能にします iOSやmacOS Mac Catalystで利用でき UIViewをAppに組み込むためのラッパーである UIViewRepresentableを使って SwiftUIで使用することも可能です PDFKitは機能のほとんどをカバーする 4つのコアクラスで構成されます PDFViewはSwiftUIやIBを使って レイアウトするウィジェットです PDFドキュメントのコンテンツを表示し ズーム設定やテキストのコピーも可能

    PDFDocumentはPDFファイルを表します 通常サブクラス化しませんが 必ず使うクラスで PDFオブジェクトグラフのルート またはツリーの幹です これらのいずれかがツリーの作成に必須です

    各ドキュメントには1つか複数の PDFPageオブジェクトを含みます コンテンツをレンダリングし そのページに固有のフォントや画像などの リソースを保存します

    オブジェクトグラフの葉の部分には PDFAnnotationsのオプションもあります PDFPageは編集を目的としませんが 注釈は多くの場合編集可能です 各オブジェクトの役割も説明します PDFKitの基本について詳しく知るには 下にリンクされている "Introducing PDFKit" のセッションをご覧ください

    ではiOS16とVenturaで導入された 新機能について

    PDFKitはLive Textをサポートします これはタップしてコピーできるテキストが 少量である写真Appとは異なります 写真と違って PDFで文字が表示されれば テキストとして扱えることが期待されます Live Textを使ってPDF文書内の文字列を選択し 検索できるようになりました これはビットマップをスキャンしただけのもので テキストはまったくありません

    もちろんPDFは多くのページを持てるので PDF文書を開いたときに 全ページにOCRを適用するのではなく PDFKitは各ページを操作するときに オンデマンドで実行します OCRはそのファイルに適用されるので 文書のコピーを作成する必要はありません 文書全体のテキストを保存したい場合は 保存時にそのオプションがあります

    さらにPDFKitはフォーム処理を改善しました フォームフィールドを含む文書は テキストフィールドが組み込まれていなくても 自動的に認識されます テキストフィールドをタブで移動して 期待通りにテキストを入力できます

    次は画像からPDFを作成するための 新APIについて説明します

    iOS16とmacOS Venturaには 画像を入力としてPDFを作成できる 柔軟な新らしいAPIを用意しました AppはCGImageRefで画像を提供します PDFKitはCGImageRefを受け取り 高品質のJPEGエンコーディングで圧縮します CGImageRefはCoreGraphicsの ネイティブデータ型なので 追加の変換は不要です

    最も一般的なケースを処理するのに役立つ いくつかのオプションがあります

    MediaBoxでページの大きさを指定 画像に合わせるか用紙サイズを選択できます

    縦向きや横向きの指定もできます

    画像がMediaBox より大きい場合 MediaBoxに収まるよう 画像を縮小します UpscaleIfSmallerが指定されている場合 画像がMediaBoxより小さい時は ページ全体に拡大されます

    多く寄せられた質問にお答えします 「PencilKitでPDFに描画するには?」 オーバーレイビューを使用します

    以前はPDFPageをサブクラス化し 描画メソッドをオーバーライドするか カスタムPDFアノテーションが必要でした iOS16とVenturaでは各PDFのページ上に 独自のビューをオーバーレイできます これでPDF上にインタラクティブな ライブビューを作成できます オーバーレイについて知っておくべき3点は まず新プロトコルによりオーバーレイビューを PDFページにインストールします

    コンテンツはPDFに組込んで保存します PDF文書を保存する際の ベストプラクティスについて紹介します

    オーバーレイビューのインストールは簡単です PDFは数百ページにもなる可能性もあるため 開く時にすべてのページのビューを 作成することはできません ユーザーが高速でスクロールした場合は? ビューをいつ作成するべきか知る方法は?

    PDFKitはページをスクロールして表示する前に コンテンツをインテリジェントに 準備するよう設計されています オーバーレイビューを要求する タイミングも万全です Appは新しいプロトコルによるリクエストに 応答する必要があるだけです

    PDFPageOverlayViewProviderが 新しいプロトコルです PDFKitPlatformViewは プラットフォームに応じて UIViewかNSViewとして定義されます 最も重要なメソッドはoverlayViewForPageです ビューのインスタンスを提供するだけで PDFKitは適切な制約を適用して そのサイズを調整します またページの回転がゼロ以外の場合は 回転させます

    次の2つのメソッドはオプションです willDisplayOverlayViewを使用して 独自のジェスチャーハンドラをインストールしたり PDFKitのジェスチャーとの衝突を 調整することができます

    willEndDisplayingOverlayViewはPDFKitが あなたのビューを終了したときに呼び出されます おそらくスクロールアウトされたためです ここでビューを解放することができますが このメソッドにはもう一つ重要な使い方があります 描画を表すデータがある場合はこのメソッドで データを取得しておくこともできます ここではPencilKitを使用していますが ビューデータが別の場所にある場合は これを実装する必要はありません

    これがこの例でプロバイダとして 使用しているクラスです PDFPageOverlayViewProviderプロトコルを 実装しています これはiOSなのでUIViewです PDFPage から UIView へは map を使用します プロトコルメソッドの宣言はこうなります 次に実装を見てみましょう overlayViewForPageはpageToViewMappingで ビューが作成済かどうかを確認します まだの場合は新しいビューを作成します いずれの場合もページからdrawingを取得して キャンバスビューに設定します ここではPDFPageのサブクラスを使っています drawingプロパティを追加するだけです

    次のメソッドを見てみましょう willEndDisplayingです

    OverlayViewはシンプルです ビューからdrawingを取得し カスタムページクラスに保存します 実際の動作を見てみます

    この時期にはいつも釣りをしますが 今年はWWDCですので 別の人が代わりに参加しているため お気に入りスポットを彼に 紹介したいと思います このAppではPencilKitを オーバーレイ表示で使用します 構成は今見たコード以外はごくわずかで オーバーレイを表示するためのコードは約30行です グランドレイクはダム湖なんですが たくさん魚がいる穴場ですね ここを下ると ダム湖に行って釣りができます あるいこの道を進んで ダムを越えてからここを通って 釣りすることもできます そこからここでも釣れます 一周してからの先には 間違っても行かないように 流れが急に深くなります ここは避けて 養魚場へ 養魚場の横を進んで この水場に移ると あちこちでキャスティングできます ここは穴場で私はいつもここで魚を釣っています

    さてルートが書けたので ズームとスクロールを実行してみましょう

    良いレスポンスですよね

    以上になります PDFKitのオーバーレイビューでした スケッチができたので次は保存についてです それにはPDFAnnotationクラスを使用します 保存するときに実現したいことは2つ 画面上の表示を 忠実に一致させることと ラウンドトリップ編集です PDFアノテーションにはこれを 容易にするいくつかの機能があり 「アピアランスストリーム」と呼ばれる PDFの描画コマンドのストリームを 持つことができます Quartz2Dで描画できるものは ほぼすべてを記録できます それ以外は画像にレンダリングして記録します Metalを使用している場合は画像で記録しています PDFの描画として記録されているため Adobe ReaderやChromeなどでも 同じように表示されます

    PDFの注釈はdictionaryとしてPDF文書に保存します カスタムデータをプライベートキーと値のペアで 保存することもできます どのようなコードになるのか見てみましょう PDFAnnotationのサブクラスの作成から始めます drawメソッドをオーバーライドする作業です PDFKitは前のスライドで説明した アピアランスストリームを保存するときに このメソッドを呼び出します

    ドキュメントを保存するためcontentsを上書きします 関数の概要を次に示します PDFDocumentのすべてのページをループします ループの中の処理は...

    各ページに対して次の作業を行います カスタムクラスのアノテーションを作成し drawingをデータにエンコードして データをアノテーションに追加します 次にこの文書を開くときに value:forAnnotationKey を使用して 保存されたdrawingデータを読み出し それをオーバーレイビューに配置します

    最後にページに注釈を追加します contentsのオーバーライドに戻ります ページに注釈を追加したので PDFDocumentのdataRepresentationで結果を返します

    コンテンツが注釈として保存されると コンテンツの移動やサイズ変更や削除も可能になります 望まれる機能ですね ページの一部として注釈を“焼き付け”たい場合 iOS16とmacOS Venturaには これを行うPDFDocumentWriteOptionが使えます 保存オプションに burnInAnnotationsOption=trueを 追加するだけです 処理はこれだけです

    PDF書き込みオプションと言えば iOS16とmacOSVenturaで 利用できるようになったもを 見ていくことにします CoreGraphicsは常に最高画質で 画像をPDFに保存するため 画像はロスレス圧縮でフル解像度です PDFが大判プリンターで 印刷される場合に最高です 画面に表示されることが多いPDFでは 忠実度の高い画像データをすべて保存すると ファイルサイズが非常に大きくなってしまいます これに対処するために 2つのオプションがあります

    saveAllImagesAsJPEGはその名のとおり 画像はすべてJPEGエンコーディングで PDFに保存します

    optimizeImagesForScreenは 画像をHiDPIスクリーンの解像度に ダウンサンプリングします これら2つのオプションは同時に使用できます

    createLinearizedPDFはインターネット用に 最適化された特別な種類のPDFを作成します インターネット登場前に設計されたPDF形式は ファイルの最後から読み取られます つまり表示する前に全体を ダウンロードする必要がありました 線形化されたPDFにはファイルの先頭に 最初のページの表示に必要な すべてが含まれており ブラウザーは残りの部分がロード中でも 表示できるようになっています

    これらのオプションはPDFDocument の dataRepresentation や writeToURL メソッドに 渡すことも可能です 以上になります PDFKitはパワフルで使いやすく iOSやmacOSの多くのAppで使われており iOS16とmacOSVenturaで 新機能も追加されました どんな風に使割れるか楽しみです

    詳細については以下のセッションを ご確認ください ご清聴ありがとうございます

    • 6:54 - Implementing the overlay protocol

      class Coordinator: NSObject, PDFPageOverlayViewProvider {
      
          var pageToViewMapping = [PDFPage: UIView]()
         
          func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? {
              var resultView: PKCanvasView? = nil
              
              if let overlayView = pageToViewMapping[page] {
                  resultView = overlayView
              } else {
                  let canvasView = PKCanvasView(frame: .zero)
                  canvasView.drawingPolicy = .anyInput
                  canvasView.tool = PKInkingTool(.pen, color: .systemYellow, width: 20)
                  canvasView.backgroundColor = UIColor.clear
                  pageToViewMapping[page] = canvasView
                  resultView = canvasView
              }
              
              // If we have stored a drawing on the page, set it on the canvas
              let page = page as! MyPDFPage
              if let drawing = page.drawing {
                  resultView?.drawing = drawing;
              }
              return resultView
          }
      
          func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView
              overlayView: UIView, for page: PDFPage) {
              let overlayView = overlayView as! PKCanvasView
              let page = page as! MyPDFPage
              page.drawing = overlayView.drawing
              pageToViewMapping.removeValue(forKey: page)
          }
      }
    • 10:22 - Create a subclass of PDFAnnotation

      // Implement a subclass with a drawing override
      
      class MyPDFAnnotation: PDFAnnotation {
          
          override func draw(with box: PDFDisplayBox, in context: CGContext) {
              UIGraphicsPushContext(context)
              context.saveGState()
              
              let page = self.page as! MyPDFPage
              if let drawing = page.drawing {
                  let image = drawing.image(from: drawing.bounds, scale: 1)
                  image.draw(in: drawing.bounds)
              }
              
              context.restoreGState()
              UIGraphicsPopContext()
          }
      }
    • 10:35 - Add annotations to your document when saving

      override func contents(forType typeName: String) throws -> Any {
              
          if let pdfDocument = pdfDocument {
            
              // Go through all pages in the document
              for i in 0...pdfDocument.pageCount-1 {
                  if let page = pdfDocument.page(at: i) {                       
                      if let drawing = (page as! MyPDFPage).drawing {
                              
                          // Create an annotation of our custom subclass
                          let newAnnotation = MyPDFAnnotation(bounds: drawing.bounds,
                                                              forType: .stamp, withProperties: nil)
                              
                          // Add our custom data
                          let codedData = try! NSKeyedArchiver.archivedData(withRootObject: drawing,
                                                                            requiringSecureCoding: true)
                          newAnnotation.setValue(codedData,
                                                 forAnnotationKey: PDFAnnotationKey(rawValue: "drawingData"))
                              
                          // Add our annotation to the page
                          page.addAnnotation(newAnnotation)
                      }
                  }
              }
      
              // -- Option #1: Save the document to a data representation
              if let resultData = pdfDocument.dataRepresentation() {
                  return resultData
              }
            
              // -- Option #2: Save the document to a data representation and "burn in" annotations
              let options = [PDFDocumentWriteOption.burnInAnnotationsOption: true]
              if let resultData = pdfDocument.dataRepresentation(options: options) {
                  return resultData
              }
          }
                      
          // Fall through to returning empty data
          return Data()
      }

Developer Footer

  • ビデオ
  • WWDC22
  • PDFKitの新機能
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン