WWDC Quick Look 💓 By SwiftGGTeam
What's new in PDFKit

What's new in PDFKit

元の動画を見る

ハイライト

iOS 16 および macOS Ventura 用の PDFKit は、PDF のスキャン、CGImage からの PDF ページの作成、各ページのインタラクティブなオーバーレイ ビューのインストール、および PencilKit 描画の PDF 注釈としての保存のためのオンデマンド Live Text をサポートしています。


主要内容

多くのドキュメント アプリも同じ問題を抱えています。PDF はページの表示とめくりを担当しますが、ユーザーがやりたいことはますますエディターに似てきています。

スキャンされた文書内のテキストは選択可能である必要があります。フォームに記入する必要があります。写真は PDF ページに変換できる必要があります。ユーザーが Apple Pencil でページ上に描いた注釈は、ファイルを閉じた後も残ります。

以前は、追加の PDF コンテンツを描画するには、通常、サブクラス化が必要でした。PDFPage描画メソッドをオーバーライドするか、カスタム メソッドを直接作成します。PDFAnnotation。このアプローチは 1 回限りの引き分けに近いです。これは、ズーム可能でジェスチャー応答性があり、リアルタイムで編集可能なビューをページ上に配置するのには適していません。

(04:18) iOS 16 と macOS Ventura は PDFKit にオーバーレイ ビューを追加します。PDFKit は、ページが表示される前にアプリからビューをリクエストし、ページ サイズに制限し、ページの回転を処理します。アプリは 1 つだけ返す必要がありますUIViewまたはNSView

これにより、PencilKit の使用が簡単になります。PKCanvasView。ユーザーが線を描くとき、​​彼または彼女はライブビューを描いていることになります。ページがスクロールして画面から消えたら、PKDrawingカスタマイズをセーブバックするPDFPage。ファイルを保存するときに、これらの図面を注釈に変換します。


詳細

PDFKit の 4 つのコア オブジェクト

(00:54) このセッションでは、最初に PDFKit オブジェクト モデルを確認します。PDFViewインターフェイスに配置され、テキストの表示、移動、ズーム、コピーを担当します。PDFDocumentPDF ファイル全体を表します。PDFPage各ページを表します。PDFAnnotationページへのインタラクティブな追加です。

// 概念例であり、完全な API シグネチャではありません
let pdfView = PDFView()
let document = PDFDocument(url: fileURL)
pdfView.document = document
let page = document?.page(at: 0)
let annotations = page?.annotations

キーポイント:

  • PDFViewレイアウトに配置されたビューオブジェクトであり、SwiftUIに渡すことができます。UIViewRepresentableアクセス。
  • PDFDocumentルートオブジェクトです。ドキュメントには複数のページが含まれます。
  • page(at:)単一のページを取り出してみると、そのページはコンテンツのレンダリングとページのリソースの保存を担当します。
  • annotationsこれは、後続の保存プロセスで PencilKit 描画をホストするために使用される、ページ上の編集可能な追加オブジェクトです。

ライブテキストおよびフォーム認識

(02:08) PDFKit が Live Text をサポートするようになりました。ユーザーは、スキャンした PDF が単なるビットマップであり、テキスト レイヤーがない場合でも、その PDF 内のテキストを選択して検索できます。

PDF には多くのページが含まれる場合があります。PDFKit は、ドキュメントを開いたときにすべてのページで OCR を実行しません。ユーザーがページを操作すると、オンデマンドでページが処理されます。OCR は元のドキュメント上でその場で実行されるため、ファイルをコピーする必要はありません。保存するときに、文書全体の認識されたテキストを保存することも選択できます。

(02:58) フォーム処理も更新されました。PDFKit は、元の PDF にテキスト フィールドが組み込まれていない場合でも、ドキュメント内のフォーム フィールドを自動的に認識します。ユーザーは Tab を使用してフィールド間を移動し、テキストを入力できます。

