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
240
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
33
はじめてのPDFKit
shomakato
0
57
SwiftとC++を利用した画像処理プログラミング
shomakato
0
2.5k
Other Decks in Programming
See All in Programming
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
250
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
320
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
560
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
500
thread_parallel_with_free-threaded_Python_and_NumPy.pdf
riku_sakamoto
0
350
AI活用は、個人から組織へ|マルチプレイヤーエージェントハーネス「QM」の社内活用事例 / AI use is moving from individuals to orgs
rkaga
1
140
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.2k
What We Talk About When We Talk About XP
m_seki
2
660
MVNOの申込からeSIM開通までをiOSアプリでつなぐ- 本人確認・MNP・通信事業者基盤をまたぐ実装
satotakeshi
0
450
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
810
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
180
そのリトライ、死んだコネクションを使い回していませんか ── GoのHTTPクライアントとHTTP/2を実プロダクト障害から学び直す
myus4a
0
200
Featured
See All Featured
Prompt Engineering for Job Search
mfonobong
0
450
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Optimizing for Happiness
mojombo
378
71k
WENDY [Excerpt]
tessaabrams
14
39k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
67
58k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Hiding What from Whom? A Critical Review of the History of Programming languages for Music
tomoyanonymous
3
1.2k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
Documentation Writing (for coders)
carmenintech
77
5.5k
A better future with KSS
kneath
240
18k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
2k
AI: The stuff that nobody shows you
jnunemaker
PRO
10
1.1k
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දࣔ ɹ- ϖʔδ൪߸ͷߋ৽