Swift - 从CIImage QR Code获取图像数据 / 如何呈现CIFilter输出

5

我已经遇到这个问题有一段时间了,看过这里的许多答案,似乎找不到任何有用的东西。

情景

我正在iOS应用程序的一侧生成QR码,并希望将此QR码发送到我目前正在开发的WatchKit扩展中。

我如何生成QR码

func createQR(with string: String) {

    if let filter = CIFilter(name: "CIQRCodeGenerator") {

        //set the data to the contact data
        filter.setValue(string, forKey: "inputMessage")
        filter.setValue("L", forKey: "inputCorrectionLevel")

        if let codeImage = filter.outputImage {
            return UIImage(ciImage: codeImage);
        }
    }
}

接下来我想要什么

我想要从QR图片中获取数据,以便将其发送到Apple Watch应用程序,如下所示:

let data = UIImagePNGRepresentation(QRCodeImage);

但是,这总是返回nil,因为没有图像数据支持来自滤镜的输出。
注意:我知道CI Image没有关联的数据,因为它还没有被渲染,甚至没有与之关联的数据,因为它只是从滤镜输出的结果。我不知道如何解决这个问题,因为我对图像处理等方面非常新手。: /
我尝试过创建一个cgImagefilter.outputImage
func createQR(with string: String) {
    if let filter = CIFilter(name: "CIQRCodeGenerator") {

        //set the data to the contact data
        filter.setValue(contactData, forKey: "inputMessage")
        filter.setValue("L", forKey: "inputCorrectionLevel")

        if let codeImage = filter.outputImage {
            let context = CIContext(options: nil)
            if let cgImage = context.createCGImage(codeImage, from: codeImage.extent) {
                self.QRCode = UIImage(cgImage: cgImage)
            }
        }
    }
}

但是这似乎无效,因为视图上的图像是空白的。

创建一个空的CIImage作为输入图像

func update(with string: String) {
    let blankCiImage = CIImage(color: .white) //This probably isn't right...
    if let filter = CIFilter(name: "CIQRCodeGenerator") {

        filter.setValue(contactData, forKey: "inputMessage")
        filter.setValue("L", forKey: "inputCorrectionLevel")
        filter.setValue(blankCiImage, forKey: kCIInputImageKey)

        if let codeImage = filter.outputImage {
            let context = CIContext(options: nil)
            if let cgImage = context.createCGImage(codeImage, from: codeImage.extent) {
                self.contactCode = UIImage(cgImage: cgImage)
                print(self.contactCode!)
                print(UIImagePNGRepresentation(self.contactCode!))
            }
        }
    }
}

这个也不行 - 我的想法是在上面添加一个空白图像,然后在其上面进行过滤,但我可能做得不对。

我的目标

简单来说,只是获取生成的QR码的数据。 大多数线程建议使用 UIImage(ciImage:output),但这没有任何支持数据。

如果有人可以帮我解决这个问题,那就太好了。并且对于它是如何工作的,任何解释都将是非常棒的。

编辑:我认为这与标记的重复不同 - 标记的重复是关于使用CI过滤器编辑现有图像并获取该数据,而这是关于仅通过CI过滤器创建的图像 - QR码。另一个答案没有完全相关。


你只需要重新绘制图像。与标记为重复的解决方案相同。 - Leo Dabus
你可以使用此答案中的CIImage扩展图像属性:https://dev59.com/WaDia4cB1Zd3GeqPB1Ir#43011878 - Leo Dabus
@LeoDabus 好的,我尝试了这个方法,但是在视图上显示我的图片时,它是一张空白的图片 - 或许是因为没有输入图片?嗯嗯。有什么想法吗? - Drew Wilken
1个回答

8

您的代码存在一些问题。在将字符串传递给过滤器之前,您需要使用字符串编码isoLatin1将其转换为数据。另一个问题是,要将CIImage转换为数据,您需要重新绘制/渲染CIImage,并在缩放图像时应用变换来增加其大小以防止图像模糊:

extension StringProtocol {
    var qrCode: UIImage? {
        guard
            let data = data(using: .isoLatin1),
            let outputImage = CIFilter(name: "CIQRCodeGenerator",
                              parameters: ["inputMessage": data, "inputCorrectionLevel": "M"])?.outputImage
        else { return nil }
        let size = outputImage.extent.integral
        let output = CGSize(width: 250, height: 250)
        let format = UIGraphicsImageRendererFormat()
        format.scale = UIScreen.main.scale
        return UIGraphicsImageRenderer(size: output, format: format).image { _ in outputImage
            .transformed(by: .init(scaleX: output.width/size.width, y: output.height/size.height))
            .image
            .draw(in: .init(origin: .zero, size: output))
        }
    }
}
extension CIImage {
    var image: UIImage { .init(ciImage: self) }
}

游乐场测试:
let link = "https://dev59.com/Xqzka4cB1Zd3GeqP_6ah"
let image = link.qrCode!
let data =  image.jpegData(compressionQuality: 1)  // 154785 bytes

enter image description here


1
谢谢,你太棒了。我搞定了。终于可以继续做其他事情了。非常感谢。 - Drew Wilken

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接