in my swift 2 app i can generate a QR Code like this:
let data = "1234567890".dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter!.setValue(data, forKey: "inputMessage")
filter!.setValue("Q", forKey: "inputCorrectionLevel")
qrcodeImage = filter!.outputImage
let transformedImage = qrcodeImage.imageByApplyingTransform(CGAffineTransformMakeScale(150, 150))
QRCodeImage.image = UIImage(CIImage: transformedImage)
but my QR Code get an white background image, but i would like to have an transparent background.
i tried something like this:
QRCodeImage.backgroundColor = UIColor.clearColor()
but this doesn't work.
any idea ? :)
It seems like the CIQRCodeGenerator filter always uses black and white.
You can pass the output into a CIMaskToAlpha filter to convert it to transparent:
And first you might want to use CIColorInvert to swap white & black.
For transparent background you should (use your instincts and) try like this ,
//Create a CIFalseColor Filter
let colorFilter: CIFilter = CIFilter(name: "CIFalseColor")!
colorFilter.setDefaults()
colorFilter.setValue(yourQRFilter.outputImage!, forKey: "inputImage")
//Then set the background colour like this,
let transparentBG: CIColor = CIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
colorFilter.setValue(qrColor, forKey: "inputColor0")
colorFilter.setValue(transparentBG, forKey: "inputColor1")
outputImage = colorFilter.outputImage!
This should yield you QRCode image with transparent background, I hope.
I think that the key will be on the alpha of the background. You can set or reduce alpha, reducing or deleting the transparency. Try something like this:
QRCodeImage.backgroundcolor = UIColor(white: 1, alpha: 0.5)
Hope it helps.
this is my code :
func QRImageFromData(_ data: Data) -> UIImage? {
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(data, forKey: "inputMessage")
//filter?.setValue("H", forKey: "inputCorrectionLevel")
//change qrcode color : #1e3259
let filterFalseColor = CIFilter(name: "CIFalseColor")
filterFalseColor?.setDefaults()
filterFalseColor?.setValue(filter?.outputImage, forKey: "inputImage")
// convert method
let cgColor: CGColor? = UIColor(hex: "#1e3259")?.cgColor
let qrColor: CIColor = CIColor(cgColor: cgColor!)
let transparentBG: CIColor = CIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
filterFalseColor?.setValue(qrColor, forKey: "inputColor0")
filterFalseColor?.setValue(transparentBG, forKey: "inputColor1")
if let image = filterFalseColor?.outputImage {
let transform = CGAffineTransform(scaleX: 5.0, y: 5.0)
return UIImage(ciImage: image.applying(transform),
scale: 1.0,
orientation: UIImageOrientation.up)
} else {
return nil
}
}
I obtained a qr with a transparent background following this tutorial.
Add these extensions:
extension CIImage {
/// Inverts the colors and creates a transparent image by converting the mask to alpha.
/// Input image should be black and white.
var transparent: CIImage? {
return inverted?.blackTransparent
}
/// Inverts the colors.
var inverted: CIImage? {
guard let invertedColorFilter = CIFilter(name: "CIColorInvert") else { return nil }
invertedColorFilter.setValue(self, forKey: "inputImage")
return invertedColorFilter.outputImage
}
/// Converts all black to transparent.
var blackTransparent: CIImage? {
guard let blackTransparentFilter = CIFilter(name: "CIMaskToAlpha") else { return nil }
blackTransparentFilter.setValue(self, forKey: "inputImage")
return blackTransparentFilter.outputImage
}
/// Applies the given color as a tint color.
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!
}
}
extension URL {
func qrImage(using color: UIColor) -> UIImage? {
let ciImage = qrCIImage?.tinted(using: color)
return ciImage != nil ? UIImage(ciImage: ciImage!) : nil
}
var qrImage: UIImage? {
return UIImage(ciImage: qrCIImage!)
}
/// Creates a QR code for the current URL in the given color.
func qrCIImage(using color: UIColor) -> CIImage? {
return qrCIImage?.tinted(using: color)
}
/// Returns a black and white QR code for this URL.
var qrCIImage: CIImage? {
guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
let qrData = absoluteString.data(using: String.Encoding.ascii)
qrFilter.setValue(qrData, forKey: "inputMessage")
let qrTransform = CGAffineTransform(scaleX: 12, y: 12)
return qrFilter.outputImage?.transformed(by: qrTransform)
}
}
And then use like this:
let myChosenColor = UIColor(red:0.93, green:0.31, blue:0.23, alpha:1.00)
let qrURLImage = URL(string: "https://stackoverflow.com")?.qrImage(using: myChosenColor)
myQrImageView.image = qrURLImage
Inside myQrImageView.image you will see a qr image with a transparent background:
In addition to answer of #jtbandes i have wrote some code so it would help others as well
extension UIImage {
func transparentBackground() -> UIImage? {
let context = CIContext(options: nil)
let filter = CIFilter(name: "CIMaskToAlpha")
filter?.setDefaults()
filter?.setValue(self.ciImage, forKey: kCIInputImageKey)
if let output = filter?.outputImage,
let imageRef = context.createCGImage(output, from: output.extent) {
return UIImage(cgImage: imageRef)
}
return nil
}
func invertColor() -> UIImage? {
let filter = CIFilter(name: "CIColorInvert")
filter?.setDefaults()
filter?.setValue(self.ciImage, forKey: kCIInputImageKey)
if let output = filter?.outputImage {
return UIImage(ciImage: output)
}
return nil
}
}
and use it like this
yourUIImage.invertColor()?.transparentBackground()
the transparentBackground() function will remove black color and leave the white where as invertColor() will will swap black with white
extension UIImage {
func alpha(_ value: CGFloat) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
draw(at: CGPoint.zero, blendMode: .normal, alpha: value)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
A ready solution in case you're looking for:
enum GeneratorType {
case qrCode, barCode, aztecCode
var filterName: String {
switch self {
case .aztecCode:
return "CIAztecCodeGenerator"
case .barCode:
return "CICode128BarcodeGenerator"
case .qrCode:
return "CIQRCodeGenerator"
}
}
}
func generateCode(type: GeneratorType, text: String,
transform: CGAffineTransform = CGAffineTransform(scaleX: 32.0, y: 32.0),
fillColor: UIColor = UIColor.black,
backgroundColor: CIColor = CIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)) -> UIImage? {
guard let filter = CIFilter(name: type.filterName) else {
return nil
}
filter.setDefaults()
guard let data = text.data(using: String.Encoding.utf8) else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
let filterFalseColor = CIFilter(name: "CIFalseColor")
filterFalseColor?.setDefaults()
filterFalseColor?.setValue(filter.outputImage, forKey: "inputImage")
filterFalseColor?.setValue(CIColor(cgColor: fillColor.cgColor), forKey: "inputColor0")
filterFalseColor?.setValue(backgroundColor, forKey: "inputColor1")
guard let image = filterFalseColor?.outputImage else { return nil }
return UIImage(ciImage: image.transformed(by: transform), scale: 1.0,
orientation: UIImage.Orientation.up)
}
Usage:
let qrImage = generateCode(type: .qrCode, text: "some text")
Peace!
Related
I want a blur effect to UIImage as slider value changes.
I am using the CIGaussianBlur filter to blur the image.
The code is as follows
func applyBlurFilter(aCIImage: CIImage, val: CGFloat) -> UIImage {
let clampFilter = CIFilter(name: "CIAffineClamp")
clampFilter?.setDefaults()
clampFilter?.setValue(aCIImage, forKey: kCIInputImageKey)
let blurFilter = CIFilter(name: "CIGaussianBlur")
blurFilter?.setValue(clampFilter?.outputImage, forKey: kCIInputImageKey)
blurFilter?.setValue(val, forKey: kCIInputRadiusKey)
let rect = aCIImage.extent
if let output = blurFilter?.outputImage {
if let cgimg = self.context.createCGImage(output, from: rect) {
let processedImage = UIImage(cgImage: cgimg)
return processedImage
}
}
return image ?? self.image
}
Note: I've also tried the below code using CICrop filter
func applyBlurFilter(beginImage: CIImage, value: Float) -> UIImage? {
let currentFilter = CIFilter(name: "CIGaussianBlur")
currentFilter?.setValue(beginImage, forKey: kCIInputImageKey)
currentFilter?.setValue(value, forKey: kCIInputRadiusKey)
let cropFilter = CIFilter(name: "CICrop")
cropFilter?.setValue(currentFilter!.outputImage, forKey: kCIInputImageKey)
cropFilter?.setValue(CIVector(cgRect: beginImage!.extent), forKey: "inputRectangle")
let output = cropFilter?.outputImage
let context = CIContext(options: nil)
let cgimg = self.context.createCGImage(output!, from: beginImage!.extent)
let processedImage = UIImage(cgImage: cgimg!)
return processedImage
}
The code works perfectly with some images, but with bigger images, while applying the blur filter to the image, the image's right edges get transparent which I don't want.
Note: I am running this on device
What am I doing wrong here, I have no idea
The image whose right edge gets transparant
Result after applying GaussianBlur to the above image
Thanks!!
Well, you're doing something wrong somewhere. The absolute best advice I can give you in your career is to create a small test project to experiment when you have such an issue - I've done this for 15 years in the Apple world, and its been of enormous help.
I created a project here so you don't have to (this time). I downloaded the image, placed it in an ImageView, and it looked perfect (as expected). I then used your code (except I had to create a context, and guess at radius values, then ran it. Image looks perfect with a blur of 0, 5, 10, and 25.
Obviously the issue is something else you are doing. What I suggest is that you keep adding to the test project until you can find what step is the problem (context? other image processing?)
This is the entirety of my code:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let im1 = UIImage(named: "Image.jpg")!
let cim = CIImage(image: im1)!
let im2 = applyBlurFilter(aCIImage: cim, val: 25)
let iv = UIImageView(image: im2)
iv.contentMode = .scaleToFill
self.view.addSubview(iv)
}
func applyBlurFilter(aCIImage: CIImage, val: CGFloat) -> UIImage {
let clampFilter = CIFilter(name: "CIAffineClamp")
clampFilter?.setDefaults()
clampFilter?.setValue(aCIImage, forKey: kCIInputImageKey)
let blurFilter = CIFilter(name: "CIGaussianBlur")
blurFilter?.setValue(clampFilter?.outputImage, forKey: kCIInputImageKey)
blurFilter?.setValue(val, forKey: kCIInputRadiusKey)
let rect = aCIImage.extent
if let output = blurFilter?.outputImage {
let context = CIContext(options: nil)
if let cgimg = context.createCGImage(output, from: rect) {
let processedImage = UIImage(cgImage: cgimg)
return processedImage
}
}
fatalError()
}
}
I create one QRCode Generator with deferent color I want to remove the Gray color in Frame and have really one white color or clear color after I use the filter this gray color
generate some time
let data = string.data(using: .isoLatin1, allowLossyConversion: false)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
guard let colorFilter = CIFilter(name: "CIFalseColor") else { return nil }
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel")
colorFilter.setValue(filter.outputImage, forKey: "inputImage")
colorFilter.setValue(CIColor(color: UIColor.clear), forKey: "inputColor1")
colorFilter.setValue(CIColor(color: UIColor.black), forKey: "inputColor0")
guard let qrCodeImage = colorFilter.outputImage
else {
return nil
}
let scaleX = imageView.frame.size.width / qrCodeImage.extent.size.width
let scaleY = imageView.frame.size.height / qrCodeImage.extent.size.height
let transform = CGAffineTransform(scaleX: scaleX, y: scaleY)
if let output = colorFilter.outputImage?.transformed(by: transform) {
let image = convert(cmage:(output.transformed(by: CGAffineTransform(scaleX: scaleX, y: scaleY))))
return image
}
}
return nil
}
func convert(cmage:CIImage) -> UIImage
{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
if I don't use the filter for change the color I don't have this problem
or If I used the blue color I have one frame with aqua blue color
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
}
I am applying a number of core image filters to an image that I have captured. The problem that I am facing is that once I have applied the filters and saved the resulting image, I am unable to save it. I do not get any errors in my code but when I go to retrieve the image the application is unable to locate it. It says that the file does not exist. I suspect I may have used the filters incorrectly some how.
// PROCESS IMAGE TO MAKE IT LOOK 'SCANNED'
guard let scannedImage = self.processImage(image: image)else{
print("failed to process image")
return
}
// SAVE SCANNED IMAGE TO LOCAL FILE SYSTEM
self.saveImageToLocalFile(image: scannedImage) // PROBELM HERE.
// PROCESS IMAGE
func processImage(image: UIImage) -> UIImage? {
guard let ciimage = CIImage.init(image: image) else{return nil}
// APPLY FILTERS
guard let shadowCimage = shadow(inputImage: ciimage) else{return nil}
guard let colorControlCimage = colorControl(input: shadowCimage, contrast: 4.0, saturation: 0.3, brightness: 0.3) else{return nil}
guard let sharpenCimage = sharpen(inputImage: colorControlCimage, inputRadius: 2.5, inputIntensity: 1.0) else {return nil}
guard let sharpIntensity = sharpenLumin(inputImg: sharpenCimage, inputSharpness: 0.2) else{return nil}
print("processImage END")
return UIImage.init(ciImage: sharpIntensity)
}
// FILTER 'CIColorControls'
func colorControl(input: CIImage, contrast: Float, saturation: Float, brightness: Float) -> CIImage? {
let filter = CIFilter(name: "CIColorControls")
filter?.setValue(input, forKey: kCIInputImageKey)
filter?.setValue(contrast, forKey: kCIInputContrastKey)
filter?.setValue(saturation, forKey: kCIInputSaturationKey)
filter?.setValue(brightness, forKey: kCIInputBrightnessKey)
return filter?.outputImage
}
// FILTER 'CIUnsharpMask'
func sharpen(inputImage: CIImage, inputRadius: Float, inputIntensity: Float) -> CIImage? {
let filter = CIFilter(name: "CIUnsharpMask")
filter?.setValue(inputImage, forKey: kCIInputImageKey)
//filter?.setDefaults()
filter?.setValue(inputRadius, forKey: kCIInputRadiusKey)
filter?.setValue(inputIntensity, forKey: kCIInputIntensityKey)
return filter?.outputImage
}
// FILTER 'CIHighlightShadowAdjust'
func shadow(inputImage: CIImage) -> CIImage? {
let filter = CIFilter(name: "CIHighlightShadowAdjust")
filter?.setValue(inputImage, forKey: kCIInputImageKey)
filter?.setDefaults()
return filter?.outputImage
}
// FILTER 'CISharpenLuminance'
func sharpenLumin(inputImg: CIImage, inputSharpness: Float) -> CIImage? {
let filter = CIFilter.init(name: "CISharpenLuminance")
filter?.setValue(inputImg, forKey: kCIInputImageKey)
filter?.setValue(inputSharpness, forKey: kCIInputSharpnessKey)
return filter?.outputImage
}
// SAVE UIIMAGE TO LOCAL FILE SYSTEM
func saveImageToLocalFile(image: UIImage) -> Void {
// CREATE URL - SAVE TO PATH
let imageURL = createPhotoURL() // CORRECT FULL LENGTH URL FOR FILE UPLAOD
print("IMAGE SAVED TO URL: \(imageURL)")
let imageData = UIImageJPEGRepresentation(image, 1.0)
do{
try imageData?.write(to: imageURL)
self.scannedImageURL = imageURL
}catch{
print("error writing img to local dir")
}
}
The problem is that your imageData is nil, because of how you are creating the UIImage.
As explained in this answer, you have a nil in the UIImage.cgImage property, which UIImageJPEGRepresentation uses. Here's the code you need to use:
func saveImageToLocalFile(image: UIImage) -> Void {
let imageURL = createPhotoURL()
var uiImage = image
if image.cgImage == nil {
guard let ciImage = image.ciImage, let cgImage = CIContext(options: nil).createCGImage(ciImage, from: ciImage.extent) else { return }
uiImage = UIImage(cgImage: cgImage)
}
if let imageData = UIImageJPEGRepresentation(uiImage, 1.0) {
do {
try imageData?.write(to: imageURL)
self.scannedImageURL = imageURL
} catch {
print("error writing img to local dir")
}
} else {
print("could not create JPEG image")
}
}
In an image editing app, I am trying to show clipped highlights and shadows using CIFilters.
Filter List
I know there isn't a straight single filter for this, will have to be a combination of few together.
Any ideas? Thanks in advance.
CIFilters can add one after another. for example: i can first adjust shadow on image and than crop it.
func addFilters(toImage image: UIImage) -> UIImage? {
guard let cgImage = image.cgImage else { return nil }
let ciImage = CIImage(cgImage: cgImage)
//add adjust shadow filter
guard let shadowAdjust = CIFilter(name: "CIHighlightShadowAdjust") else { return nil }
shadowAdjust.setValue(ciImage, forKey: kCIInputImageKey)
shadowAdjust.setValue(1, forKey: "inputHighlightAmount")
shadowAdjust.setValue(3, forKey: "inputShadowAmount")
guard let output1 = shadowAdjust.outputImage else { return nil }
//now output result crop 80%
guard let crop = CIFilter(name: "CICrop") else { return nil }
crop.setValue(ciImage, forKey: kCIInputImageKey)
crop.setValue(CIVector(x: output1.extent.origin.x, y: output1.extent.origin.y, z: output1.extent.size.width * 0.8, w: output1.extent.size.height * 0.8), forKey: "inputRectangle")
guard let output2 = crop.outputImage else { return UIImage(ciImage: output1) }
//the image will be croped and shadow adjusted
return UIImage(ciImage: output2)
}
How can I achieve the output in iOS using Objective-C .. Image-1 + Image-2 = Image-3 ?
How can I achieve the output in iOS using Objective-C .. Image-1 + Image-2 = Image-3 ?
//: Playground - noun: a place where people can play
import UIKit
import CoreImage
func aspectFill(from: CGRect, to: CGRect) -> CGAffineTransform {
let horizontalRatio = to.width / from .width
let verticalRatio = to.height / from.height
let scale = max(horizontalRatio, verticalRatio)
let translationX = horizontalRatio < verticalRatio ? (to.width - from.width * scale) * 0.5 : 0
let translationY = horizontalRatio > verticalRatio ? (to.height - from.height * scale) * 0.5 : 0
return CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: translationX, y: translationY)
}
func filter(image: UIImage, texture: UIImage) -> UIImage? {
guard let imageCI = CIImage(image: image),
let textureCI = CIImage(image: texture)
else {
return nil
}
let scaleFillTextureCI = textureCI.applying(aspectFill(from: textureCI.extent, to: imageCI.extent))
let crop = CIFilter(name: "CICrop")!
crop.setValue(scaleFillTextureCI, forKey: "inputImage")
crop.setValue(imageCI.extent, forKey: "inputRectangle")
let alpha = CIFilter(name: "CIConstantColorGenerator")!
alpha.setValue(CIColor.init(red: 0, green: 0, blue: 0, alpha: 0.7), forKey: "inputColor")
let mix = CIFilter(name: "CIBlendWithAlphaMask")!
mix.setValue(imageCI, forKey: "inputImage")
mix.setValue(crop.outputImage, forKey: "inputBackgroundImage")
mix.setValue(alpha.outputImage, forKey: "inputMaskImage")
let blend = CIFilter(name: "CIBlendWithMask")!
blend.setValue(imageCI, forKey: "inputImage")
blend.setValue(mix.outputImage, forKey: "inputBackgroundImage")
blend.setValue(imageCI, forKey: "inputMaskImage")
let context = CIContext(options: nil)
guard let ciImage = blend.outputImage,
let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
return nil
}
return UIImage(cgImage: cgImage)
}
let image = #imageLiteral(resourceName: "image.jpg")
let texture = #imageLiteral(resourceName: "texture.jpg")
let output = filter(image: image, texture: texture)]
I have solution in Swift since I am not familiar with Objective-C syntax, but I think you can translate to Objective-C easily.
You can achieve the effect by using CoreImage. Here the result from Xcode Playground. Screenshot