Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

ios - Swift - Image Data From CIImage QR Code / How to render CIFilter Output

I've been having this problem for a while now and looked at dozens of answers here and can't seem to find anything that helps.

Scenario

I am generating a QR Code on the iOS side of my app and want this QR code to be sent to the WatchKit Extension that I am currently developing.

How I am generating the QR Code

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

What I want next

I want to get the data from the QR image so that I can send it to the Apple Watch app, like so:

let data = UIImagePNGRepresentation(QRCodeImage);

But, This always returns nil because there is no image data backing the output from the filter.

Note: I know that there is no data associated with the CI Image because it hasn't been rendered and doesn't even have data associated with it because it's just the output from the filter. I don't know how to get around this because I'm pretty new to image processing and such. :/

What I've Tried

Creating a cgImage from the filter.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)
            }
        }
    }
}

But this doesn't work, it doesn't seem, because the image on the view is blank.

Creating a blank CIImage as Input Image

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

This doesn't work either - my thought was to add a blank image to it and then do the filter on top of it, but I am probably not doing this right.

My Goal

Literally, just to get the data from the generated QR Code. Most threads suggest UIImage(ciImage: output) , but this doesn't have any backing data.

If anyone could help me out with this, that'd be great. And any explanation on how it works would be wonderful too.

Edit: I don't believe this is the same as the marked duplicate - The marked duplicate is about editing an existing image using CI filters and getting that data and this is about an image that is solely created through CI filter with no input image - QR Codes. the other answer did not fully relate.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have a couple of issues in your code. You need to convert your string to data using String Encoding isoLatin1 before passing it to the filter. Another issue is that to convert your CIImage to data you need to redraw/render your CIImage and to prevent blurring the image when scaled you need to apply a transform to the image to increase its size:

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

Playground testing:

let link = "https://stackoverflow.com/questions/51178573/swift-image-data-from-ciimage-qr-code-how-to-render-cifilter-output?noredirect=1"
let image = link.qrCode!
let data =  image.jpegData(compressionQuality: 1)  // 154785 bytes

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...