40

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.

0

5 Answers 5

89

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Amazing !! But then, I wonder why people create more or less complex libraries to handle barcode generation. Where are differences between this and libs ?
@PAD Well, these Core Image filters are quite new (iOS >= 8.0). Before iOS 8, generating barcodes would have been done through these libraries I guess.
It should be noted there are three different types of Code128. This implementation uses subtype C. If you are looking to generate Code 128 type A or B, you may need to look into the ZXing library.
Amazing !! Thanks, If I want to create other barcodes like UPCA, UPCE with HRI values is it possible with this?
what is the CIFilter name for Barcode Code28, Code39 and CODABAR?
|
21

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 } 

4 Comments

@Rushi, how are you trying to read the barcode? With a scanner or through the app?
worked perfact. but my image size is too small at that time so not readable.
Working solution, but code is unsafe with a lot of force unwrapping. Why at first you create a cgImage, then create a rawImage: UIImage from it and then getting back the cgimage from the UIImage? There is some difference?
Is there a way to set background to transparent?
12

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)) 

7 Comments

what is the CIFilter name for Barcode Code28, Code39 and CODABAR?
only those 4 descriptors are supported as you can see here developer.apple.com/documentation/coreimage/cibarcodedescriptor
Unless I'm missing something they seem to have replaced code128 with dataMatrix as of Jan 19
if you go to the link i posted above, I still see code128 and I don't see DataMatrix.
|
1

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 } 

Comments

0

Similar to the answer from Matteo Pacini, here's the version using the newer type-safe CIFilter instances (iOS 13.0+).

import UIKit import CoreImage.CIFilterBuiltins // Type-safe CIFilter instances, iOS 13.0+ extension UIImage { static func barcode( string: String, height: Float, quietSpace: Float ) -> UIImage? { guard let message = string.data(using: String.Encoding.ascii) else { return nil } let filter = CIFilter.code128BarcodeGenerator() filter.message = message filter.barcodeHeight = height filter.quietSpace = quietSpace guard let outputImage = filter.outputImage else { return nil } return UIImage(ciImage: outputImage) } } 

Usage:

imageView.image = .barcode( string: "0123456789", height: 64, quietSpace: 10 ) 

Related documentations:

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.