僅供參考
struct QrCode {
/// 創(chuàng)建帶圖標、顏色、圓角和邊框的二維碼圖片
///
/// - Parameters:
/// - qrString: 需要編碼的字符串內(nèi)容
/// - icon: 可選的中心圖標(如品牌 logo、頭像)
/// - iconSizeRatio: 圖標相對二維碼寬度的比例,默認 0.25
/// - iconCornerRadius: 圖標圓角比例(0~1,0 表示無圓角)
/// - iconBorderWidth: 圖標邊框?qū)挾?,默認 0
/// - iconBorderColor: 圖標邊框顏色,默認白色
/// - foregroundColor: 二維碼前景色(二維碼本體顏色)
/// - backgroundColor: 二維碼背景色
/// - scale: 放大倍數(shù),避免二維碼模糊,默認 10
/// - Returns: 最終生成的二維碼 UIImage,失敗返回 nil
static func createQRForString(
qrString: String?,
icon: UIImage? = nil,
iconSizeRatio: CGFloat = 0.25,
iconCornerRadius: CGFloat = 0,
iconBorderWidth: CGFloat = 0,
iconBorderColor: UIColor = .white,
foregroundColor: UIColor = .black,
backgroundColor: UIColor = .white,
scale: CGFloat = 10
) -> UIImage? {
// MARK: 1. 基礎(chǔ)安全校驗
guard let qrString = qrString,
!qrString.isEmpty,
let stringData = qrString.data(using: .utf8, allowLossyConversion: false),
let qrFilter = CIFilter(name: "CIQRCodeGenerator") else {
return nil
}
// MARK: 2. 配置二維碼生成器(inputMessage: 字符串,inputCorrectionLevel: 容錯率)
qrFilter.setValue(stringData, forKey: "inputMessage")
qrFilter.setValue("H", forKey: "inputCorrectionLevel") // H 表示最高容錯率 30%
// 獲取二維碼 CIImage
guard let qrCIImage = qrFilter.outputImage else { return nil }
// MARK: 3. 設(shè)置二維碼顏色(CIFalseColor 過濾器)
guard let colorFilter = CIFilter(name: "CIFalseColor") else { return nil }
colorFilter.setDefaults()
colorFilter.setValue(qrCIImage, forKey: "inputImage")
colorFilter.setValue(CIColor(color: foregroundColor), forKey: "inputColor0") // 前景色
colorFilter.setValue(CIColor(color: backgroundColor), forKey: "inputColor1") // 背景色
guard let coloredQRImage = colorFilter.outputImage else { return nil }
// MARK: 4. 使用仿射變換放大二維碼,避免縮放時模糊
let transformedQR = coloredQRImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
// MARK: 5. 使用 CIContext 柵格化 CIImage → CGImage
let context = CIContext()
guard let cgImage = context.createCGImage(transformedQR, from: transformedQR.extent) else { return nil }
// 生成最終二維碼 UIImage
let qrUIImage = UIImage(cgImage: cgImage, scale: UIScreen.main.scale, orientation: .up)
// 如果不需要添加中心圖標,直接返回二維碼
guard let icon = icon else { return qrUIImage }
// MARK: 6. 計算中心圖標尺寸與位置
let qrSize = qrUIImage.size
let validIconRatio = min(max(iconSizeRatio, 0.0), 1.0) // 確保 0~1
let iconSize = CGSize(width: qrSize.width * validIconRatio,
height: qrSize.height * validIconRatio)
let iconX = (qrSize.width - iconSize.width) / 2
let iconY = (qrSize.height - iconSize.height) / 2
let iconRect = CGRect(x: iconX, y: iconY, width: iconSize.width, height: iconSize.height)
// MARK: 7. 繪制二維碼與圖標合成
UIGraphicsBeginImageContextWithOptions(qrSize, false, 0.0)
// 繪制二維碼背景圖
qrUIImage.draw(in: CGRect(origin: .zero, size: qrSize))
// 繪制圖標圓角路徑
let cornerRadius = iconSize.width * max(0, min(iconCornerRadius, 1))
let path = UIBezierPath(roundedRect: iconRect, cornerRadius: cornerRadius)
path.addClip() // 將繪圖上下文裁剪為圓角
// 繪制圖標
icon.draw(in: iconRect)
// 如果有邊框,則繪制邊框
if iconBorderWidth > 0 {
iconBorderColor.setStroke()
path.lineWidth = iconBorderWidth
path.stroke()
}
// 獲取最終圖像
let finalImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return finalImage
}
}