iOS 17 之后,QR 图像未在 Widget 上呈现

问题描述 投票:0回答:1

我有一些扩展方法,用于将二维码转换为图像。在 iOS 17 更新之前,一切都运行得非常完美。它们现在根本没有渲染。

这些是我正在使用的方法

extension UIImage {
convenience init?(qrcode string: String) {
    if let outputCIImage = CIImage.make(qrcode: string) {
        let context = CIContext()
        guard let cgImage = context.createCGImage(outputCIImage, from: outputCIImage.extent) else { return nil }
        self.init(cgImage: cgImage)
        return
    }
    return nil
}

convenience init?(qrcode string: String, using color: UIColor) {
    if let outputCIImage = CIImage.make(qrcode: string)?.tinted(using: color) {
        let context = CIContext()
        guard let cgImage = context.createCGImage(outputCIImage, from: outputCIImage.extent) else { return nil }
        self.init(cgImage: cgImage)
        return
    }
    return nil
}

}

extension CIImage {
static func make(qrcode string: String) -> CIImage? {
    let data = string.data(using: .ascii)
    if let filter = CIFilter(name: "CIQRCodeGenerator") {
        filter.setValue(data, forKey: "inputMessage")
        filter.setValue("Q", forKey: "inputCorrectionLevel")
        let transform = CGAffineTransform(scaleX: 12, y: 12)
        return filter.outputImage?.transformed(by: transform)
    }
    return nil
}

}

extension CIImage {
var transparent: CIImage? {
    inverted?.blackTransparent
}

var inverted: CIImage? {
    guard let invertedColorFilter = CIFilter(name: "CIColorInvert") else { return nil }

    invertedColorFilter.setValue(self, forKey: "inputImage")
    return invertedColorFilter.outputImage
}

var blackTransparent: CIImage? {
    guard let blackTransparentFilter = CIFilter(name: "CIMaskToAlpha") else { return nil }
    blackTransparentFilter.setValue(self, forKey: "inputImage")
    return blackTransparentFilter.outputImage
}

func tinted(using color: UIColor) -> CIImage? {
    guard
        let transparentQRImage = transparent,
        let filter = CIFilter(name: "CIMultiplyCompositing"),
        let colorFilter = CIFilter(name: "CIConstantColorGenerator") else { return nil }

    let ciColor = CIColor(color: color)
    colorFilter.setValue(ciColor, forKey: kCIInputColorKey)
    let colorImage = colorFilter.outputImage

    filter.setValue(colorImage, forKey: kCIInputImageKey)
    filter.setValue(transparentQRImage, forKey: kCIInputBackgroundImageKey)

    return filter.outputImage
}

func combined(with image: CIImage) -> CIImage? {
    guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else { return nil }
    let centerTransform = CGAffineTransform(translationX: extent.midX - (image.extent.size.width / 2), y: extent.midY - (image.extent.size.height / 2))
    combinedFilter.setValue(image.transformed(by: centerTransform), forKey: "inputImage")
    combinedFilter.setValue(self, forKey: "inputBackgroundImage")
    return combinedFilter.outputImage!
}

}

经过一番调查我发现了这个扩展方法

extension UIImage {
static func make(qrcode string: String) -> UIImage? {
    guard let data = string.data(using: String.Encoding.ascii) else { return nil }
    var uiImage: UIImage?
    if let filter = CIFilter(
        name: "CIQRCodeGenerator",
        parameters: ["inputMessage": data, "inputCorrectionLevel": "Q"]
    ) {
        guard
            let outputImage = filter.outputImage,
            let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent)
        else {
            return nil
        }
        let scaleFactor: CGFloat = 12
        let size = CGSize(
            width: outputImage.extent.width * scaleFactor,
            height: outputImage.extent.height * scaleFactor
        )
        UIGraphicsBeginImageContext(size)
        if let context = UIGraphicsGetCurrentContext() {
            context.interpolationQuality = .none
            context.draw(cgImage, in: CGRect(origin: .zero, size: size))
            uiImage = UIGraphicsGetImageFromCurrentImageContext()
        }
        UIGraphicsEndImageContext()
    }
    return uiImage
}

}

现在可以工作了,但我无法使其背景透明,我想如果不将 UIImage 转换为 CIImage 是不可能的。但当我这样做时,图像将不会渲染。可能会出现什么问题?

ios swift swiftui core-graphics
1个回答
0
投票

这是在iOS 17中实现所需的高质量透明背景二维码图像的更新代码,希望它能解决您的疑问。

更新代码:

extension UIImage {
    
    static func make(qrcode string: String, tint color: UIColor) -> UIImage? {
        guard let qrCIImage = string.qrCIImage else { return nil }
        
        if let tintedCIImage = qrCIImage.tinted(using: color),
           let cgImage = CIContext().createCGImage(tintedCIImage, from: tintedCIImage.extent) {
            return UIImage(cgImage: cgImage)
        }
        
        return nil
    }
}

extension String {
    
    var qrCIImage: CIImage? {
        guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
        let qrData = data(using: String.Encoding.ascii)
        qrFilter.setValue(qrData, forKey: "inputMessage")
        
        let qrTransform = CGAffineTransform(scaleX: 12, y: 12)
        return qrFilter.outputImage?.transformed(by: qrTransform)
    }
    
    var transparentQRImage: CIImage? {
        return qrCIImage?.transparent
    }
}

extension CIImage {
    
    var transparent: CIImage? {
        return inverted?.blackTransparent
    }
    
    var inverted: CIImage? {
        guard let invertedColorFilter = CIFilter(name: "CIColorInvert") else { return nil }
        invertedColorFilter.setValue(self, forKey: "inputImage")
        return invertedColorFilter.outputImage
    }
    
    var blackTransparent: CIImage? {
        guard let blackTransparentFilter = CIFilter(name: "CIMaskToAlpha") else { return nil }
        blackTransparentFilter.setValue(self, forKey: "inputImage")
        return blackTransparentFilter.outputImage
    }
    
    func tinted(using color: UIColor) -> CIImage? {
        guard
            let transparentQRImage = transparent,
            let filter = CIFilter(name: "CIMultiplyCompositing"),
            let colorFilter = CIFilter(name: "CIConstantColorGenerator") else { return nil }
        
        let ciColor = CIColor(color: color)
        colorFilter.setValue(ciColor, forKey: kCIInputColorKey)
        let colorImage = colorFilter.outputImage
        
        filter.setValue(colorImage, forKey: kCIInputImageKey)
        filter.setValue(transparentQRImage, forKey: kCIInputBackgroundImageKey)
        
        return filter.outputImage
    }
}

使用方法:

class ViewController: UIViewController {
    
    @IBOutlet weak var imgview: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.view.backgroundColor = .yellow
        
        // Generate a QR code for a sample string
        let sampleString = "Hello, QR Code!"
        if let qrCodeImage = UIImage.make(qrcode: sampleString, tint: UIColor.black) {
            imgview.image = qrCodeImage
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.