質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

Q&A

解決済

1回答

226閲覧

PDFPageOverlayViewProviderを利用したPKToolの変更の仕方が思いつかない

Gameno

総合スコア10

PDF

PDF(Portable Document Format)とはISOによって国際標準として制定されている電子ドキュメント用の拡張子です。

0グッド

0クリップ

投稿2024/04/25 08:07

編集2024/04/26 10:01

実現したいこと

swiftuiでPDFKitのPDFPageOverlayViewProviderを利用し、PDF上にPKCanvasViewをセットしています。
canvasに利用するペンや消しゴムを作るため、

swift

1canvasView.tool = PKInkingTool(.pen, width: 20)

の部分を変更したいのですが、うまくいきません。
どなたかお力をお貸しください。お願いします。
以下が全体のコードです。

swift

1import SwiftUI 2import PencilKit 3import PDFKit 4 5struct SwiftUIView: View { 6 7 var body: some View { 8 VStack { 9 HStack{ 10 Button(action: { 11 //ここがわからない 12 }, label: { 13 Text("ペン") 14 }) 15 Button(action: { 16 //ここがわからない 17 }, label: { 18 Text("消しゴム") 19 }) 20 21 } 22 PdfView() 23 } 24 } 25} 26 27struct PdfView : UIViewRepresentable { 28 typealias UIViewType = PDFView 29 30 let overlayProvider = OverlayCoordinator() 31 func makeUIView(context: Context) -> PDFView { 32 let pdfView: PDFView = PDFView() 33 if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") { 34 pdfView.pageOverlayViewProvider = overlayProvider 35 pdfView.document = PDFDocument(url: url) 36 pdfView.autoScales = true 37 pdfView.isInMarkupMode = true 38 } 39 return pdfView 40 } 41 func updateUIView(_ uiView: PDFView, context: Context) { 42 } 43} 44 45class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider { 46 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { 47 let canvasView = PKCanvasView() 48 canvasView.drawingPolicy = .anyInput 49 canvasView.tool = PKInkingTool(.pen, width: 1) //ここがtoolを定義しているところ 50 canvasView.backgroundColor = .clear 51 return canvasView 52 } 53} 54#Preview { 55 SwiftUIView() 56}

発生している問題・分からないこと

ボタンを押すことでPKToolを変更したい。
@publishedや@bindingで値を渡すことを考えたが、classではできなかった。

該当のソースコード

swiftui

1特になし

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

PDFPageOverlayViewProviderで検索すると、この位置にtoolを定義しているものしか見当たりませんでした。WWDC22を参照しているものが多いからだと思います。
WWDC22 PDFKitの新機能
PKToolPickerをこの位置に入力すると、ペンや消しゴムが使えるようにはなりますが、toolの表示・非表示がうまくいかなくなる問題が発生したことと、余計なツールが多かったので、今回は見送っています。

pdfViewのoverlayProviderにtoolを上書きしても、変更されませんでした。

補足

yametaiさんからいただいたコードの追記

swift

1import SwiftUI 2import PencilKit 3import PDFKit 4 5struct SwiftUIView: View { 6 @State private var isPen = true 7 var body: some View { 8 VStack { 9 HStack{ 10 Button(action: { 11 isPen = true 12 }, label: { 13 Text("ペン") 14 }) 15 Button(action: { 16 isPen = false 17 }, label: { 18 Text("消しゴム") 19 }) 20 21 } 22 PdfView(isPen: $isPen) 23 } 24 } 25} 26 27struct PdfView : UIViewRepresentable { 28 typealias UIViewType = PDFView 29 @Binding var isPen: Bool 30 let overlayProvider = OverlayCoordinator() 31 func makeUIView(context: Context) -> PDFView { 32 let pdfView: PDFView = PDFView() 33 if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") { 34 pdfView.pageOverlayViewProvider = overlayProvider 35 pdfView.document = PDFDocument(url: url) 36 pdfView.autoScales = true 37 pdfView.isInMarkupMode = true 38 } 39 return pdfView 40 } 41 func updateUIView(_ uiView: PDFView, context: Context) { 42 43 if isPen { 44 print("pen") 45 overlayProvider.setPen() 46 } else { 47 print("eraser") 48 overlayProvider.setEraser() 49 } 50 51 } 52} 53 54class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider { 55 var pageToViewMapping = [PDFPage: PKCanvasView]() //補足追加 56 var canvasView: PKCanvasView = PKCanvasView() 57 58 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { 59// let canvasView = PKCanvasView() 60 var resultView:PKCanvasView? = nil 61 // 編集・追加↓ 62 if let overlayView = pageToViewMapping[page] { 63 resultView = overlayView 64 } else { 65 let canvasView = PKCanvasView() 66 canvasView.drawingPolicy = .anyInput 67 canvasView.tool = PKInkingTool(.pen, width: 20) 68 canvasView.backgroundColor = .clear 69 pageToViewMapping[page] = canvasView 70 resultView = canvasView 71 } 72 return resultView 73 // 編集・追加↑ 74 } 75 func setPen() { 76 canvasView.tool = PKInkingTool(.pen, width: 1) 77 } 78 func setEraser() { 79 canvasView.tool = PKEraserTool(.bitmap) 80 } 81 82}

環境 macOS Ventura 13.6.6
xcode Version 15.2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yametai

2024/04/26 09:17

コメントありがとうございます。 > OverlayCoordinatoのcanvasView = PKCanvasView()をfunc外に出してしまうと、ペン自体が描けなくなってしまいます。 > この場合どの辺りに原因がありそうでしょうか? canvasViewをfuncの外に出しただけでは影響しないと思うのですが、描けないのですね。 もう一度全体のコードが見たいですので、質問欄に追加で(最初のコードは残したままで) 最新のコードも追記してもらえますか? それから、環境も質問欄に書いてあると良いと思います。 *私の環境は下のもので、少し古いかもしれません macOS Sonoma 14.4.1 Xcode Version 15.2
Gameno

2024/04/26 10:04 編集

コメントありがとうございます。 今確認中に気がついたのですが、PDFが2枚以上の場合に書けなくなるようです。 全体のコードは回答いただいたコードをそのままコピーして使用しました。 ただ、質問の見栄えを考えて少しコードを削りすぎていたので、回答いただいたコードに少し変更したものを補足に追記させていただきます。 追記したコードにより、初期設定のpenは書けるようになったものの,buttonは反映しなくなっていしまいました。
guest

回答1

0

ベストアンサー

次のような感じですか。

swift

1import SwiftUI 2import PencilKit 3import PDFKit 4 5struct SwiftUIView: View { 6 @State private var isPen = true // 追加 7 var body: some View { 8 VStack { 9 HStack{ 10 Button(action: { 11 //ここがわからない 12 isPen = true // 追加 13 }, label: { 14 Text("ペン") 15 }) 16 Button(action: { 17 //ここがわからない 18 isPen = false // 追加 19 }, label: { 20 Text("消しゴム") 21 }) 22 23 } 24 PdfView(isPen: $isPen) // 変更 25 } 26 } 27} 28 29struct PdfView : UIViewRepresentable { 30 typealias UIViewType = PDFView 31 @Binding var isPen: Bool // 追加 32 let overlayProvider = OverlayCoordinator() 33 func makeUIView(context: Context) -> PDFView { 34 let pdfView: PDFView = PDFView() 35 if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") { 36 pdfView.pageOverlayViewProvider = overlayProvider 37 pdfView.document = PDFDocument(url: url) 38 pdfView.autoScales = true 39 pdfView.isInMarkupMode = true 40 } 41 return pdfView 42 } 43 func updateUIView(_ uiView: PDFView, context: Context) { 44 // 追加↓ 45 if isPen { 46 print("pen") 47 overlayProvider.setPen() 48 } else { 49 print("eraser") 50 overlayProvider.setEraser() 51 } 52 // 追加↑ 53 } 54} 55 56class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider { 57 var canvasView: PKCanvasView = PKCanvasView() // 追加 58 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { 59// let canvasView = PKCanvasView() 60 canvasView.drawingPolicy = .anyInput 61 canvasView.tool = PKInkingTool(.pen, width: 1) //ここがtoolを定義しているところ 62 canvasView.backgroundColor = .clear 63 return canvasView 64 } 65 // 追加↓ 66 func setPen() { 67 canvasView.tool = PKInkingTool(.pen, width: 1) 68 } 69 func setEraser() { 70 canvasView.tool = PKEraserTool(.bitmap) 71 } 72 // 追加↑ 73}

参考

Section 4
Add a custom page control

Interfacing with UIKit — SwiftUI Tutorials | Apple Developer Documentation

追記

今確認中に気がついたのですが、PDFが2枚以上の場合に書けなくなるようです。
追記したコードにより、初期設定のpenは書けるようになったものの,buttonは反映しなくなっていしまいました。

コメントありがとうございます。
確かに、最初の回答のコードでは、私の環境でもPDF2枚で確認したら、1枚目はtoolの設定が反映されていないようでした。(1枚のPDFでしか確認していませんでした・・)
ページによってPKCanvasViewを用意しないといけないのですね。
勉強になります。

これらを踏まえて、辞書で保持しているPKCanvasViewに対して全部toolを設定するように変更したら、想定通りになったように見えました。
*OverlayCoordinatorの部分だけコードを追記します

swift

1class OverlayCoordinator : NSObject,PDFPageOverlayViewProvider { 2 var pageToViewMapping = [PDFPage: PKCanvasView]() //補足追加 3// var canvasView: PKCanvasView = PKCanvasView() // ***削除 4 5 func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { 6 // 編集・追加↓ 7 if let overlayView = pageToViewMapping[page] { 8 return overlayView 9 } 10 11 let canvasView = PKCanvasView() 12 canvasView.drawingPolicy = .anyInput 13 canvasView.tool = PKInkingTool(.pen, width: 20) 14 canvasView.backgroundColor = .clear 15 pageToViewMapping[page] = canvasView 16 return canvasView 17 // 編集・追加↑ 18 } 19 func setPen() { 20// canvasView.tool = PKInkingTool(.pen, width: 1) // ***削除 21 for i in pageToViewMapping { // ***追加 22 i.value.tool = PKInkingTool(.pen, width: 1) // ***追加 23 } // ***追加 24 } 25 func setEraser() { 26// canvasView.tool = PKEraserTool(.bitmap) // ***削除 27 for i in pageToViewMapping { // ***追加 28 i.value.tool = PKEraserTool(.bitmap) // ***追加 29 } // ***追加 30 } 31 32}

投稿2024/04/25 14:58

編集2024/04/26 11:11
yametai

総合スコア27

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gameno

2024/04/26 05:57

回答ありがとうございます。試してみましたが解決できませんでした。 OverlayCoordinatoのcanvasView = PKCanvasView()をfunc外に出してしまうと、ペン自体が描けなくなってしまいます。 この場合どの辺りに原因がありそうでしょうか?
Gameno

2024/04/26 12:50

試したところ問題が解決しました! ベストアンサーに選ばせていただきました。 ずっと悩んでいたので、本当に助かりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問