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
}
Related
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
I am a new iOS developer. I was wondering how can I generate a barcode in Swift.
I have the code already, there are multiple resources from where to learn how to read a barcode, but I didn't find any that talks about generating one from a string.
Thanks a lot!
P.S. I know there is a similar question about this, but it's for Objective-C. I don't know Obj-C and I find it difficult coming from .NET.
You could use a CoreImage (import CoreImage) filter to do that!
class Barcode {
class func fromString(string : String) -> UIImage? {
let data = string.data(using: .ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
if let outputCIImage = filter.outputImage {
return UIImage(ciImage: outputCIImage)
}
}
return nil
}
}
let img = Barcode.fromString("whateva")
A newer version, with guard and failable initialiser:
extension UIImage {
convenience init?(barcode: String) {
let data = barcode.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage = filter.outputImage else {
return nil
}
self.init(ciImage: ciImage)
}
}
Usage:
let barcode = UIImage(barcode: "some text") // yields UIImage?
According to the docs :
Generates an output image representing the input data according to the
ISO/IEC 15417:2007 standard. The width of each module (vertical line)
of the barcode in the output image is one pixel. The height of the
barcode is 32 pixels. To create a barcode from a string or URL,
convert it to an NSData object using the NSASCIIStringEncoding string
encoding.
Improved code:
Barcode scaling
Set barcode image margin
Convert the UIImage to NSData (for some reason it wasn't possible with the code above).
It won't fail when sharing the barcode image (probably because of the same bug)
Swift 3
func generateBarcode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setDefaults()
//Margin
filter.setValue(7.00, forKey: "inputQuietSpace")
filter.setValue(data, forKey: "inputMessage")
//Scaling
let transform = CGAffineTransform(scaleX: 3, y: 3)
if let output = filter.outputImage?.applying(transform) {
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
let rawImage:UIImage = UIImage.init(cgImage: cgImage)
//Refinement code to allow conversion to NSData or share UIImage. Code here:
//http://stackoverflow.com/questions/2240395/uiimage-created-from-cgimageref-fails-with-uiimagepngrepresentation
let cgimage: CGImage = (rawImage.cgImage)!
let cropZone = CGRect(x: 0, y: 0, width: Int(rawImage.size.width), height: Int(rawImage.size.height))
let cWidth: size_t = size_t(cropZone.size.width)
let cHeight: size_t = size_t(cropZone.size.height)
let bitsPerComponent: size_t = cgimage.bitsPerComponent
//THE OPERATIONS ORDER COULD BE FLIPPED, ALTHOUGH, IT DOESN'T AFFECT THE RESULT
let bytesPerRow = (cgimage.bytesPerRow) / (cgimage.width * cWidth)
let context2: CGContext = CGContext(data: nil, width: cWidth, height: cHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: cgimage.bitmapInfo.rawValue)!
context2.draw(cgimage, in: cropZone)
let result: CGImage = context2.makeImage()!
let finalImage = UIImage(cgImage: result)
return finalImage
}
}
return nil
}
If your deployment target is at least iOS 8, you can use Core Image. Here is my BarcodeGenerator class (you need to import CoreImage):
class BarcodeGenerator {
enum Descriptor: String {
case code128 = "CICode128BarcodeGenerator"
case pdf417 = "CIPDF417BarcodeGenerator"
case aztec = "CIAztecCodeGenerator"
case qr = "CIQRCodeGenerator"
}
class func generate(from string: String,
descriptor: Descriptor,
size: CGSize) -> CIImage? {
let filterName = descriptor.rawValue
guard let data = string.data(using: .ascii),
let filter = CIFilter(name: filterName) else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let image = filter.outputImage else {
return nil
}
let imageSize = image.extent.size
let transform = CGAffineTransform(scaleX: size.width / imageSize.width,
y: size.height / imageSize.height)
let scaledImage = image.transformed(by: transform)
return scaledImage
}
}
It can be used like this
BarcodeGenerator.generate(from: "barcode-string",
descriptor: .code128,
size: CGSize(width: 800, height: 300))
Use like this,
func createBarcodeFromString(barcode:String)->UIImage?{
let data = self.data(using: .isoLatin1)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
filter.setValue(7.0, forKey:"inputQuietSpace")
guard var ciImage = filter.outputImage else {
return nil
}
let imageSize = ciImage.extent.integral
let outputSize = CGSize(width:320, height: 60)
ciImage = ciImage.transformed(by:CGAffineTransform(scaleX: outputSize.width/imageSize.width, y: outputSize.height/imageSize.height))
let image = convertCIImageToUIImage(ciimage: ciImage)
return image
}
func convertCIImageToUIImage(ciimage:CIImage)->UIImage{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(ciimage, from: ciimage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
Before I asking this question, I have searched the related post:
"unrecognized selector" when attempting to access CIFilter's outputImage
I don't know if is because of using swift or extension, I will get error. I have tested two methods to get the CIImage, but fails in EXC_BAD_INSTRUCTION:
Attention
my url is not http:// prefix, but weixin://wxpay/bizpayurl?pr=ZwBVaW0, and I think this is not the reason of the error.
Method one:
extension String {
func initQRImage() ->UIImage {
let filter:CIFilter = CIFilter.init(name: "CIQRCodeGenerator")!
filter.setDefaults()
let data:Data = self.data(using: String.Encoding.utf8)!
filter.setValue(data, forKey: "inputMessage")
let outputImage:CGImage = filter.outputImage as! CGImage // EXC_BAD_INSTRUCTION here
let qr_image = UIImage.init(cgImage: outputImage)
return qr_image
}
}
Method two:
extension String {
func initQRImage() ->UIImage {
let url:URL = URL.init(fileURLWithPath: self)
let inputImage:CIImage = CIImage.init(contentsOf: url)! // EXC_BAD_INSTRUCTION here
let filter: CIFilter = CIFilter.init(name: "CIAreaAverage")!
filter.setValue(inputImage, forKey: kCIInputImageKey)
let inputExtent:CGRect = inputImage.extent
let extent:CIVector = CIVector.init(x: inputExtent.origin.x, y: inputExtent.origin.y, z: inputExtent.size.width, w: inputExtent.size.height)
filter.setValue(extent, forKey: kCIInputExtentKey)
let outputImage:CIImage = filter.value(forKey: "outputImage") as! CIImage
let qr_image = UIImage.init(cgImage: outputImage as! CGImage)
return qr_image
}
}
Two method will report EXC_BAD_INSTRUCTION error here, you can see the annotation I write after the report error line.
EDIT - 1
I have tried in my project again, not using extension, there is the error too, and data is not nil:
I think the data is nil.
let data:Data = self.data(using: String.Encoding.utf8)!
Also an UIImage instantiated with CIImage has no bitmap, it has no actual image, it's just a set of instructions for applying a filter. So your methods to convert to UIImage shouldn't work.
Finally I found a outdated method to generate QR code, after my improvement, it becomes this:
// quality can modify the defintion
class func generateQRImage(stringQR:NSString, withSizeRate rate:CGFloat, quality:CGFloat?) -> UIImage
{
let filter:CIFilter = CIFilter(name:"CIQRCodeGenerator")!
filter.setDefaults()
let data:NSData = stringQR.data(using: String.Encoding.utf8.rawValue)! as NSData
filter.setValue(data, forKey: "inputMessage")
let outputImg:CIImage = filter.outputImage!
let context:CIContext = CIContext(options: nil)
var tmp_quality = quality
if quality == nil {
tmp_quality = 1.0
}
let transform: CGAffineTransform = CGAffineTransform(scaleX: tmp_quality!, y: tmp_quality!);
let outputImg_after = outputImg.applying(transform)
let cgimg:CGImage = context.createCGImage(outputImg_after, from: outputImg_after.extent)!
var img:UIImage = UIImage(cgImage: cgimg, scale: 1.0, orientation: UIImageOrientation.up)
let width = img.size.width * rate
let height = img.size.height * rate
UIGraphicsBeginImageContext(CGSize.init(width: width, height: height))
let cgContxt:CGContext = UIGraphicsGetCurrentContext()!
cgContxt.interpolationQuality = .high // cgContxt kCGInterpolationNone
img.draw(in: CGRect.init(x: 0, y: 0, width: width, height: height)) // (0, 0, width, height)
img = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return img
}
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!
I am a new iOS developer. I was wondering how can I generate a barcode in Swift.
I have the code already, there are multiple resources from where to learn how to read a barcode, but I didn't find any that talks about generating one from a string.
Thanks a lot!
P.S. I know there is a similar question about this, but it's for Objective-C. I don't know Obj-C and I find it difficult coming from .NET.
You could use a CoreImage (import CoreImage) filter to do that!
class Barcode {
class func fromString(string : String) -> UIImage? {
let data = string.data(using: .ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
if let outputCIImage = filter.outputImage {
return UIImage(ciImage: outputCIImage)
}
}
return nil
}
}
let img = Barcode.fromString("whateva")
A newer version, with guard and failable initialiser:
extension UIImage {
convenience init?(barcode: String) {
let data = barcode.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage = filter.outputImage else {
return nil
}
self.init(ciImage: ciImage)
}
}
Usage:
let barcode = UIImage(barcode: "some text") // yields UIImage?
According to the docs :
Generates an output image representing the input data according to the
ISO/IEC 15417:2007 standard. The width of each module (vertical line)
of the barcode in the output image is one pixel. The height of the
barcode is 32 pixels. To create a barcode from a string or URL,
convert it to an NSData object using the NSASCIIStringEncoding string
encoding.
Improved code:
Barcode scaling
Set barcode image margin
Convert the UIImage to NSData (for some reason it wasn't possible with the code above).
It won't fail when sharing the barcode image (probably because of the same bug)
Swift 3
func generateBarcode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CICode128BarcodeGenerator") {
filter.setDefaults()
//Margin
filter.setValue(7.00, forKey: "inputQuietSpace")
filter.setValue(data, forKey: "inputMessage")
//Scaling
let transform = CGAffineTransform(scaleX: 3, y: 3)
if let output = filter.outputImage?.applying(transform) {
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
let rawImage:UIImage = UIImage.init(cgImage: cgImage)
//Refinement code to allow conversion to NSData or share UIImage. Code here:
//http://stackoverflow.com/questions/2240395/uiimage-created-from-cgimageref-fails-with-uiimagepngrepresentation
let cgimage: CGImage = (rawImage.cgImage)!
let cropZone = CGRect(x: 0, y: 0, width: Int(rawImage.size.width), height: Int(rawImage.size.height))
let cWidth: size_t = size_t(cropZone.size.width)
let cHeight: size_t = size_t(cropZone.size.height)
let bitsPerComponent: size_t = cgimage.bitsPerComponent
//THE OPERATIONS ORDER COULD BE FLIPPED, ALTHOUGH, IT DOESN'T AFFECT THE RESULT
let bytesPerRow = (cgimage.bytesPerRow) / (cgimage.width * cWidth)
let context2: CGContext = CGContext(data: nil, width: cWidth, height: cHeight, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: cgimage.bitmapInfo.rawValue)!
context2.draw(cgimage, in: cropZone)
let result: CGImage = context2.makeImage()!
let finalImage = UIImage(cgImage: result)
return finalImage
}
}
return nil
}
If your deployment target is at least iOS 8, you can use Core Image. Here is my BarcodeGenerator class (you need to import CoreImage):
class BarcodeGenerator {
enum Descriptor: String {
case code128 = "CICode128BarcodeGenerator"
case pdf417 = "CIPDF417BarcodeGenerator"
case aztec = "CIAztecCodeGenerator"
case qr = "CIQRCodeGenerator"
}
class func generate(from string: String,
descriptor: Descriptor,
size: CGSize) -> CIImage? {
let filterName = descriptor.rawValue
guard let data = string.data(using: .ascii),
let filter = CIFilter(name: filterName) else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let image = filter.outputImage else {
return nil
}
let imageSize = image.extent.size
let transform = CGAffineTransform(scaleX: size.width / imageSize.width,
y: size.height / imageSize.height)
let scaledImage = image.transformed(by: transform)
return scaledImage
}
}
It can be used like this
BarcodeGenerator.generate(from: "barcode-string",
descriptor: .code128,
size: CGSize(width: 800, height: 300))
Use like this,
func createBarcodeFromString(barcode:String)->UIImage?{
let data = self.data(using: .isoLatin1)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else {
return nil
}
filter.setValue(data, forKey: "inputMessage")
filter.setValue(7.0, forKey:"inputQuietSpace")
guard var ciImage = filter.outputImage else {
return nil
}
let imageSize = ciImage.extent.integral
let outputSize = CGSize(width:320, height: 60)
ciImage = ciImage.transformed(by:CGAffineTransform(scaleX: outputSize.width/imageSize.width, y: outputSize.height/imageSize.height))
let image = convertCIImageToUIImage(ciimage: ciImage)
return image
}
func convertCIImageToUIImage(ciimage:CIImage)->UIImage{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(ciimage, from: ciimage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}