Swift - Image Data from Ciimage Qr Code/How to Render Cifilter Output

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

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

Sample Image

Given a CIImage, what is the fastest way to write image data to disk?

I would suggest passing the CGImage directly to ImageIO using CGImageDestination. You can pass a dictionary to CGImageDestinationAddImage to indicate the compression quality, image orientation, etc.

CFDataRef save_cgimage_to_jpeg (CGImageRef image)
{
CFMutableDataRef cfdata = CFDataCreateMutable(nil,0);
CGImageDestinationRef dest = CGImageDestinationCreateWithData(data, CFSTR("public.jpeg"), 1, NULL);
CGImageDestinationAddImage(dest, image, NULL);
if(!CGImageDestinationFinalize(dest))
; // error
CFRelease(dest);
return cfdata
}

iOS 7 Core Image QR Code generation too blur

I was about to start bounty on this question but i found the answer.

What you need is a scale filter. To achieve this with CoreImage, you need to do something like this:

CIImage *input = [CIImage imageWithCGImage: ImageView.Image.CGImage]; // input image is 100 X 100
CGAffineTransform transform = CGAffineTransformMakeScale(5.0f, 5.0f); // Scale by 5 times along both dimensions
CIImage *output = [input imageByApplyingTransform: transform];
// output image is now 500 X 500

FROM THIS SO ANSWER: https://stackoverflow.com/a/16316701/2859764

CIFilter output image nil

You cannot call UIImage(CIImage:) and use that UIImage as the image of a UIImageView. UIImageView requires a UIImage backed by a bitmap (CGImage). A UIImage instantiated with CIImage has no bitmap; it has no actual image, it's just a set of instructions for applying a filter. That is why your UIImageView's image is nil.

imageView.image = UIImage(ciImage: ) won't update a second time

Quick searching ... seems to be either a "bug" or a change...

Changing your generator code to this seems to correct the issue:

func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)

let context = CIContext()

if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 3, y: 3)

if let output = filter.outputImage?.transformed(by: transform) {
if let retImg = context.createCGImage(output, from: output.extent) {
return UIImage(cgImage: retImg)
}
}
}
return nil
}

func generateBarcode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)

let context = CIContext()

if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 3, y: 3)

if let output = filter.outputImage?.transformed(by: transform) {
if let retImg = context.createCGImage(output, from: output.extent) {
return UIImage(cgImage: retImg)
}
}
}
return nil
}

How to remove the gray Frame from QR code generator

Using the extension from the link I posted as a starting point:

extension String {
func qrCode(background: UIColor = .white, color: UIColor = .black, output: CGSize = CGSize(width: 250, height: 250))-> UIImage? {
guard
let data = data(using: .isoLatin1),
let filter = CIFilter(name: "CIQRCodeGenerator")
else { return nil }
filter.setValue(data, forKey: "inputMessage")
filter.setValue("M", forKey: "inputCorrectionLevel")
guard let image = filter.outputImage
else { return nil }
let size = image.extent.integral
let matrix = CGAffineTransform(scaleX: output.width / size.width, y: output.height / size.height)
UIGraphicsBeginImageContextWithOptions(output, false, 0)
defer { UIGraphicsEndImageContext() }
guard
let colorFilter = CIFilter(name: "CIFalseColor",
parameters: ["inputImage" : image.transformed(by: matrix),
"inputColor1": CIColor(color: background) ,
"inputColor0": CIColor(color: color)]),
let coloredImage = colorFilter.outputImage
else { return nil }
UIGraphicsBeginImageContextWithOptions(output, false, 0)
defer { UIGraphicsEndImageContext() }
UIImage(ciImage: coloredImage).draw(in: CGRect(origin: .zero, size: output))
return UIGraphicsGetImageFromCurrentImageContext()
}
}

let link = "https://stackoverflow.com/questions/51178573/swift-image-data-from-ciimage-qr-code-how-to-render-cifilter-output?noredirect=1"
if let coloredQRCode = link.qrCode(color: .red, output: CGSize(width: 500, height: 500)) {
coloredQRCode
}

Sample Image

How can I convert an UIImage to grayscale in Swift using CIFilter?

You can use CIColorControls and set Contrast Key kCIInputContrastKey to increase the black/white contrast as follow:

Xcode 9 • Swift 4

extension String {
static let colorControls = "CIColorControls"
}

extension UIImage {
var coreImage: CIImage? { return CIImage(image: self) }
}

extension CIImage {
var uiImage: UIImage? { return UIImage(ciImage: self) }
func applying(contrast value: NSNumber) -> CIImage? {
return applyingFilter(.colorControls, parameters: [kCIInputContrastKey: value])
}
func renderedImage() -> UIImage? {
guard let image = uiImage else { return nil }
return UIGraphicsImageRenderer(size: image.size,
format: image.imageRendererFormat).image { _ in
image.draw(in: CGRect(origin: .zero, size: image.size))
}
}
}

let url = URL(string: "https://i.stack.imgur.com/Xs4RX.jpg")!
do {
if let coreImage = UIImage(data: try Data(contentsOf: url))?.coreImage,
let increasedContrast = coreImage.applying(contrast: 1.5) {
imageView.image = increasedContrast.uiImage
// if you need to convert your image to data (JPEG/PNG) you would need to render the ciimage using renderedImage method on CIImage
}
} catch {
print(error)
}

To convert from colors to grayscale you can set the Saturation Key kCIInputSaturationKey to zero:

extension CIImage {
func applying(saturation value: NSNumber) -> CIImage? {
return applyingFilter(.colorControls, parameters: [kCIInputSaturationKey: value])
}
var grayscale: CIImage? { return applying(saturation: 0) }
}

let url = URL(string: "https://i.stack.imgur.com/Xs4RX.jpg")!
do {
if let coreImage = UIImage(data: try Data(contentsOf: url))?.coreImage,
let grayscale = coreImage.grayscale {
// use grayscale image here
imageView.image = grayscale.uiImage
}
} catch {
print(error)
}


Related Topics



Leave a reply



Submit