Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
はじめてのPDFKit.pdf
Search
shoma.kato
April 28, 2025
Programming
230
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
26
動画エフェクトに関する新技術の紹介
shomakato
0
29
はじめてのPDFKit
shomakato
0
52
SwiftとC++を利用した画像処理プログラミング
shomakato
0
2.5k
Other Decks in Programming
See All in Programming
Claude Team Plan導入・ガイド
tk3fftk
0
220
act2-costs.pdf
sumedhbala
0
120
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.7k
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
220
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
180
광주소프트웨어마이스터고등학교 DevFest 특강 - 바이브 코딩 시대에서 주니어 개발자로 살아남는 방법
utilforever
1
150
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
110
【やさしく解説 設計編 #1】「ドメイン駆動」と「実装駆動」ってなに? 〜設計の考え方を、たとえ話で学ぼう〜
panda728
PRO
1
120
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
270
OSINT for SRE: 学術論文とポストモーテムから探る システム障害の共通パターン / SRE NEXT 2026
tomoyk
1
4.1k
AI時代の仕事技芸論〜ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ(スクフェス仙台 2026バージョン)
kuranuki
0
680
Featured
See All Featured
Become a Pro
speakerdeck
PRO
31
6k
Visualization
eitanlees
152
17k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
How GitHub (no longer) Works
holman
316
150k
sira's awesome portfolio website redesign presentation
elsirapls
0
300
Java REST API Framework Comparison - PWX 2021
mraible
34
9.5k
Docker and Python
trallard
47
4k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
21
1.5k
Amusing Abliteration
ianozsvald
1
240
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
270
Music & Morning Musume
bryan
47
7.3k
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
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දࣔ ɹ- ϖʔδ൪߸ͷߋ৽