Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
「QRコード読み取り?楽勝ですよ😙」=>「AVFoundationを信じたおれがバカだった😇」...
Search
monoqlo
September 01, 2018
Programming
10
29k
「QRコード読み取り?楽勝ですよ😙」=>「AVFoundationを信じたおれがバカだった😇」 / iOSDC 2018
iOSDC 2018 2018/09/01 14:40〜 Track B レギュラートーク(15分)
monoqlo
September 01, 2018
Tweet
Share
More Decks by monoqlo
See All by monoqlo
入門 SwiftUI Alignment Guide / iOSDC2022
monoqlo
11
5.9k
Hey Siri!マルチプラットフォームでのSiriショートカットの地雷を教えて / iOSDC2021
monoqlo
0
780
あなたのアプリ、✨リブランディング✨できますか? / iosdc2020
monoqlo
9
1.6k
実践 CallKit/PushKit ときどき🐛退治 / iOSDC 2019
monoqlo
4
3.9k
WWDC2016のススメ
monoqlo
0
120
Other Decks in Programming
See All in Programming
C-Shared Buildで突破するAI Agent バックテストの壁
po3rin
0
390
組み合わせ爆発にのまれない - 責務分割 x テスト
halhorn
1
150
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
130
Context is King? 〜Verifiability時代とコンテキスト設計 / Beyond "Context is King"
rkaga
9
1.2k
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
6
2.2k
sbt 2
xuwei_k
0
300
Flutter On-device AI로 완성하는 오프라인 앱, 박제창 @DevFest INCHEON 2025
itsmedreamwalker
1
110
JETLS.jl ─ A New Language Server for Julia
abap34
1
400
著者と進める!『AIと個人開発したくなったらまずCursorで要件定義だ!』
yasunacoffee
0
140
Integrating WordPress and Symfony
alexandresalome
0
150
なあ兄弟、 余白の意味を考えてから UI実装してくれ!
ktcryomm
11
11k
バックエンドエンジニアによる Amebaブログ K8s 基盤への CronJobの導入・運用経験
sunabig
0
160
Featured
See All Featured
Rebuilding a faster, lazier Slack
samanthasiow
84
9.3k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
Site-Speed That Sticks
csswizardry
13
1k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.6k
Producing Creativity
orderedlist
PRO
348
40k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
32
2.7k
The Art of Programming - Codeland 2020
erikaheidi
56
14k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
196
70k
A designer walks into a library…
pauljervisheath
210
24k
The Cost Of JavaScript in 2023
addyosmani
55
9.3k
The Invisible Side of Design
smashingmag
302
51k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Transcript
@monoqlo QRίʔυಡΈऔΓʁ ָউͰ͢Α AVFoundationΛ৴ͨ͡ ͓Ε͕όΧͩͬͨ
None
ḪΔ͜ͱ ಥવͰ͕͢
1
2017 3 ݄
ָউͰ͢Α✌✌ QRίʔυಡΈऔΔ ΞϓϦͭ͘ΕΔʁ
͜ͷ࣌ߟ͍͑ͯͨ͜ͱ
AVFoundation Ͱ༨༟Ͱ͠ΐ • AVCaptureSession • AVCaptureMetadataOutput • AVMetadataMachineReadableCodeObject • etc…
QRίʔυ ͞Εͨ
https://www.55truck.com/shaken.html
https://www.55truck.com/shaken.html
None
"8/-/1/-/- /- /999999/02” "2/- //160114/1001/BKG-NKR85” "AN/0168/- /- /0381/13/09” "2/ɹɹ̔̌̌ͤ̒̐̎” “̒/1/NKR85-7011300/4JJ1/1"
http://mangalifewin.takeshobo.co.jp/rensai/popute3/
"8/-/1/-/- /- /999999/02” "2/- //160114/1001/BKG-NKR85” "AN/0168/- /- /0381/13/09” "2/ɹɹ̔̌̌ͤ̒̐̎” “̒/1/NKR85-7011300/4JJ1/1"
"2/- //160114/1001/BKG-NKR85AN/0168/- /- /0381/13/098/-/1/-/- /- /999999/02” "2/ɹɹ̔̌̌ͤ̒̐̎̒/1/NKR85-7011300/4JJ1/1”
φχϞϊ ͜Ε…
None
http://www.qrcode.com
None
ͬͱ QRίʔυ ΛΖ͏
ใٕज़ʵࣗಈೝࣝٴͼσʔλऔಘٕज़ʵ ̧̦ίʔυόʔίʔυγϯϘϧମܥ༷ JIS ن֨ X0510
http://www.jisc.go.jp/
શ 115 ϖʔδ…
QRίʔυͷΈ μΠδΣετ൛
ࠇനϞδϡʔϧͷೝࣝ START ܕࣜใͷ෮߸ ܕ൪ͷܾఆ ϚεΫॲཧͷղআ σʔλ & ޡΓగਖ਼ίʔυޠͷ෮ݩ
ޡΓగਖ਼ ޡΓݕग़ σʔλΛ෮߸ σʔλೖख END ޡΓφγ ޡΓΞϦ
“Ϟʔυ” ղऍ ෮߸͢ΔͨΊʹॏཁͳͷ͕
“Ϟʔυ” ͱ
• ECI • ߏత࿈ • FNC1 • (ऴύλʔϯ) • ࣈ
• ӳࣈ • 8ϏοτόΠτ • ࣈ Ϟʔυ = σʔλΛ֨ೲ͢Δܗࣜ • ѹॖޮ্Λతͱ͠ɺଟͷϞʔυ͕ఆٛ͞Ε͍ͯΔ • QRίʔυੜ࣌ɺσʔλʹ߹Θͤͯ࠷దͳͷΛબ͢Δ • ϔομʔͱͯ͠จࣈࢦࣔࢠͱͱʹσʔλʹՃ͢Δ • Έ߹Θͤͯ༻Մʢex. ӳࣈ + ࣈʣ ߏత࿈
• ࣈ • ӳࣈ • 8ϏοτόΠτ • ࣈ • ECI
• ߏత࿈ • FNC1 • (ऴύλʔϯ) Ϟʔυ = σʔλΛ֨ೲ͢Δܗࣜ • ѹॖޮ্Λతͱ͠ɺଟͷϞʔυ͕ఆٛ͞Ε͍ͯΔ • QRίʔυੜ࣌ɺσʔλʹ߹Θͤͯ࠷దͳͷΛબ͢Δ • ϔομʔͱͯ͠จࣈࢦࣔࢠͱͱʹσʔλʹՃ͢Δ • Έ߹Θͤͯ༻Մʢex. ӳࣈ + ࣈʣ ߏత࿈
ߏత࿈ Ϟʔυ
ϔομʔ༷ 1. Ϟʔυࢦࣔࢠʢ0011ʣɿ4bit 2. γϯϘϧྻࢦࣔࢠɿ8bit 1. γϯϘϧҐஔɿ4bit 2. ࿈݁͞ΕΔγϯϘϧͷ߹ܭɿ4bit 3.
ύϦςΟɿ8bit ׂલͷσʔλΛόΠτ͝ͱʹXORԋࢉͨ͠
None
ϓϩύςΟ var corners: [CGPoint] A Swift array of corner points.
var stringValue: String? Returns the error corrected data decoded into a human- readable string.
ͦΜͳͷͳ͍ AVMetadataMachineReadableCodeObject ʹ
ࠇനϞδϡʔϧͷೝࣝ START ܕࣜใͷ෮߸ ܕ൪ͷܾఆ ϚεΫॲཧͷղআ σʔλ & ޡΓగਖ਼ίʔυޠͷ෮ݩ
ޡΓగਖ਼ ޡΓݕग़ σʔλΛ෮߸ σʔλೖख END ޡΓφγ ޡΓΞϦ AVMetadataMachine ReadableCodeObject ͷ
stringValue ෳ߹ޙͷίϨ
ϥΠϒϥϦΛ୳͢ ߏత࿈Λ͏·͘ѻ͑Δ
None Swift ͷϥΠϒϥϦ
None
ZXingObjC ٹੈओ TheLevelUp/ZXingObjC: An Objective-C Port of ZXing
γϯϘϧҐஔ/߹ܭͱύϦςΟ͕औΕΔ @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard
let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return } // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … } @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity
γϯϘϧҐஔ/߹ܭͱύϦςΟ͕औΕΔ @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard
let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return } // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … } @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return }
γϯϘϧҐஔ/߹ܭͱύϦςΟ͕औΕΔ @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard
let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return } // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … } @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return } // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … }
γϯϘϧҐஔ/߹ܭͱύϦςΟ͕औΕΔ @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard
let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return } // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … } @objc func captureResult(_ capture: ZXCapture!, result: ZXResult!) { guard let _ = result else { return } // ׂQRίʔυͷ߹ɺZXResult#resultMetadata ͷҎԼ2ͭΛ֬ೝͯ͠ // Ͳͷ෦ͷQRίʔυ͕ಡΈࠐ·Εͨͷ͔ఆ͢Δ͜ͱ͕Ͱ͖Δ // - kResultMetadataTypeStructuredAppendSequence // - kResultMetadataTypeStructuredAppendParity // sequence: ಡΈऔͬͨQRίʔυͷ൪߸ 4bit + τʔλϧͷQRίʔυ 4bit let bit = String(sequenceValue, radix: 2) let pad = String(repeating: "0", count: (8 - bit.count)) let sequence = pad + bit let current = Int(sequence.prefix(4), radix: 2)! let total = Int(sequence.suffix(from: 4), radix: 2)! … } guard let metaData = result.resultMetadata, let sequenceValue = metaData[Int(kResultMetadataTypeStructuredAppendSequence.rawValue)] as? Int, let parity = metaData[Int(kResultMetadataTypeStructuredAppendParity.rawValue)] as? Int else { return }
ղܾ ͬͨʔʂʂ
ຊʹʁ
ZXingObjC ͷऑ • ಡΈऔΓਫ਼͕͋·Γߴ͘ͳ͍ • AVFoundation σϯιʔެࣜΞϓϦʹൺΔͱ݁ߏ ͕͔͔࣌ؒΔ͜ͱ͕͋Δ • ։ൃ͕࣮࣭ࢭ·͍ͬͯΔ
• Swift ʹஔ͖͍͑ͨͱ͔ॻ͔ΕͯΔ͚Ͳ͍ͭʹͳΔ ͔·ͬͨ͘Θ͔Βͳ͍
ઈ ະདྷ͕ͳ͍
ઈ ະདྷ͕ͳ͍ ʁ
ઈ ະདྷ͕ͳ͍ ʁ 2017 ·Ͱͷ͓
࣌ྲྀΕ… 2018 9 ݄ 1
iOS ͷόʔδϣϯγΣΞભҠ ݄ ݄ ݄
݄ ݄ ݄ ݄ ݄ ݄ iOS 11 iOS 10 iOS 9 or Earlier ※ 20189݄༧ଌ
iOS 10 ͷαϙʔτ ͦΖͦΖΕ·͢ΑͶʁ ࠓ݄ iOS 12 ͕ϦϦʔε͞Ε·͢
CIQRCodeDescriptor ਅͷٹੈओ in AVMetadataMachineReadableCodeObject
ϓϩύςΟ var corners: [CGPoint] A Swift array of corner points.
var stringValue: String? Returns the error corrected data decoded into a human- readable string. var descriptor: CIBarcodeDescriptor? A barcode description for use in Core Image.
CIQRCodeDescriptor ͱ
CIQRCodeDescriptor ͱ • iOS 11 ͰՃ͞ΕͨڧྗͳΫϥε • நΫϥε CIBarcodeDescriptor ͷαϒΫϥε
• QRίʔυΛੜ͢ΔͨΊʹඞཁेͳσʔλΛ࣋ͭ • CIFilter Ͱ QRίʔυը૾Λੜ͢Δ͜ͱͰ͖Δ
CIQRCodeDescriptor ͱ • iOS 11 ͰՃ͞ΕͨڧྗͳΫϥε • நΫϥε CIBarcodeDescriptor ͷαϒΫϥε
• CIFilter Ͱ QRίʔυը૾Λੜ͢Δ͜ͱͰ͖Δ func generateQRCodeImage(from descriptor: CIQRCodeDescriptor) -> UIImage? { let inputParams: [String: Any] = ["inputBarcodeDescriptor": descriptor] let barcodeCreationFilter = CIFilter(name: "CIBarcodeGenerator", parameters: inputParams) guard let outputImage = barcodeCreationFilter?.outputImage, let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent) else { return nil } return UIImage(cgImage: cgImage) }
େࣄͳͷ͜ͷ 2 ͭ var errorCorrectedPayload: Data The error-corrected payload containing
the data encoded in the QR code. var symbolVersion: Int The version of the QR code.
ࠇനϞδϡʔϧͷೝࣝ START ܕࣜใͷ෮߸ ܕ൪ͷܾఆ ϚεΫॲཧͷղআ σʔλ & ޡΓగਖ਼ίʔυޠͷ෮ݩ
ޡΓగਖ਼ ޡΓݕग़ σʔλΛ෮߸ σʔλೖख END ޡΓφγ ޡΓΞϦ AVMetadataMachine ReadableCodeObject ͷ
stringValue ෳ߹ޙͷίϨ
ޡΓగਖ਼ ޡΓݕग़ σʔλΛ෮߸ σʔλೖख END ޡΓφγ ޡΓΞϦ errorCorrectedPayload ίίͷσʔλʂ
େࣄͳͷ͜ͷ 2 ͭ var errorCorrectedPayload: Data The error-corrected payload containing
the data encoded in the QR code. var symbolVersion: Int The version of the QR code.
େࣄͳͷ͜ͷ 2 ͭ var errorCorrectedPayload: Data The error-corrected payload containing
the data encoded in the QR code. var symbolVersion: Int The version of the QR code.
จࣈࢦࣔࢠͷϏοτ ܕ൪ TZNCPM7FSTJPO ࣈ Ϟʔυ ӳࣈ Ϟʔυ ϏοτόΠτ Ϟʔυ ࣈ
Ϟʔυ ʙ ʙ ʙ
symbolVersion + errorCorrectedPayload σίʔυͰ͖Δ
ͱ͍͏͜ͱ…ʁ
iOS 11 Ҏ߱ͷੈքͰ 1. AVCaptureSession ͰಡΈऔΔ ߴਫ਼Ͱ͍
iOS 11 Ҏ߱ͷੈքͰ AVMetadata Machine ReadableCode Object 2. CIQRCodeDescriptor #errorCorrectedPayload
ΛऔΓग़͢ 1. AVCaptureSession ͰಡΈऔΔ
iOS 11 Ҏ߱ͷੈքͰ AVMetadata Machine ReadableCode Object 2. CIQRCodeDescriptor #errorCorrectedPayload
ΛऔΓग़͢ σίʔυ͢Δ 1. AVFoundation ͰಡΈऔΔ ͕Μͬͯ 3.
ղܾ ͬͨʔʂʂࠓͦ͜
σίʔυ͢Δ ͕Μͬͯ 3. ͕Μͬͯ
͕ΜΔ = ࣗલͰσίʔυॲཧΛॻ͘
ࣗલσίʔυͷํ • શϞʔυʹରԠ͠Α͏ͱࢥͬͨΒʢͨͿΜʣ݁ߏେม… • ͱ͍͏͔σϯιʔެࣜΞϓϦରԠͯ͠ͳ͍ • ࠷ݶಡΈऔΓ͍ͨQRίʔυͷσίʔυॲཧͰଥڠ • ಠࣗΤϯίʔυ͞ΕͨQRίʔυσίʔυͰ͖Δ͠ɺ ෯͕͕Δʢͱ͔ॻ͍ͯΔ͏ͪʹσϯιʔ͕Ԍ্͠·ͨ͠ʣ
=> https://srad.jp/submission/78134/
σίʔυͷҰྫ https://github.com/ monoqlo/QRCodeReader
࣌ؒ͋Ε গ͚ͩ͠ DEMO
·ͱΊ
0. iOS 10 ͷαϙʔτΛΔʢҰ൪େࣄʣ
·ͱΊʢiOS 11 Ҏ߱ͷੈքʣ 1. AVCaptureSession ͰಡΈऔΔ AVMetadata Machine ReadableCode Object
2. CIQRCodeDescriptor #errorCorrectedPayload ΛऔΓग़͢ ͕Μͬͯσίʔυ͢Δ 3.
Appendix • Speaker Info @monoqlo • This Slide URL https://speakerdeck.com/monoqlo/iosdc-2018