// PDFView でドキュメントを開くと、Live Text とフォーム認識は PDFKit によって提供されます。
// ここでは追加の有効化スイッチはなく、この例は PDFKit の接続位置だけを示しています。
let pdfView = PDFView()
pdfView.document = PDFDocument(url: scannedPDFURL)

キーポイント:

  • PDFViewここでユーザーが PDF ページを操作し、Live Text の選択と検索が行われます。
  • PDFDocument(url:)ロードされるファイルはスキャンされた PDF である場合があります。セッションは、サンプル ドキュメントにテキスト レイヤーがないことを明示的に示しています。
  • Live Text の OCR は、大きな文書を開いたときにすべてのページが一度に処理されることを避けるために、ページごとにオンデマンドで実行されます。
  • フォームフィールド認識も PDFKit によって処理され、Web フォームに近いキーボードジャンプエクスペリエンスをユーザーに提供します。

画像から PDF ページを作成する

(03:14) iOS 16 と macOS Ventura は、画像から PDF ページを作成するための新しい API を提供します。使用する画像を入力してくださいCGImageRef, PDFKit は、高品質の JPEG エンコードを使用して画像を圧縮します。

このパスは、スキャン、写真の撮影とアーカイブ、および写真の PDF への整理を行うアプリに適しています。なぜならCGImageRefこれは CoreGraphics ネイティブ タイプであり、アプリは最初に画像を中間形式に変換する必要はありません。

// 概念例であり、API シグネチャではありません。デモ session で言及された入力とオプションを示します。
let sourceImage: CGImage = scannedImage
let pageOptions = [
    "MediaBox": pageSize,
    "Rotation": pageRotation,
    "UpscaleIfSmaller": true,
]
let pdfPage = PDFPage(image: sourceImage, options: pageOptions)

キーポイント:

  • sourceImage使用CGImage、のトランスクリプトに対応CGImageRef入力。
  • MediaBoxページ サイズを決定します。画像をフィットさせることも、レターなどの用紙サイズを選択することもできます。
  • Rotation縦方向または横方向を指定するために使用されます。
  • UpscaleIfSmaller小さな画像もページ全体に拡大されることを示します。大きな画像もページに合わせて縮小されます。
  • この段落は概念的な例であり、公式の抜粋ではありません。セッションでは完全な Swift 署名が得られません。

PDFPageOverlayViewProvider を使用して対話型ビューをインストールする

(05:47) オーバーレイビューへの入り口は次のとおりです。PDFPageOverlayViewProvider。最も重要な方法は、overlayViewFor page。PDFKit が特定のページを表示する必要がある場合、このメソッドを呼び出してビューをリクエストします。

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)
    }
}

キーポイント:

  • Coordinator成し遂げるPDFPageOverlayViewProvider、これは PDFKit がオーバーレイ ビューを要求するオブジェクトです。
  • pageToViewMappingバンドルPDFPageすでに作成されたものにマッピングされるUIView、同じページにキャンバスを繰り返し作成することを避けるため。
  • overlayViewFor page最初にキャッシュを確認し、キャッシュがない場合は新しいキャッシュを作成しますPKCanvasView
  • drawingPolicy = .anyInput鉛筆または指で入力できます。
  • PKInkingTool(.pen, color: .systemYellow, width: 20)例では黄色のブラシを設定します。
  • backgroundColor = UIColor.clearPDF ページのコンテンツを際立たせます。
  • MyPDFPage例の中にあるよPDFPageサブクラス、1 つだけ追加drawing財産。
  • willEndDisplayingOverlayViewページがスクロールして表示されなくなると呼び出されます。PKCanvasView.drawingページを再度保存し、キャッシュされたビューを削除します。

PencilKit 図面を PDF 注釈に保存

(09:28) オーバーレイ ビューは、画面上のインタラクションのみを解決します。ファイルを保存すると、図面も PDF に書き戻されます。

