I'm trying to create a simple EAN13 image to show a barcode from a String.
I tried with this code but it can only generate a code128. What can I use to generate a EAN13?
class Barcode {
class func fromString(string : String) -> UIImage? {
let data = string.dataUsingEncoding(NSASCIIStringEncoding)
let filter = CIFilter(name: "CICode128BarcodeGenerator")
filter.setValue(data, forKey: "inputMessage")
return UIImage(CIImage: filter.outputImage)
}
}
let img = Barcode.fromString("1234567890123")
you can try this EAN13BarcodeGenerator
Usage is pretty simple:
BarCodeView *barCodeView = [[BarCodeView alloc] initWithFrame:kBarCodeFrame];
[self.view addSubview:barCodeView];
[barCodeView setBarCode:GetNewRandomEAN13BarCode()];
my two cents for osx..
func barCodeFromString(string : String, destSize: NSSize) -> NSImage? {
let data = string.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else{
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage : CIImage = filter.outputImage else{
return nil
}
let c_size = ciImage.extent.size
let w_ratio = destSize.width/c_size.width
let h_ratio = destSize.height/c_size.height
let ratio = w_ratio>h_ratio ? h_ratio : w_ratio
let transform = CGAffineTransform(scaleX: ratio, y: ratio)
let scaled = ciImage.transformed(by: transform)
let rep = NSCIImageRep(ciImage: scaled)
let nsImage = NSImage(size: rep.size)
nsImage.addRepresentation(rep)
return nsImage
}
Related
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
}
I'm generating an image with barcode using its string like below.
class BarCode {
class func fromString(string : String) -> UIImage? {
let data = string.dataUsingEncoding(NSASCIIStringEncoding)
let filter = CIFilter(name: "CICode128BarcodeGenerator")
filter!.setValue(data, forKey: "inputMessage")
return UIImage(CIImage: filter!.outputImage!)
}
}
so this generates a accurate image. but the quality is low. how can I increase the quality of the image.(I cant increase the size of the image, if I do so it looks liked blured)
When the CIImage is converted to a UIImage it does so with a fixed size that is determined by the CIImage, if you subsequently try to scale this image up, say by assigning it to a UIImageView, then you will get the typical pixellation associated with scaling up a bitmap.
Transform the image before assigning it to the UIImage
if let barImage = filter.outputImage {
let transform = CGAffineTransformMakeScale(5.0, 5.0)
let scaled = barImage.imageByApplyingTransform(transform)
return(UIImage(CIImage: scaled))
}
Try transform to make it bigger
let transform = CGAffineTransform(scaleX: 3, y: 3)
if let output = filter.outputImage?.applying(transform) {
return UIImage(ciImage: output)
}
my two cents for OSX :)
func barCodeFromString(string : String) -> NSImage? {
let data = string.data(using: .ascii)
guard let filter = CIFilter(name: "CICode128BarcodeGenerator") else{
return nil
}
filter.setValue(data, forKey: "inputMessage")
guard let ciImage : CIImage = filter.outputImage else{
return nil
}
let transform = CGAffineTransform(scaleX: 5.0, y: 5.0)
let scaled = ciImage.transformed(by: transform)
let rep = NSCIImageRep(ciImage: scaled)
let nsImage = NSImage(size: rep.size)
nsImage.addRepresentation(rep)
return nsImage
}
I am making image form QR Code by using following code:
func createQRFromString(str: String) -> CIImage? {
let stringData = str.dataUsingEncoding(NSUTF8StringEncoding)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(stringData, forKey: "inputMessage")
filter?.setValue("H", forKey: "inputCorrectionLevel")
return filter?.outputImage
}
And Then I am adding to UIImageView Like this:
if let img = createQRFromString(strQRData) {
let somImage = UIImage(CIImage: img, scale: 1.0, orientation: UIImageOrientation.Down)
imgviewQRcode.image = somImage
}
Now I need to save this to a JPEG or PNG file. But when I am doing so my app crashes:
#IBAction func btnSave(sender: AnyObject) {
// // Define the specific path, image name
let documentsDirectoryURL = try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
// create a name for your image
let fileURL = documentsDirectoryURL.URLByAppendingPathComponent("image.jpg")
if let image = imgviewQRcode.image // imgviewQRcode is UIImageView
{
if let path = fileURL?.path
{
if !NSFileManager.defaultManager().fileExistsAtPath(fileURL!.path!)
{
if UIImageJPEGRepresentation(image, 1.0)!.writeToFile(path, atomically: true)
{
print("file saved")
}
}//Checking existing file
}//Checking path
}//CHecking image
}
Crash Point
UIImageJPEGRepresentation(image, 1.0)!.writeToFile(path, atomically: true)
Reason
fatal error: unexpectedly found nil while unwrapping an Optional value
Debug Tests:
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
}
Use this function to convert CIImage to UIImage . It works .
func convert(image:CIImage) -> UIImage
{
let image:UIImage = UIImage.init(ciImage: image)
return image
}
Perhaps, this was unavailable before, but it is now possible to create UIImages directly from CIImage.
My final code
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
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) {
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
}
return nil
}
I'm creating QR Codes in my app and I'm wanting to know if it's possible to add a second key-value pair. Right now I have a 12 digit number for the "inputMessage" key and I'm wanting to have some other data for another key. For example, using another string for a new key called "gym".
Here is my function for creating the QR Code:
func generateCode() {
let gymData = gymName.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
let codeNumberData = generateRandomNumber(12).dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(codeNumberData, forKey: "inputMessage")
// filter?.setValue(gymData, forKey: "gym")
filter?.setValue("Q", forKey: "inputCorrectionLevel")
let qrCodeImage = filter?.outputImage
let context = CIContext(options: nil)
let cgImage = context.createCGImage(qrCodeImage!, fromRect: (qrCodeImage?.extent)!)
let image = UIImage(CGImage: cgImage, scale: 1.0, orientation: .Up)
let resized = resizeImage(image, withQuality: CGInterpolationQuality.None, rate: 5.0)
codeImageView.image = resized
}
The CIFilter is only expecting to generate the QR code from inputMessage, so you need to create a single aggregate inputMessage and pass that to the filter. One fairly straight forward way of doing this is to create a Dictionary from your inputs, serialize it into a NSData blob using the NSKeyedArchiver, and then set the result as your inputMessage.
func generateCode() {
var aggregateData = [String: NSData]()
if let gymData = gymName.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false) {
aggregateData.updateValue(gymData, forKey: "gymData")
}
if let codeNumberData = generateRandomNumber(12).dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false) {
aggregateData.updateValue(codeNumberData, forKey: "codeNumberData")
}
let archived = NSKeyedArchiver.archivedDataWithRootObject(aggregateData)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(archived, forKey: "inputMessage")
filter?.setValue("Q", forKey: "inputCorrectionLevel")
let qrCodeImage = filter?.outputImage
let context = CIContext(options: nil)
let cgImage = context.createCGImage(qrCodeImage!, fromRect: (qrCodeImage?.extent)!)
let image = UIImage(CGImage: cgImage, scale: 1.0, orientation: .Up)
let resized = resizeImage(image, withQuality: CGInterpolationQuality.None, rate: 5.0)
codeImageView.image = resized
}
Of course this means that on the receiving end, you'll need to expect the payload to be a dictionary, and access the individual components by their keys. Should look something like this.
guard let inputData = scannedQrString.dataUsingEncoding(NSISOLatin1StringEncoding, allowLossyConversion: false),
dictionary = NSKeyedUnarchiver.unarchiveObjectWithData(inputData) as? [String: NSData] else {
return
}
let gymData = dictionary["gymData"]
let codeNumberData = dictionary["codeNumberData"]
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
}