Ivan Territo
Ivan Territo

Reputation: 43

How to generate a EAN13 barcode?

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

Upvotes: 4

Views: 8128

Answers (3)

ZAY
ZAY

Reputation: 5015

Here is a Swift rendition of @ale_stro's answer that uses the original Objective-C code: (https://github.com/astrokin/EAN13BarcodeGenerator)

Create Swift File: "BarcodeEAN13.swift"

import Foundation

enum Parity {
    case odd
    case even
}

let kBarCodeLength: Int = 12
let bQuiteZone: [Bool] = [false, false, false, false, false, false, false, false, false]
let bLeadTrailer: [Bool] = [true, false, true]
let bSeporator: [Bool] = [false, true, false, true, false]

let bOddLeft: [[Bool]] = [
    [false, false, false, true, true, false, true],
    [false, false, true, true, false, false, true],
    [false, false, true, false, false, true, true],
    [false, true, true, true, true, false, true],
    [false, true, false, false, false, true, true],
    [false, true, true, false, false, false, true],
    [false, true, false, true, true, true, true],
    [false, true, true, true, false, true, true],
    [false, true, true, false, true, true, true],
    [false, false, false, true, false, true, true]
]

let bEvenLeft: [[Bool]] = [
    [false, true, false, false, true, true, true],
    [false, true, true, false, false, true, true],
    [false, false, true, true, false, true, true],
    [false, true, false, false, false, false, true],
    [false, false, true, true, true, false, true],
    [false, true, true, true, false, false, true],
    [false, false, false, false, true, false, true],
    [false, false, true, false, false, false, true],
    [false, false, false, true, false, false, true],
    [false, false, true, false, true, true, true]
]

let bRight: [[Bool]] = [
    [true, true, true, false, false, true, false],
    [true, true, false, false, true, true, false],
    [true, true, false, true, true, false, false],
    [true, false, false, false, false, true, false],
    [true, false, true, true, true, false, false],
    [true, false, false, true, true, true, false],
    [true, false, true, false, false, false, false],
    [true, false, false, false, true, false, false],
    [true, false, false, true, false, false, false],
    [true, true, true, false, true, false, false]
]

let bParity: [[Bool]] = [
    [false, false, false, false, false], [false, true, false, true, true],
    [false, true, true, false, true], [false, true, true, true, false],
    [true, false, false, true, true], [true, true, false, false, true],
    [true, true, true, false, false], [true, false, true, false, true],
    [true, false, true, true, false], [true, true, false, true, false]
]

func initializeBarCode(barCodeString: String) -> [Int] {
    var barCode: [Int] = Array(repeating: 0, count: kBarCodeLength)
    for (index, char) in barCodeString.prefix(kBarCodeLength).enumerated() {
        barCode[index] = Int(String(char)) ?? 0
    }
    return barCode
}

func calculateBarCodeEAN13(barCodeString: String) -> [Bool] {
    var buffer: [Bool] = []
    let barCode = initializeBarCode(barCodeString: barCodeString)
    buffer.append(contentsOf: bQuiteZone)
    buffer.append(contentsOf: bLeadTrailer)

    let countryCode = barCode[1]
    buffer.append(contentsOf: bOddLeft[countryCode])

    // Manufacture Code
    for i in 2..<7 {
        let num = barCode[i]
        let parity = bParity[barCode[0]][i - 2] ? Parity.even : Parity.odd
        let bin = (parity == .odd) ? bOddLeft[num] : bEvenLeft[num]
        buffer.append(contentsOf: bin)
    }

    buffer.append(contentsOf: bSeporator)

    // Product Code
    for i in 7..<12 {
        let num = barCode[i]
        buffer.append(contentsOf: bRight[num])
    }

    // Checksum
    var sum = 0
    for (index, num) in barCode.enumerated() {
        let factor = (index % 2 == 0) ? 1 : 3
        sum += num * factor
    }
    let checksum = (10 - (sum % 10)) % 10
    buffer.append(contentsOf: bRight[checksum])

    buffer.append(contentsOf: bLeadTrailer)
    buffer.append(contentsOf: bQuiteZone)
    return buffer
}

func isValidBarCode(barCode: String) -> Bool {
    guard barCode.count == 13 else { return false }
    let sum = barCode.prefix(12).enumerated().reduce(0) { result, item in
        let (index, char) = item
        guard let digit = Int(String(char)) else { return result }
        return result + digit * ((index % 2 == 0) ? 1 : 3)
    }
    let checkDigit = 10 - (sum % 10)
    return checkDigit == Int(String(barCode.last!))
}

Create Swift File: "BarCodeView.swift"

import UIKit

class BarCodeView: UIView {
    var binaryCode: [Bool] = []
    var barCode: String = "" {
        didSet {
            if isValidBarCode(barCode: barCode) {
                binaryCode = calculateBarCodeEAN13(barCodeString: barCode)
                setNeedsDisplay()
            } else {
                binaryCode = Array(repeating: false, count: 113)
                setNeedsDisplay()
            }
        }
    }

    override func draw(_ rect: CGRect) {
        guard binaryCode.count == 113 else { return }
        let context = UIGraphicsGetCurrentContext()
        context?.clear(rect)
        context?.setAllowsAntialiasing(false)

        // Draw each bar
        let barWidth = rect.width / CGFloat(binaryCode.count)
        for (index, bit) in binaryCode.enumerated() {
            let xPosition = CGFloat(index) * barWidth
            let color: UIColor = bit ? .black : .white
            color.setFill()
            context?.fill(CGRect(x: xPosition, y: 0, width: barWidth, height: rect.height))
        }
    }
}

Usage:

let barCodeView = BarCodeView()
view.addSubview(barCodeView) // adjust view as needed

// Display EAN13 Code:
barCodeView.barCode = "7611330732917" // sample code

Sample EAN-13 Code

Upvotes: 0

ingconti
ingconti

Reputation: 11646

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
}

Upvotes: -6

ale_stro
ale_stro

Reputation: 816

you can try this EAN13BarcodeGenerator

Usage is pretty simple:

BarCodeView *barCodeView = [[BarCodeView alloc] initWithFrame:kBarCodeFrame];
[self.view addSubview:barCodeView];
[barCodeView setBarCode:GetNewRandomEAN13BarCode()];

Upvotes: 3

Related Questions