PDF 注釈には、これに役立つ 2 つの機能があります。まず、Adobe Reader や Chrome などのリーダーで一貫した表示を保証するための PDF 描画コマンド ストリームである外観ストリームを持つことができます。次に、辞書の形式で保存され、秘密キー/値データを配置して、次回開いたときに編集状態を復元できます。

// 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()
    }
}

キーポイント:

  • MyPDFAnnotation継承するPDFAnnotation、目的は描画動作をオーバーライドすることです。
  • draw(with:in:)PDFKit が注釈の外観ストリームを保存するときに呼び出されます。
  • UIGraphicsPushContext(context)Core Graphics コンテキストを UIKit 描画環境に接続します。
  • context.saveGState()そしてrestoreGState()外部の描画状態が汚染されないように、カスタム描画をラップします。
  • self.page as! MyPDFPage回収テープdrawingプロパティのカスタム ページ。
  • drawing.image(from:scale:)バンドルPKDrawing画像にレンダリングされます。
  • image.draw(in:)注釈の境界内に画像を描画します。

注釈を保存し、焼き付けるかどうかを選択します

(10:35) の例UIDocumentcontents(forType:)すべてのページを閲覧します。描画のあるすべてのページにカスタムの注釈が付けられます。絵を描くこと自体に対してNSKeyedArchiverエンコード後、アノテーションの秘密鍵を書き込みます。

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()
}

キーポイント:

  • contents(forType:)はいUIDocument内容を書く場所。
  • 0...pdfDocument.pageCount-1すべての PDF ページに目を通します。
  • (page as! MyPDFPage).drawingすでに PencilKit 描画が含まれているページのみを処理します。
  • MyPDFAnnotation(bounds:forType:withProperties:)カスタム アノテーションを作成します。タイプの例は次のとおりです。.stamp
  • NSKeyedArchiver.archivedDataバンドルPKDrawing次回開いた後に往復編集を再開できるようにデータにエンコードします。
  • setValue(_:forAnnotationKey:)秘密キーを使用するdrawingData描画データを保存します。
  • page.addAnnotation(newAnnotation)ページに注釈を付けます。
  • dataRepresentation()書き込み可能な PDF データを返します。受信者は注釈を移動、拡大縮小、削除することができます。
  • burnInAnnotationsOption: true注釈はページ コンテンツに焼き付けられます。これは、受信者に注釈の編集を続けてほしくないファイルに適しています。

PDF の書き込み量とネットワーク負荷を制御する

(11:50) iOS 16 と macOS Ventura では、さらに多くの PDF 書き込みオプションも開かれています。

デフォルトでは、CoreGraphics はフル解像度と可逆圧縮を使用して画質を維持しようとします。これは大きな印刷には問題ありませんが、ファイルが画面で読み取るには大きすぎる可能性があります。saveAllImagesAsJPEG画像はJPEGエンコードで保存されます。optimizeImagesForScreen画像は HiDPI 画面解像度制限までダウンサンプリングされます。両方を一緒に使用できます。

12:41createLinearizedPDFネットワーク読み込みに適した線形化された PDF を作成するために使用されます。最初のページを表示するために必要なデータがファイルの先頭に配置されるため、ブラウザーは最初に最初のページを表示し、その後残りのコンテンツの読み込みを続けることができます。

// 概念例であり、完全な API シグネチャではありません。session では、これらのオプションを dataRepresentation または writeToURL に渡すと説明しています。
let options = [
    "saveAllImagesAsJPEG": true,
    "optimizeImagesForScreen": true,
    "createLinearizedPDF": true,
]
let data = pdfDocument.dataRepresentation(options: options)

キーポイント:

  • saveAllImagesAsJPEG大量の画像を含む PDF ファイルのサイズを縮小するのに適しています。
  • optimizeImagesForScreen画面読み取りの場合、高解像度画像のコストが削減されます。
  • createLinearizedPDFネットワーク配信シナリオにおける最初の画面の表示速度を向上させます。
  • これらの書き出しオプションは、PDFDocumentdataRepresentationまたはwriteToURL
  • この段落は概念的な例です。セッションのみが提供しますburnInAnnotationsOption完全なSwiftの書き方。

