import SwiftUI import CoreImage import QRCode // MARK: - 二维码生成工具类 class QRCodeGenerator { // MARK: - 生成基本二维码(使用Core Image) static func generateBasicQRCode(content: String) -> UIImage { let data = content.data(using: .utf8) let qrFilter = CIFilter.qrCodeGenerator() qrFilter.setValue(data, forKey: "inputMessage") qrFilter.setValue("H", forKey: "inputCorrectionLevel") guard let outputImage = qrFilter.outputImage else { return UIImage(systemName: "qrcode") ?? UIImage() } let context = CIContext() guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return UIImage(systemName: "qrcode") ?? UIImage() } return UIImage(cgImage: cgImage) } // MARK: - 生成高质量二维码(使用QRCode库) static func generateHighQualityQRCode( content: String, styleData: QRCodeStyleData? = nil ) -> UIImage { do { let document = try createQRCodeDocument(content: content, styleData: styleData) let imageData = try document.pngData(dimension: 600) return UIImage(data: imageData) ?? generateBasicQRCode(content: content) } catch { print("生成高质量二维码失败:\(error.localizedDescription)") return generateBasicQRCode(content: content) } } // MARK: - 创建QRCode文档 private static func createQRCodeDocument( content: String, styleData: QRCodeStyleData? ) throws -> QRCode.Document { let document = try QRCode.Document(engine: QRCodeEngineExternal()) // 设置内容 document.utf8String = content // 如果没有样式数据,使用默认样式 guard let styleData = styleData else { // 使用默认样式 document.design.backgroundColor(CGColor(red: 1, green: 1, blue: 1, alpha: 1)) // 白色背景 document.design.style.eye = QRCode.FillStyle.Solid(CGColor(red: 0, green: 0, blue: 0, alpha: 1)) // 黑色眼睛 document.design.style.eyeBackground = CGColor(red: 1, green: 1, blue: 1, alpha: 1) // 白色眼睛背景 document.design.shape.onPixels = QRCode.PixelShape.Square() // 方形点 document.design.style.onPixels = QRCode.FillStyle.Solid(CGColor(red: 0, green: 0, blue: 0, alpha: 1)) // 黑色点 document.design.style.onPixelsBackground = CGColor(red: 1, green: 1, blue: 1, alpha: 1) // 白色点背景 document.design.shape.offPixels = QRCode.PixelShape.Square() // 方形空白 document.design.style.offPixels = QRCode.FillStyle.Solid(CGColor(red: 1, green: 1, blue: 1, alpha: 1)) // 白色空白 document.design.style.offPixelsBackground = CGColor(red: 1, green: 1, blue: 1, alpha: 1) // 白色空白背景 document.design.shape.eye = QRCode.EyeShape.Square() // 方形眼睛 return document } // 应用样式数据 applyStyleData(styleData, to: document) return document } // MARK: - 应用样式数据 private static func applyStyleData(_ styleData: QRCodeStyleData, to document: QRCode.Document) { // 设置背景色 if let backgroundColor = getColor(from: styleData.backgroundColor) { document.design.backgroundColor(backgroundColor) } // 设置前景色 let foregroundColor = getColor(from: styleData.foregroundColor) ?? CGColor(red: 0, green: 0, blue: 0, alpha: 1) // 设置眼睛样式 document.design.style.eye = QRCode.FillStyle.Solid(foregroundColor) document.design.style.eyeBackground = getColor(from: styleData.backgroundColor) ?? CGColor(red: 1, green: 1, blue: 1, alpha: 1) // 设置点样式 let dotType = getDotType(from: styleData.dotType) document.design.shape.onPixels = dotType document.design.style.onPixels = QRCode.FillStyle.Solid(foregroundColor) document.design.style.onPixelsBackground = getColor(from: styleData.backgroundColor) ?? CGColor(red: 1, green: 1, blue: 1, alpha: 1) document.design.shape.offPixels = dotType document.design.style.offPixels = QRCode.FillStyle.Solid(getColor(from: styleData.backgroundColor) ?? CGColor(red: 1, green: 1, blue: 1, alpha: 1)) document.design.style.offPixelsBackground = getColor(from: styleData.backgroundColor) ?? CGColor(red: 1, green: 1, blue: 1, alpha: 1) // 设置眼睛形状 let eyeType = getEyeType(from: styleData.eyeType) document.design.shape.eye = eyeType // 设置Logo if let logo = styleData.logo { applyLogo(logo, hasCustomLogo: styleData.hasCustomLogo, customLogoFileName: styleData.customLogoFileName, to: document) } } // MARK: - 应用Logo private static func applyLogo( _ logoIdentifier: String, hasCustomLogo: Bool, customLogoFileName: String?, to document: QRCode.Document ) { if hasCustomLogo, let fileName = customLogoFileName { // 加载自定义Logo if let customLogoImage = loadCustomLogoImage(fileName: fileName), let cgImage = customLogoImage.cgImage { document.logoTemplate = QRCode.LogoTemplate.CircleCenter(image: cgImage, inset: 0) } } else { // 加载预设Logo if let qrCodeLogo = QRCodeLogo(rawValue: logoIdentifier), let logoImage = qrCodeLogo.image, let cgImage = logoImage.cgImage { document.logoTemplate = QRCode.LogoTemplate.CircleCenter(image: cgImage) } } } // MARK: - 加载自定义Logo图片 private static func loadCustomLogoImage(fileName: String) -> UIImage? { guard let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil } let customLogosPath = documentsPath.appendingPathComponent("CustomLogos") let imagePath = customLogosPath.appendingPathComponent(fileName) return UIImage(contentsOfFile: imagePath.path) } // MARK: - 颜色转换 private static func getColor(from colorString: String) -> CGColor? { switch colorString.lowercased() { case "black": return CGColor(red: 0, green: 0, blue: 0, alpha: 1) case "white": return CGColor(red: 1, green: 1, blue: 1, alpha: 1) case "red": return CGColor(red: 1, green: 0, blue: 0, alpha: 1) case "blue": return CGColor(red: 0, green: 0, blue: 1, alpha: 1) case "green": return CGColor(red: 0, green: 1, blue: 0, alpha: 1) case "yellow": return CGColor(red: 1, green: 1, blue: 0, alpha: 1) case "purple": return CGColor(red: 0.5, green: 0, blue: 0.5, alpha: 1) case "orange": return CGColor(red: 1, green: 0.5, blue: 0, alpha: 1) case "pink": return CGColor(red: 1, green: 0.75, blue: 0.8, alpha: 1) case "cyan": return CGColor(red: 0, green: 1, blue: 1, alpha: 1) case "magenta": return CGColor(red: 1, green: 0, blue: 1, alpha: 1) case "brown": return CGColor(red: 0.6, green: 0.4, blue: 0.2, alpha: 1) case "gray": return CGColor(red: 0.5, green: 0.5, blue: 0.5, alpha: 1) case "navy": return CGColor(red: 0, green: 0, blue: 0.5, alpha: 1) case "teal": return CGColor(red: 0, green: 0.5, blue: 0.5, alpha: 1) case "indigo": return CGColor(red: 0.3, green: 0, blue: 0.7, alpha: 1) case "lime": return CGColor(red: 0.5, green: 1, blue: 0, alpha: 1) case "maroon": return CGColor(red: 0.5, green: 0, blue: 0, alpha: 1) case "olive": return CGColor(red: 0.5, green: 0.5, blue: 0, alpha: 1) case "silver": return CGColor(red: 0.75, green: 0.75, blue: 0.75, alpha: 1) default: return nil } } // MARK: - 点类型转换 private static func getDotType(from dotTypeString: String) -> QRCodePixelShapeGenerator { // 根据字符串匹配到对应的QRCodeDotType if let dotType = QRCodeDotType.allCases.first(where: { $0.rawValue == dotTypeString }) { return dotType.pixelShape } // 如果没有找到匹配的类型,返回默认的方形 return QRCode.PixelShape.Square() } // MARK: - 眼睛类型转换 private static func getEyeType(from eyeTypeString: String) -> QRCodeEyeShapeGenerator { // 根据字符串匹配到对应的QRCodeEyeType if let eyeType = QRCodeEyeType.allCases.first(where: { $0.rawValue == eyeTypeString }) { return eyeType.eyeShape } // 如果没有找到匹配的类型,返回默认的方形 return QRCode.EyeShape.Square() } }