创建带图标、颜色、圆角和边框的二维码图片

仅供参考

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
    }
}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容