利用 Swift 在 iOS 構建獨特漂亮的 QR code 視圖
本篇原文(標題:Generating beautiful QR code views in iOS using Swift)刊登於作者 Medium,由 Prafulla Singh 所著,並授權翻譯及轉載。
QR Code 是一種認證技術,廣泛應用於行動科技領域中。iOS 內建支援創建帶有 Payload 的漂亮 QR Code 圖像。在本篇教學中,我們將會學習這個技巧。
QR code 的基本組件:
- Payload,多數是一個網址
- QR code 錯誤修正功能
- 可選公司圖片/Logo
- 可選顏色
首先,讓我們先構建結構,然後再實作基本和漂亮的 QR Code 視圖。
struct QRCodeDataSet { let logo: UIImage? let url: String let backgroundColor: CIColor let color: CIColor let size: CGSize init(logo: UIImage? = nil, url: String) { self.logo = logo self.url = url self.backgroundColor = CIColor(red: 1,green: 1,blue: 1) self.color = CIColor(red: 1,green: 0.46,blue: 0.46) self.size = CGSize(width: 300, height: 300) } init(logo: UIImage? = nil, url: String, backgroundColor: CIColor, color: CIColor, size: CGSize) { self.logo = logo self.url = url self.backgroundColor = backgroundColor self.color = color self.size = size } }
這就是基本的結構,使用者要按需要傳遞 payload 和其他可選物件。
建立一個基本的 QR Code
使用 ‘CIQRCodeGenerator’ 過濾器建立一個 CIFilter 物件,然後利用 inputMessage 和修正鍵 inputCorrectionLevel 設置 Payload。 (在這個範例中,我們使用了 inputCorrectionLevel H。)
private func createCIImage() -> CIImage? { guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil } filter.setDefaults() filter.setValue(url.data(using: String.Encoding.ascii), forKey: "inputMessage") filter.setValue("H", forKey: "inputCorrectionLevel") //https://www.qrcode.com/en/about/error_correction.html return filter.outputImage }
然後會得到回傳的 CIImage:

為 QR Code 添加顏色
假色 (False Color) 的過濾器是 ‘CIFalseColor’。讓我們從前面函式提取圖像,並設置為輸入圖像 (Input Image),如此設置顏色:
private func updateColor(image: CIImage) -> CIImage? { guard let colorFilter = CIFilter(name: "CIFalseColor") else { return nil } colorFilter.setValue(image, forKey: kCIInputImageKey) colorFilter.setValue(color, forKey: "inputColor0") colorFilter.setValue(backgroundColor, forKey: "inputColor1") return colorFilter.outputImage }
然後會得到回傳的 CIImage:

為 QR Code 添加 Logo
讓我們創建新的過濾器 ‘CISourceOverCompositing’,然後將 Logo 圖像轉換為最終圖像的中心,將 Logo 設置為主圖像,並把前面函式中提取的圖像(也就是 QR 圖像)設置為背景。
private func addLogo(image: CIImage, logo: UIImage) -> CIImage? { guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else { return nil } guard let logo = logo.cgImage else { return image } let ciLogo = CIImage(cgImage: logo) let centerTransform = CGAffineTransform(translationX: image.extent.midX - (ciLogo.extent.size.width / 2), y: image.extent.midY - (ciLogo.extent.size.height / 2)) combinedFilter.setValue(ciLogo.transformed(by: centerTransform), forKey: "inputImage") combinedFilter.setValue(image, forKey: "inputBackgroundImage") return combinedFilter.outputImage }
然後會得到回傳的 CIImage:

完整程式碼
import SwiftUI import Foundation import UIKit struct ContentView: View { var body: some View { ZStack { QRView().frame(width: 300, height: 300, alignment: .center) } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct QRView: UIViewRepresentable { func updateUIView(_ uiView: UIImageView, context: Context) { } func makeUIView(context: Context) -> UIImageView { return UIImageView.init(image: QRCodeDataSet(logo: UIImage.init(named: "red-hat")!, url: "https://google.com").getQRImage()) } } struct QRCodeDataSet { let logo: UIImage? let url: String let backgroundColor: CIColor let color: CIColor let size: CGSize init(logo: UIImage? = nil, url: String) { self.logo = logo self.url = url self.backgroundColor = CIColor(red: 1,green: 1,blue: 1) self.color = CIColor(red: 1,green: 0.46,blue: 0.46) self.size = CGSize(width: 300, height: 300) } //rgb(255, , 118) init(logo: UIImage? = nil, url: String, backgroundColor: CIColor, color: CIColor, size: CGSize) { self.logo = logo self.url = url self.backgroundColor = backgroundColor self.color = color self.size = size } func getQRImage() -> UIImage? { guard var image = createCIImage() else { return nil} ///scale to width:height let scaleW = self.size.width/image.extent.size.width let scaleH = self.size.height/image.extent.size.height let transform = CGAffineTransform(scaleX: scaleW, y: scaleH) image = image.transformed(by: transform) /// add logo if let logo = logo, let newImage = addLogo(image: image, logo: logo) { image = newImage } /// update color if let colorImgae = updateColor(image: image) { image = colorImgae } return UIImage(ciImage: image) } private func updateColor(image: CIImage) -> CIImage? { guard let colorFilter = CIFilter(name: "CIFalseColor") else { return nil } colorFilter.setValue(image, forKey: kCIInputImageKey) colorFilter.setValue(color, forKey: "inputColor0") colorFilter.setValue(backgroundColor, forKey: "inputColor1") return colorFilter.outputImage } private func addLogo(image: CIImage, logo: UIImage) -> CIImage? { guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else { return nil } guard let logo = logo.cgImage else { return image } let ciLogo = CIImage(cgImage: logo) let centerTransform = CGAffineTransform(translationX: image.extent.midX - (ciLogo.extent.size.width / 2), y: image.extent.midY - (ciLogo.extent.size.height / 2)) combinedFilter.setValue(ciLogo.transformed(by: centerTransform), forKey: "inputImage") combinedFilter.setValue(image, forKey: "inputBackgroundImage") return combinedFilter.outputImage } private func createCIImage() -> CIImage? { guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil } filter.setDefaults() filter.setValue(url.data(using: String.Encoding.ascii), forKey: "inputMessage") filter.setValue("H", forKey: "inputCorrectionLevel") //https://www.qrcode.com/en/about/error_correction.html return filter.outputImage } }
請記得更改圖像名稱,來讓程式碼可以正常運作。
參考資料
本篇原文(標題:Generating beautiful QR code views in iOS using Swift)刊登於作者 Medium,由 Prafulla Singh 所著,並授權翻譯及轉載。
作者簡介:Prafulla Singh,Block.one 的 iOS 開發者
譯者簡介:Kelly Chan-AppCoda 編輯小姐。
iOS
下一篇
SwiftUI TabView 教學:利用 PageTabViewStyle 建立 Paged Scrolling 視圖
iOS