重要ポイント

  1. PDF をスキャンするためのテキスト検索ツールを作成します
  • 何をすべきか: スキャンを開いた後、ユーザーがスキャン内のテキストを直接検索できるようにします。
  • 実行する価値がある理由: PDFKit は、テキスト レイヤーなしで PDF をスキャンするためのオンデマンド Live Text を提供します。ドキュメントを開くときにアプリでドキュメント全体を OCR する必要はありません。
  • 開始方法: を使用しますPDFView負荷PDFDocument、インタラクティブなエントリをページビューに配置し、保存時に認識されたテキストを保存するためのパスを指定します。
  1. 画像を PDF に変換するためのアーカイブ ツールを作成します
  • 対処方法: 写真またはインポートした画像を固定用紙サイズの PDF に整理します。
  • 実行する価値がある理由: 新しい API を直接使用するCGImageRef, PDFKit は JPEG 圧縮を担当し、ページ サイズ、向き、小さな画像の拡大などのオプションを提供します。
  • 開始方法: スキャンした画像を名前を付けて保存しますCGImage、各ページにMediaBox、Rotation、UpscaleIfSmallerを設定し、それらを結合します。PDFDocument
  1. Apple Pencil 注釈を備えた PDF リーダーを作成します
  • 内容: ユーザーは PDF をめくりながら、ページ上に直接手書きの注釈を付けることができます。
  • 実行する価値がある理由:PDFPageOverlayViewProviderページごとにオーバーレイを許可するPKCanvasView, PDFKit は、オンデマンドで作成、レイアウト、回転を処理します。
  • 開始方法: 実装overlayViewFor page戻るPKCanvasView、存在するwillEndDisplayingOverlayViewミドルハンドルPKDrawingカスタマイズをセーブバックするPDFPage
  1. 編集可能なPDFアノテーション保存処理を作成
  • 対処方法: 手書きの注釈を保存すると、次回開いたときに編集を続けることができます。
  • 実行する価値がある理由: PDF 注釈は外観ストリームを保存でき、秘密キー/値を使用して元のファイルを保存することもできます。PKDrawingデータ。
  • 開始方法: サブクラス化PDFAnnotationリライトdraw(with:in:)、保存するときPKDrawingにエンコードするdrawingDataをクリックし、オーバーレイ ビューを開いたときにそれを読み返します。
  1. Web 配布に適した PDF エクスポート オプションを作成
  • 対処方法: 「小さいファイル」、「画面に合わせる」、「Web ページのプレビューに合わせる」などのエクスポート スイッチをユーザーに提供します。
  • 実行する価値がある理由: PDFKit の JPEG、画面最適化、線形化 PDF 書き込みオプションは、それぞれサイズ、画面読み取り、最初の画面読み込みに対応しています。
  • 開始方法: エクスポート パネルのこれらのオプションを次のようにマッピングします。PDFDocumentdataRepresentationまたはwriteToURLパラメータを書き込みます。

関連セッション

  • Live Text インタラクションをアプリに追加 — Live Text を静止画像や一時停止したビデオ フレームに接続し、PDFKit のスキャンされた PDF テキスト インタラクションを補完する方法について説明します。
  • VisionKit を使用して機械可読コードとテキストをキャプチャする - VisionKit がリアルタイムのカメラ映像からテキストとコードをキャプチャする方法を示します。これは、システムのテキスト認識機能を理解するためのもう 1 つのエントリ ポイントです。
  • Vision の新機能 - Vision のテキスト認識、バーコード検出、およびタスク デバッグの更新を紹介します。これは、Live Text の背後にある認識機能に関連する背景です。
  • UIKit で SwiftUI を使用する — UIKit ビューと SwiftUI の組み合わせについて説明します。PDFViewSwiftUIアプリに接続する際の参考に。

コメント

GitHub Issues · utterances