仅供参考
struct QrCode {
/// 创建带图标、颜色、圆角和边框的二维码图片
///
/// - Parameters:
/// - qrString: 需要编码的字符串内容
/// - icon: 可选的中心图标(如品牌 logo、头像)
/// - iconSizeRatio: 图标相对二维码宽度的比例,默认 0.25
/// - iconCornerRadius: 图标圆角比例(0~1,0 表示无圆角)
/// - iconBorderWidth: 图标边框宽度,默认 0
/// - iconBorderColor: 图标边框颜色,默认白色
/// - foregroundColor: 二维码前景色(二维码本体颜色)
/// - backgroundColor: 二维码背景色
/// - scale: 放大倍数,避免二维码模糊,默认 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. 基础安全校验
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. 设置二维码颜色(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
}
}