I want add lights effect on image. I have masked on that and this is my image
For that I have code to use masking image
func maskImage(image:UIImage, mask:(UIImage))->UIImage{
let imageReference = image.cgImage
let maskReference = mask.cgImage
let imageMask = CGImage(maskWidth: maskReference!.width,
height: maskReference!.height,
bitsPerComponent: maskReference!.bitsPerComponent,
bitsPerPixel: maskReference!.bitsPerPixel,
bytesPerRow: maskReference!.bytesPerRow,
provider: maskReference!.dataProvider!, decode: nil, shouldInterpolate: true)
let maskedReference = imageReference!.masking(imageMask!)
let maskedImage = UIImage(cgImage:maskedReference!)
return maskedImage
}
And result is get to this
it will get only in white
Please help me
I'm assuming you want to remove the black background and just show the lens flare. For this you can use screen blend mode.
func filteredImage(image: UIImage, effect: UIImage) -> UIImage? {
guard let imageReference = CIImage(image: image),
let effectReference = CIImage(image: effect) else {
return nil
}
let filteredCIImage = effectReference.applyingFilter(
"CIScreenBlendMode",
parameters: [kCIInputBackgroundImageKey: imageReference]
)
let filteredImage = UIImage(ciImage: filteredCIImage)
return filteredImage
}
Related
Is there an option to replicate func masking(_ mask: CGImage) -> CGImage? from Core Graphics using CoreImage and one of CIFilter? I've tried CIBlendWithMask and CIBlendWithAlphaMask without success. Most important thing is that I need to preserve alpha channel, so I want image to be masked in such way, that if mask is black -> show Image, if mask is white -> transparent.
My masking code:
extension UIImage {
func masked(by mask: UIImage) -> UIImage {
guard let maskRef = mask.cgImage,
let selfRef = cgImage,
let dataProvider = maskRef.dataProvider,
let mask = CGImage(
maskWidth: maskRef.width,
height: maskRef.height,
bitsPerComponent: maskRef.bitsPerComponent,
bitsPerPixel: maskRef.bitsPerPixel,
bytesPerRow: maskRef.bytesPerRow,
provider: dataProvider,
decode: nil,
shouldInterpolate: false),
let masked = selfRef.masking(mask) else {
fatalError("couldnt create mask!")
}
let maskedImage = UIImage(cgImage: masked)
return maskedImage
}
}
I found solution. Key is to use image that has grayscale format, rgb and other will not work. Resizing step can be removed, if image and maks have the same size. Doable as extension, can be done as subclass of CIImage too. Enjoy:)
Of course It can be modified as extension to UIImage, CIImage, CIFilter, how You like it.
extension CGImage {
func masked(by cgMask: CGImage) -> CIImage {
let selfCI = CIImage(cgImage: self)
let maskCI = CIImage(cgImage: cgMask)
let maskFilter = CIFilter(name: "CIMaskToAlpha")
maskFilter?.setValue(maskCI, forKey: "inputImage")
let scaleFilter = CIFilter(name: "CILanczosScaleTransform")
scaleFilter?.setValue(maskFilter?.outputImage, forKey: "inputImage")
scaleFilter?.setValue(selfCI.extent.height / maskCI.extent.height, forKey: "inputScale")
let filter: CIFilter! = CIFilter(name: "CIBlendWithAlphaMask")
filter.setValue(selfCI, forKey: "inputBackgroundImage")
let maskOutput = scaleFilter?.outputImage
filter.setValue(maskOutput, forKey: "inputMaskImage")
let outputImage = filter.outputImage!
return outputImage
}
}
You need to create your own custom CIFilter. The tutorials:
Apple Docs
Apple Docs 2
Raywenderlich.com Tutorial
This is not trivial, but it pays off when you learn how to do it :)
Given this image:
Is there a way to get a bezier path of the non-alpha parts from this image? Here, it would be the part delimited by the cat.
I know how to mask an image with another one:
func maskImage(image: UIImage, withMask maskImage: UIImage) -> UIImage {
let maskRef = maskImage.cgImage
let mask = CGImage(
maskWidth: maskRef!.width,
height: maskRef!.height,
bitsPerComponent: maskRef!.bitsPerComponent,
bitsPerPixel: maskRef!.bitsPerPixel,
bytesPerRow: maskRef!.bytesPerRow,
provider: maskRef!.dataProvider!,
decode: nil,
shouldInterpolate: false)
let masked = image.cgImage!.masking(mask!)
let maskedImage = UIImage(cgImage: masked!)
return maskedImage
}
But don't know how to get a bezier path from this.
Thanks for your help!
I'm trying to resize a CVPixelBuffer to a size of 128x128. I'm working with one that is 750x750. I'm currently using the CVPixelBuffer to create a new CGImage, which I resize then convert back into a CVPixelBuffer. Here is my code:
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let context = CIContext()
let imageRect = CGRect(x: 0, y: 0, width: 128, height: 128)
if let image = context.createCGImage(ciImage, from: imageRect) {
let t = CIImage(cgImage: image)
let new = t.applying(transformation)
context.render(new, to: pixelBuffer)
return UIImage(cgImage: image, scale: UIScreen.main.scale, orientation: .right)
}
}
return nil
}
I've also tried scaling the CIImage then converting it:
let t = CIImage(cgImage: image)
let transformation = CGAffineTransform(scaleX: 1, y: 2)
let new = t.applying(transformation)
context.render(new, to: pixelBuffer)
But that didn't work either.
Any help is appreciated. Thanks!
There's no need for pixel buffer rendering and alike. Just transform the original CIImage and crop to size. Cropping is necessary if you source and destination dimensions aren't proportional.
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let srcWidth = CGFloat(ciImage.extent.width)
let srcHeight = CGFloat(ciImage.extent.height)
let dstWidth: CGFloat = 128
let dstHeight: CGFloat = 128
let scaleX = dstWidth / srcWidth
let scaleY = dstHeight / srcHeight
let scale = min(scaleX, scaleY)
let transform = CGAffineTransform.init(scaleX: scale, y: scale)
let output = ciImage.transformed(by: transform).cropped(to: CGRect(x: 0, y: 0, width: dstWidth, height: dstHeight))
return UIImage(ciImage: output)
}
return nil
}
Try this
func getImageFromSampleBuffer (buffer:CMSampleBuffer) -> UIImage? {
if let pixelBuffer = CMSampleBufferGetImageBuffer(buffer) {
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
let resizedCIImage = ciImage.applying(CGAffineTransform(scaleX: 128.0 / 750.0, y: 128.0 / 750.0))
let context = CIContext()
if let image = context.createCGImage(resizedCIImage, from: resizedCIImage.extent) {
return UIImage(cgImage: image)
}
}
return nil
}
Here I assume that pixel buffer is square and size is equal to 750x750, you can change it to work with all aspect ratios and sizes
I am experiencing a problem using CIQRCodeGenerator to create a QR code: when I generate the code at first, it is crisp, but when I run the function again, with the same input, the QR code becomes blurry:
Initial Run (more clear):
Second Run (more blurry):
The following function is first called in viewWillAppear and subsequently triggered after the user taps a button.
func generateQRCodeFromString(string: String) -> UIImage? {
let data = string.dataUsingEncoding(NSISOLatin1StringEncoding)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel")
let transform = CGAffineTransformMakeScale(10, 10)
if let output = filter.outputImage?.imageByApplyingTransform(transform) {
return UIImage(CIImage: output)
}
}
return nil
}
A sample project illustrating the problem is available here: http://jakeserver.com/Uploads/Apps/QR_Test.zip
Is there a reason why the UIImage becomes blurry after the function is run a second time with the same input?
EDIT - Added More Information
override func viewDidLoad() {
super.viewDidLoad()
qrCode.image = generateQRCodeFromString("test", size: qrCode.frame.size);
}
override func viewWillLayoutSubviews() {
qrCodeWidth.constant = self.view.frame.width * 0.8;
}
#IBAction func buttonTapped(sender: AnyObject) {
qrCode.image = generateQRCodeFromString("test", size: qrCode.frame.size);
}
I'm not sure why the blurriness changes between runs (maybe an internal implementation detail), but in Objective-C code I worked around this by making the QR code and then manually writing the image into a larger sized bitmap context.
I took a stab at porting that code to Swift and came up with this:
func generateQRCodeFromString(string: String, size: CGSize) -> UIImage? {
guard let data = string.dataUsingEncoding(NSISOLatin1StringEncoding),
let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
filter.setDefaults()
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel")
guard let image = filter.outputImage else { return nil }
let extent = CGRectIntegral(image.extent)
let scale = min(size.width / extent.width, size.height / extent.height);
let (height, width) = (extent.height * scale, extent.width * scale)
let colorSpace = CGColorSpaceCreateDeviceGray()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.None.rawValue)
guard let bitmapContext = CGBitmapContextCreate(nil, Int(width), Int(height), 8, 0, colorSpace, bitmapInfo.rawValue) else { return nil }
CGContextSetInterpolationQuality(bitmapContext, CGInterpolationQuality.None)
CGContextScaleCTM(bitmapContext, CGFloat(scale), CGFloat(scale))
CGContextDrawImage(bitmapContext, extent, CIContext().createCGImage(image, fromRect: extent))
if let scaledImage = CGBitmapContextCreateImage(bitmapContext) {
return UIImage(CGImage: scaledImage)
// You might need to use this instead:
// return UIImage(CGImage: <#T##CGImage#>, scale: <#T##CGFloat#>, orientation: <#T##UIImageOrientation#>)
}
return nil
}
Will that work for your use case?
BTW, I don't think this caused your issue, but you weren't unwrapping data (dataUsingEncoding(_:) returns NSData? not NSData).
Updated version of Aaron's great answer, for Swift 5+
func generateQRCodeFromString(string: String, size: CGSize) -> UIImage? {
guard let data = string.data(using: .isoLatin1),
let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
filter.setDefaults()
filter.setValue(data, forKey: "inputMessage")
filter.setValue("H", forKey: "inputCorrectionLevel")
guard let image = filter.outputImage else { return nil }
let extent = CGRectIntegral(image.extent)
let scale = min(size.width / extent.width, size.height / extent.height);
let (height, width) = (extent.height * scale, extent.width * scale)
let colorSpace = CGColorSpaceCreateDeviceGray()
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue)
guard let bitmapContext = CGContext(data: nil, width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: 0, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else { return nil }
bitmapContext.interpolationQuality = CGInterpolationQuality.none
bitmapContext.scaleBy(x: CGFloat(scale), y: CGFloat(scale))
bitmapContext.draw(CIContext().createCGImage(image, from: extent)!, in: extent)
if let scaledImage = bitmapContext.makeImage() {
return UIImage(cgImage: scaledImage)
}
return nil
}
I am trying to generate QR Code using iOS Core Image API:
func createQRForString(#data : NSData)->CIImage!{
var qrFilter = CIFilter(name: "CIQRCodeGenerator")
qrFilter.setValue(data, forKey: "inputMessage")
qrFilter.setValue("H", forKey:"inputCorrectionLevel")
return qrFilter.outputImage
}
func createNonInterpolatedImageFromCIImage(image : CIImage,withScale scale:CGFloat)->UIImage{
let cgImage = CIContext(options: nil).createCGImage(image, fromRect: image.extent())
UIGraphicsBeginImageContext(CGSizeMake(image.extent().size.width*scale, image.extent().size.height*scale))
let context = UIGraphicsGetCurrentContext()
CGContextSetInterpolationQuality(context, kCGInterpolationNone)
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return scaledImage
}
And the following code in viewDidLoad method :
let data = "Hello World".dataUsingEncoding(NSUTF8StringEncoding)
if let image=createQRForString(data: data!){
let uiimage = createNonInterpolatedImageFromCIImage(image, withScale: 1.0)
imageView.image = uiimage
}
else{
println("Error loading image")
}
}
But it neither prints "Error" nor shows qr code in the imageView.
Here is the solution:
override func viewDidLoad() {
super.viewDidLoad()
self.imgView.image = generateCode()
}
func generateCode() -> UIImage {
let filter = CIFilter(name: "CIQRCodeGenerator")
let data = "Hello World".dataUsingEncoding(NSUTF8StringEncoding)
filter.setValue("H", forKey:"inputCorrectionLevel")
filter.setValue(data, forKey:"inputMessage")
let outputImage = filter.outputImage
let context = CIContext(options:nil)
let cgImage = context.createCGImage(outputImage, fromRect:outputImage.extent())
let image = UIImage(CGImage:cgImage, scale:1.0, orientation:UIImageOrientation.Up)
let resized = resizeImage(image!, withQuality:kCGInterpolationNone, rate:5.0)
return resized
}
func resizeImage(image: UIImage, withQuality quality: CGInterpolationQuality, rate: CGFloat) -> UIImage {
let width = image.size.width * rate
let height = image.size.height * rate
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), true, 0)
let context = UIGraphicsGetCurrentContext()
CGContextSetInterpolationQuality(context, quality)
image.drawInRect(CGRectMake(0, 0, width, height))
let resized = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return resized;
}