How can I generate a barcode from a string in Swift?
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))