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

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

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

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

1595閲覧

SwiftUIでのQRコード読み込み処理

CrazySora_JP

総合スコア18

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2022/12/04 09:13

前提

SwiftUIでiOSアプリを開発しています。
QRコードをギャラリーから読み込み、URLを取得したいです。

実現したいこと

  • QRの画像からQRコードを認識し、URLを取得したい

発生している問題

現在、”PhotosPicker”を使用して”PhotosPickerItem”に画像を渡すところまでできています。
しかし、肝心のQRコードを読み取る処理ができません。
様々なサイトで調べましたが、カメラを起動して読み取ってという処理しか見つけることができませんでした。
QRコードを読み取る処理で適当なものがありましたらご教授願います。

該当のソースコード

SwiftUI

1@State var photoPickerItems: [PhotosPickerItem] = [] 2 3var body: some View { 4 5//QR画像選択 6PhotosPicker( 7  selection: $photoPickerItems, // Bindingした[PhotosPickerItem] 8  maxSelectionCount: 1, // 選択する写真の数(0で無制限) 9  selectionBehavior: .ordered, // 順番が関係するか 10  matching: .images, // 写真の種類を選択(nilでどれでも可に) 11  preferredItemEncoding: .current, // エンコードの種類(基本currentでいいはず) 12   photoLibrary: .shared()){ // ライブラリの選択 13 14Text("QRコードを読み込む") 15 .foregroundColor(MyColor.HighlightColor) 16 } 17}

補足情報

初心者質問で申し訳ありません。不足している情報などありましたら追記いたしますのでお申し付けください。

ios16.1
Xcode Version 14.1

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

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

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

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

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

guest

回答1

0

ベストアンサー

過去に同様の質問があったみたいでした。

swiftでアルバムからQRコード画像を読み込み、解析したい
https://teratail.com/questions/163956

How to read QR code from static image
https://stackoverflow.com/questions/35956538/how-to-read-qr-code-from-static-image

stackoverflowのコードを参考に確認してみたところSwift5.7でも動くみたいでした。
*言語のバージョンが上がってもっと良い書き方ができるのかどうかまではわかりません・・

swift

1struct ContentView: View { 2 @State var photoPickerItems: [PhotosPickerItem] = [] 3 var body: some View { 4 //QR画像選択 5 PhotosPicker( 6 selection: $photoPickerItems, // Bindingした[PhotosPickerItem] 7 maxSelectionCount: 1, // 選択する写真の数(0で無制限) 8 selectionBehavior: .ordered, // 順番が関係するか 9 matching: .images, // 写真の種類を選択(nilでどれでも可に) 10 preferredItemEncoding: .current, // エンコードの種類(基本currentでいいはず) 11 photoLibrary: .shared()){ // ライブラリの選択 12 Text("QRコードを読み込む") 13 .foregroundColor(MyColor.HighlightColor) 14 } 15 .onChange(of: photoPickerItems, perform: action) // ***** onChange(of:perform:) modifierでphotoPickerItemsが変わったら処理が動くようにします。 16 } 17 // ***** 写真を選択してphotoPickerItemsが変わったら呼び出されるメソッドです。 18 func action(equatable: any Equatable) { 19 guard let items = equatable as? [PhotosPickerItem] else { 20 return 21 } 22 Task { 23 // ***** photoPickerItemsは配列ですので(選択できるのは1つに限定しているとは思いますが)、配列の数だけ繰り返します。 24 for item in items { 25 // ***** PhotosPickerItemをData型に変換して、さらにUIImage型に変換します。 26 guard let data = try? await item.loadTransferable(type: Data.self), 27 let image = UIImage(data: data) else { 28 continue 29 } 30 // ***** UIImageからQRコードを検出します。 31 // ***** 1つの画像から複数のQRコードが検出されるとfeatures配列の要素は複数になると思います。 32 // ***** QRコードが検出できない場合はfeatures配列は要素数が0になると思います。 33 let features = detectQRCode(image) 34 for feature in features { 35 // ***** QRコードが正しく検出できたらmessageStringにURLが入っているはずです。 36 print(feature.messageString ?? "nope") // https://jingged.com 37 } 38 } 39 } 40 } 41 // ***** UIImageからQRコードを検出するメソッドです。 42 func detectQRCode(_ image: UIImage?) -> [CIQRCodeFeature] { 43 guard let image = image, 44 let ciImage = CIImage(image: image) else { 45 return [] 46 } 47 let context = CIContext() 48 let options1: [String : Any] = [CIDetectorAccuracy: CIDetectorAccuracyHigh] 49 guard let qrDetector = CIDetector(ofType: CIDetectorTypeQRCode, context: context, options: options1) else { 50 return [] 51 } 52 let options2: [String : Any] = ciImage.properties.keys.contains((kCGImagePropertyOrientation as String)) ? 53 [CIDetectorImageOrientation: ciImage.properties[(kCGImagePropertyOrientation as String)] ?? 1] : 54 [CIDetectorImageOrientation: 1] 55 let features = qrDetector.features(in: ciImage, options: options2) 56 let qrCodeFeatures = features.compactMap({ $0 as? CIQRCodeFeature }) 57 return qrCodeFeatures 58 } 59}

追記です。

コメントありがとうございます。

説明不足ですみません・・
SwiftUIのViewの記述からコードを記載するようにしてみました。
今回はもう少しコメントも記述してみました。
「// *****」のコメントも読んでみてください。

messageStringにurlを代入するのでしょうか?

messageStringに欲しい結果(URL)が格納されていますので、それを使って何か必要な処理を書いてみてください。

追記2です。

コメントありがとうございます。

戻り値の型をstringで指定して返そうとすると、
このエラーが、関数を呼び出す部分で発生します。
voidに変換できないとのことですが、そもそもvoid型はデータ型不明というような型ではないのでしょうか?

Voidはメソッド(関数)の戻り値がない場合ですね。

actionメソッドは onChange(of:perform:) のperformパラメータに渡していますが、
このパラメータは @escaping (V) -> Void の型ということになっています。
戻り値がVoidの型を要求していますので、Stringに変更したものはこの型に合わず、
エラーになっていると思います。

onChange(of:perform:) | Apple Developer Documentation

ですので、actionの中からビューのプロパティに直接設定するとか、
(戻り値で返すのではなく)
そういう感じになるのかなと思います。

その先の具体的な処理の内容をご提示いただけましたら、
もう少し具体的な回答ができるかもしれません。

投稿2022/12/04 11:06

編集2022/12/05 14:29
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

CrazySora_JP

2022/12/05 02:12

ご回答ありがとうございます。 下の関数から上の関数を呼び出してQRコードを読み込み、messageStringnにurlを代入するのでしょうか? SwiftUI内でどのように使用すればいいのでしょうか。。 勉強不足理解が足らず申し訳ないです。。。
CrazySora_JP

2022/12/05 12:50

本当にありがとうございます。。。! 私の知識が浅く理解できていないだけでしたので説明不足だなんてそんなことないです!! 詳しく説明していただいて理解できました!頑張ります!!
CrazySora_JP

2022/12/05 14:08 編集

何度もすみません! messageStringの値をビューに返そうと思い、戻り値の型をstringで指定して返そうとすると、 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー Cannot convert value of type '(any Equatable) -> String' to expected argument type '([PhotosPickerItem]) -> Void' ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー このエラーが、関数を呼び出す部分で発生します。 voidに変換できないとのことですが、そもそもvoid型はデータ型不明というような型ではないのでしょうか? もしビュー内に値を返す方法で最適なものがありましたら教えていただきたいです。。。!
CrazySora_JP

2022/12/05 14:36

ご回答ありがとうございます この先の処理は適当な変数にurlを格納し、ifを用いて文字列を検索しようとしています。 戻り値で返さない方法を調べてみます!
退会済みユーザー

退会済みユーザー

2022/12/06 00:59

コメントありがとうございます。 > この先の処理は適当な変数にurlを格納し、ifを用いて文字列を検索しようとしています。 1つの案として書いてみます。 ビューに `@State var str: String?` のようなプロパティを定義しておいて、 QRコードが検出できたところでビューのプロパティにURLを設定します。 `str = feature.messageString` 「ifを用いて文字列を検索」という処理は、 photoPickerItemsが変わったら処理が動くのと同様に `.onChange(of:perform:)` modifierを使って、 `.onChange(of: str, perform: sampleMethod)` のように記述する感じはいかがでしょうか。 *「sampleMethod」という名前のメソッドの中に文字列を検索する処理を記述する感じです ちゃんと仕様を理解できていないかもしれませんので・・ 何かありましたらまたコメントくださいね。
CrazySora_JP

2022/12/06 02:01

無事思い通りに実装することができました!! 教えていただいた通り、ビューで変数を定義して代入したところうまくビューに渡すことができました。 関数からはビューの変数が参照できないと思い込んでいたので本当にありがとうございます! その後の処理も.onCgangeを用いて処理を記述しました。 こんな質問に最後まで丁寧に教えていただき本当に感謝しかないです。。。! コードに書いてくださったコメントもとてもわかりやすかったです! ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問