Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
はじめてのPDFKit.pdf
Search
shoma.kato
April 28, 2025
Programming
250
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
はじめてのPDFKit.pdf
shoma.kato
April 28, 2025
More Decks by shoma.kato
See All by shoma.kato
体験!SwiftChartsの世界
shomakato
0
29
動画エフェクトに関する新技術の紹介
shomakato
0
34
はじめてのPDFKit
shomakato
0
60
SwiftとC++を利用した画像処理プログラミング
shomakato
0
2.5k
Other Decks in Programming
See All in Programming
コードレビューのボトルネックを"する側"と"される側"の両面から解消する
yub0n
2
1.5k
気持ちぃ〜角丸 Squircle
ryu1013
0
190
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
1
430
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
160
contenteditable と日本語入力に向き合う
colorful12
0
180
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
370
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
140
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
600
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
490
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
280
Ghostty + Neovimで作る 透明でカッコ良い開発環境
j341nono
0
160
SREの越境 / SRE Collaboration
y0hgi
2
300
Featured
See All Featured
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
450
Java REST API Framework Comparison - PWX 2021
mraible
34
9.8k
The #1 spot is gone: here's how to win anyway
tamaranovitovic
4
1.2k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
250
1.3M
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
740
Un-Boring Meetings
codingconduct
0
450
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
2
360
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
Skip the Path - Find Your Career Trail
mkilby
1
250
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
560
How to build an LLM SEO readiness audit: a practical framework
nmsamuel
2
940
HDC tutorial
michielstock
2
950
Transcript
͡ΊͯͷPDFKit Ճ౻ਅ
2 גࣜձࣾZOZO Ճ౻ ਅ • X: @shoma10170806 • 20234݄: ZOZOೖࣾʢ3ʣ
• γϣοϓελοϑͷൢചαϙʔτπʔϧ ʮFAANSʯͷiOSΞϓϦΛ։ൃ • ത࢜ޙظ՝ఔʹࡏֶதɹը૾ॲཧͳͲͷݚڀʹैࣄ
3 FAANSͷ৽ػೳ ɾPDFͷදࣔػೳ - ཱͭใͷදࣔ - ֦େɾॖখ - ϖʔδ൪߸ͷදࣔ
4 FAANSͷ৽ػೳ ɾPDFͷදࣔػೳ - ཱͭใͷදࣔ - ֦େɾॖখ - ϖʔδ൪߸ͷදࣔ
5 FAANSͷ৽ػೳ ɾPDFͷදࣔػೳ - ཱͭใͷදࣔ - ֦େɾॖখ - ϖʔδ൪߸ͷදࣔ
6 FAANSͷ৽ػೳ PDFදࣔ: PDFKit ɾPDFͷදࣔػೳ - ཱͭใͷදࣔ - ֦େɾॖখ -
ϖʔδ൪߸ͷදࣔ
7 Section1: PDFKitΛ༻͍ͨදࣔ Section2: ϖʔδ൪߸ͷߋ৽
8 Section1: PDFKitΛ༻͍ͨදࣔ Section2: ϖʔδ൪߸ͷߋ৽
9 PDFDocumentͷಡΈࠐΈ Section1: PDFKitΛ༻͍ͨදࣔ extension URLSession { func data(with url:
URL) async throws -> (Data, URLResponse) { try await data(from: url) } } private func loadPdfDocument() async { var pdfDocument: PDFDocument? do { let (data, _) = try await URLSession.shared.data(with: pdfUrl) if let document = PDFDocument(data: data), document.pageCount > 0 { self.pdfDocument = document } } catch { // ಡΈࠐΈΤϥʔͷ߹ } }
private func loadPdfDocument() async { var pdfDocument: PDFDocument? do {
let (data, _) = try await URLSession.shared.data(with: pdfUrl) if let document = PDFDocument(data: data), document.pageCount > 0 { self.pdfDocument = document } } catch { // ಡΈࠐΈΤϥʔͷ߹ } } 10 PDFDocumentͷಡΈࠐΈ Section1: PDFKitΛ༻͍ͨදࣔ pdfUrl: https:// xxx.pdf extension URLSession { func data(with url: URL) async throws -> (Data, URLResponse) { try await data(from: url) } }
private func loadPdfDocument() async { var pdfDocument: PDFDocument? do {
let (data, _) = try await URLSession.shared.data(with: pdfUrl) if let document = PDFDocument(data: data), document.pageCount > 0 { self.pdfDocument = document } } catch { // ಡΈࠐΈΤϥʔͷ߹ } } extension URLSession { func data(with url: URL) async throws -> (Data, URLResponse) { try await data(from: url) } } 11 PDFDocumentͷಡΈࠐΈ Section1: PDFKitΛ༻͍ͨදࣔ ɾdata͔ΒPDFDocumentΛੜ ɾϖʔδ: 1Ҏ্
12 PDFͷදࣔ let pdfView = PDFView() pdfView.document = document pdfView.displayMode
= .singlePageContinuous pdfView.displayDirection = .vertical pdfView.autoScales = true pdfView.minScaleFactor = pdfView.scaleFactor ① PDFViewʹPDFDocumentͷૠೖ Section1: PDFKitΛ༻͍ͨදࣔ
13 PDFͷදࣔ ① PDFViewʹPDFDocumentͷૠೖ ② දࣔํ๏ͷઃఆ let pdfView = PDFView()
pdfView.document = document pdfView.displayMode = .singlePageContinuous pdfView.displayDirection = .vertical pdfView.autoScales = true pdfView.minScaleFactor = pdfView.scaleFactor Section1: PDFKitΛ༻͍ͨදࣔ
let pdfView = PDFView() pdfView.document = document pdfView.displayMode = .singlePageContinuous
pdfView.displayDirection = .vertical pdfView.autoScales = true pdfView.minScaleFactor = pdfView.scaleFactor 14 PDFͷදࣔ ① PDFViewʹPDFDocumentͷૠೖ ② දࣔํ๏ͷઃఆ ③ PDFͷαΠζΛࣗಈͰௐ Section1: PDFKitΛ༻͍ͨදࣔ
let pdfView = PDFView() pdfView.document = document pdfView.displayMode = .singlePageContinuous
pdfView.displayDirection = .vertical pdfView.autoScales = true pdfView.minScaleFactor = pdfView.scaleFactor 15 PDFͷදࣔ ① PDFViewʹPDFDocumentͷૠೖ ② දࣔํ๏ͷઃఆ ④ ॖখαΠζͷ࠷খͷܾఆ ③ PDFͷαΠζΛࣗಈͰௐ Section1: PDFKitΛ༻͍ͨදࣔ
let pdfView = PDFView() pdfView.document = document pdfView.displayMode = .singlePageContinuous
pdfView.displayDirection = .vertical pdfView.autoScales = true pdfView.minScaleFactor = pdfView.scaleFactor 16 PDFͷදࣔ ① PDFViewʹPDFDocumentͷૠೖ ② දࣔํ๏ͷઃఆ ④ ॖখαΠζͷ࠷খͷܾఆ ③ PDFͷαΠζΛࣗಈͰௐ Section1: PDFKitΛ༻͍ͨදࣔ
17 ॳظঢ়ଶʹ͓͚ΔPDFදࣔҐஔͷζϨ ॳظදࣔʢζϨʣ ਖ਼ৗ ζϨ Section1: PDFKitΛ༻͍ͨදࣔ
18 ζϨ ɾζϨͷݪҼ - PDFͷαΠζ - தԝἧ͑ Section1: PDFKitΛ༻͍ͨදࣔ ॳظঢ়ଶʹ͓͚ΔPDFදࣔҐஔͷζϨ
ਖ਼ৗ ॳظදࣔʢζϨʣ
19 ζϨ ɾζϨͷݪҼ - PDFͷαΠζ - தԝἧ͑ Section1: PDFKitΛ༻͍ͨදࣔ ॳظঢ়ଶʹ͓͚ΔPDFදࣔҐஔͷζϨ
ॳظঢ়ଶ: PDFࠨ্͕ը໘ ਖ਼ৗ ॳظදࣔʢζϨʣ
20 ζϨͷվળํ๏ if let firstPage = document.page(at: 0) { pdfView.go(
to: firstPage.bounds(for: pdfView.displayBox), on: firstPage ) } Section1: PDFKitΛ༻͍ͨදࣔ
21 if let firstPage = document.page(at: 0) { pdfView.go( to:
firstPage.bounds(for: pdfView.displayBox), on: firstPage ) } ① PDFDocumentͷ1ϖʔδΛऔಘ ② 1ϖʔδͷࠨ্͕දࣔ͞ΕΔΑ͏ʹҠಈ Section1: PDFKitΛ༻͍ͨදࣔ ζϨͷվળํ๏
22 Section1: PDFKitΛ༻͍ͨදࣔ Section2: ϖʔδ൪߸ͷߋ৽
23 ϖʔδ൪߸ͷදࣔ ࠨଆ: ݱࡏͷϖʔδ൪߸ ӈଆ: ૯ϖʔδ
24 ϖʔδ൪߸ͷऔಘํ๏ let document: PDFDocument? let pdfView = PDFView() let
totalPage = document.pageCount NotificationCenter.default .addObserver(forName: .PDFViewPageChanged, object: pdfView, queue: .main) { _ in Task { @MainActor in let pageNumber = pdfView.currentPage?.pageRef?.pageNumber } } ࠨଆ: ݱࡏͷϖʔδ൪߸ ӈଆ: ૯ϖʔδ ① ૯ϖʔδͷऔಘ
25 ϖʔδ൪߸ͷऔಘํ๏ let document: PDFDocument? let pdfView = PDFView() let
totalPage = document.pageCount NotificationCenter.default .addObserver(forName: .PDFViewPageChanged, object: pdfView, queue: .main) { _ in Task { @MainActor in let pageNumber = pdfView.currentPage?.pageRef?.pageNumber } } ࠨଆ: ݱࡏͷϖʔδ൪߸ ӈଆ: ૯ϖʔδ ① ૯ϖʔδͷऔಘ ② ϖʔδͷมߋࢹɾ൪߸औಘ
26 ϖʔδ൪߸ͷऔಘํ๏ let document: PDFDocument? let pdfView = PDFView() let
totalPage = document.pageCount NotificationCenter.default .addObserver(forName: .PDFViewPageChanged, object: pdfView, queue: .main) { _ in Task { @MainActor in let pageNumber = pdfView.currentPage?.pageRef?.pageNumber } } ࠨଆ: ݱࡏͷϖʔδ൪߸ ӈଆ: ૯ϖʔδ ① ૯ϖʔδͷऔಘ ② ϖʔδͷมߋࢹɾ൪߸औಘ
27 ϖʔδ൪߸औಘͷ ɾԣͷPDF - ը໘্ʹෳຕͷPDF - ϖʔδ൪߸: 2͔Βදࣔ͞ΕΔ ॳظঢ়ଶ: ϖʔδ൪߸Λ1ʹ͢Δ
※ Πϝʔδը૾
28 ॳظঢ়ଶͷఆํ๏ ɾoffset͕0: ϖʔδ൪߸1 PDFView: offsetऔಘͰ͖ͳ͍
29 ॳظঢ়ଶͷఆํ๏ UIScrollView extension PDFView { func scrollView() -> UIScrollView?
{ return self.subviews.compactMap { $0 as? UIScrollView }.first } } ɾoffset͕0: ϖʔδ൪߸1 PDFView: offsetऔಘͰ͖ͳ͍ ϫʔΫΞϥϯυ
30 ॳظঢ়ଶͷఆํ๏ if let scrollView = pdfView.scrollView() { scrollView.publisher(for: \.contentOffset)
.sink { [weak pdfView] contentOffset in Task { @MainActor in guard let pdfView = pdfView else { return } if contentOffset.y <= 0.0 { currentPage = 1 } else if let pageNumber = pdfView.currentPage?.pageRef?.pageNumber, pageNumber != currentPage { NotificationCenter.default.post( name: .PDFViewPageChanged, object: pdfView ) } } } } ① UIScrollViewͷݕग़ ② offSetͷpublisherΛൃߦ
if let scrollView = pdfView.scrollView() { scrollView.publisher(for: \.contentOffset) .sink {
[weak pdfView] contentOffset in Task { @MainActor in guard let pdfView = pdfView else { return } if contentOffset.y <= 0.0 { currentPage = 1 } else if let pageNumber = pdfView.currentPage?.pageRef?.pageNumber, pageNumber != currentPage { NotificationCenter.default.post( name: .PDFViewPageChanged, object: pdfView ) } } } } 31 ॳظঢ়ଶͷఆํ๏ ③ ϖʔδ൪߸ͷߋ৽ ① UIScrollViewͷݕग़ ② offSetͷpublisherΛൃߦ
if let scrollView = pdfView.scrollView() { scrollView.publisher(for: \.contentOffset) .sink {
[weak pdfView] contentOffset in Task { @MainActor in guard let pdfView = pdfView else { return } if contentOffset.y <= 0.0 { currentPage = 1 } else if let pageNumber = pdfView.currentPage?.pageRef?.pageNumber, pageNumber != currentPage { NotificationCenter.default.post( name: .PDFViewPageChanged, object: pdfView ) } } } } 32 ॳظঢ়ଶͷఆํ๏ ③ ϖʔδ൪߸ͷߋ৽ ① UIScrollViewͷݕग़ ② offSetͷpublisherΛൃߦ
if let scrollView = pdfView.scrollView() { scrollView.publisher(for: \.contentOffset) .sink {
[weak pdfView] contentOffset in Task { @MainActor in guard let pdfView = pdfView else { return } if contentOffset.y <= 0.0 { currentPage = 1 } else if let pageNumber = pdfView.currentPage?.pageRef?.pageNumber, pageNumber != currentPage { NotificationCenter.default.post( name: .PDFViewPageChanged, object: pdfView ) } } } } 33 ॳظঢ়ଶͷఆํ๏ ③ ϖʔδ൪߸ͷߋ৽ ① UIScrollViewͷݕग़ ② offSetͷpublisherΛൃߦ
34 ϖʔδ൪߸ͷදࣔ݁Ռ ※දࣔ͞Ε͍ͯΔPDFΠϝʔδͰ͢
35 ·ͱΊ ɾPDFKitͷ͍ํ ɹ- PDFKitΛ༻͍ͨPDFදࣔ ɹ- ϖʔδ൪߸ͷߋ৽