Industrial Case: Replacing a Barcode Solution at Inkeria

Martin F. Johansen, 2018-07-02

Inkeria is a print company. They sell stickers used to mark clothes. This is often used to mark clothing where clothes gets mixed, such as in kinder gardens and retirement homes. This is a growing market and Inkeria is selling more and more stickers.

To track the physical product through their factory and out of their building, they use barcodes printed on the product.

What is bar code generation?

Generating a barcode is a 100% computational task: A certain string of codes, usually characters, are to be coded as a series of black and white bars, thereby barcode. This can be done equally well in all programming languages and can readily produce exactly the same result.

Inkeria's Existing Solution

Inkeria's existing solution was the WooCommerce Order Barcodes. Generating a barcode with this solution, a commercial $79.00 solution, requires the following steps: Once an order has been placed in the e-store, someone must use a browser and open the order page. A barcode is then generated in JavaScript and sent to the server which stores the barcode in the database. The barcode can then be fetched using the Wordpress and WooCommerce APIs.

As you can see, this involes a lot of non-computational steps: Opening a browser manually, doing several network requests and storing the barcode on the disk. This is overly complex compared to what the task really is. This added complexity causes inflexibility. The task of generating the barcode cannot be moved, as it is tied to the browser, Wordpress and Woocommerce, the server and the database. It even involes a manual step: Someone must open the order in a browser.

Barcode Generation as a Computation

As barcode generation is a computational task, and as Inkeria wanted the freedom to chose where and when the barcode gets generated, progsbase was ideal for this problem.

At the top-level, barcode generation is a function that takes a string as input and an image as output. We will generate Code 128B barcodes. In Java, this function can be written:

public static Image generateCode128BBarcode(char [] string){
    ...
}

An image

An image is a list of colors, a width and a height. A color can be defined many ways, but we will use the RGBA encoding, the Red, Green, Blue and Alpha encoding using numbers between 0 and 1, 0 being none and 1 being full. A red value of 1 means completely red, and an alpha value of 1 means completely opaque. What we are talking about here is called a bitmap image. Therefore, we can change the function to something a little more descriptive:

public static RGBABitmapImage generateCode128BBarcode(char [] string){
    ...
}

The RGBABitmapImage is a data structure, and we will have it contain all the rows, or x'es, which length is the width of the image:

public class RGBABitmapImage {
    public RGBABitmap [] x;
}

which in turn contains the columns, or the y's, which length is the height of the image:

public class RGBABitmap {
    public RGBA [] y;
}

And finally, each color contains:

public class RGBA {
    public double r, g, b, a;
}

Thus, given an image image, the color at (a, b) can be accessed by image.x[a].y[b].

This image structure is available in the progsbase library RGBABitmapImage found in the Progsbase Database.

Drawing

Now that we have an image structure, we need some small utilities for drawing on it.

The first useful method is drawing a sinle pixel, which can be written in Java as follows:

public static void dp(RGBABitmapImage image, double x, double y, RGBA color) {
    image.x[(int)x].y[(int)y].a = color.a;
    image.x[(int)x].y[(int)y].r = color.r;
    image.x[(int)x].y[(int)y].g = color.g;
    image.x[(int)x].y[(int)y].b = color.b;
}

This function simply copies the color values into the pixel located at (x, y).

Now, we can use this function to create a function for creating a new image of a certain height and width, filled with a certain color:

public static RGBABitmapImage createImage(double w, double h, RGBA color) {
    RGBABitmapImage image;
    double i, j;

    image = new RGBABitmapImage();
    image.x = new RGBABitmap[(int)w];
    for(i = 0d; i < w; i = i + 1d){
        image.x[(int)i] = new RGBABitmap();
        image.x[(int)i].y = new RGBA[(int)h];
        for(j = 0d; j < h; j = j + 1d){
            image.x[(int)i].y[(int)j] = new RGBA();
            dp(image, i, j, color);
        }
    }

    return image;
}

This function creates all the rows and columns and draws the color into each pixel. The new image is returned.

We also need a function for drawing a vertical line on the image. The following method draws a line from coordinate (x, y) of a certain height and color.

public static void drawVerticalLine1px(RGBABitmapImage image, double x, double y, double height, RGBA color){
  double i;

  for(i = 0d; i < height; i = i + 1d){
    dp(image, x, y + i, color);
  }
}

This function simply draws each pixel in the vertical line in a loop.

This 2D graphics utility is available in the progsbase library Graphics2D found in the Progsbase Database.

Making the barcode

We now have tools we need to make the barcode image.

The specification of the Code 128 B barcode is readily available, for example, on Wikipedia.

Calculating the width

The width of the barcode is according to the specification as follows:

public static double calculateWidth(char[] chars) {
    double width;

    // Quiet Zones + start + 11 * chars + checksum + stop symbol.
    width = 10d + 11d + chars.length * 11d + 11d + 13d + 10d;

    return width;
}

The width of the barcode is dependent only on the number of characters. Horizontally, the barcode first contains a quiet zone of 10 bars, then a starting symbol of 11 bars, then 11 bars per character and an 11 bar checksum symbol followed by a 13 bar end symbol and a 10 bar quiet zone.

Getting bar widths:

We need two conversion functions, one that converts the ASCII character code to the Code 128 code and one that gives the number of bars of oscillating color.

public static double [] getAsciiToNrTable(){
    double [] c;

    c = new double [(int)(210d + 1d)];

    c[32] = 0d;
    c[33] = 1d;
    c[34] = 2d;
    ...
    c[208] = 103d;
    c[209] = 104d;
    c[210] = 105d;

    return c;
}

This shortened function return the conversion array that takes an ASCII code and gives the Code 128 code.

Then the function that gives the bar lengths:

public static char [] getWidths(double code){
    char [] spaces;

    spaces = "".toCharArray();

    if(code == 0d){ spaces = "212222".toCharArray(); }
    if(code == 1d){ spaces = "222122".toCharArray(); }
    if(code == 2d){ spaces = "222221".toCharArray(); }
    ...
    if(code == 106d){ spaces = "233111".toCharArray(); }
    if(code == 107d){ spaces = "211133".toCharArray(); }
    if(code == 108d){ spaces = "2331112".toCharArray(); }

    return spaces;
}

This shortened function takes the Code 128 code and returns a string of bar widths. The bar widths for code 0, for example, begins with 2 black bars followed by 1 white and then 2 black, 2 white, 2 black and finally 2 white.

We can use these to create a function for writing a single barcode symbol:

public static void drawBarcodeSymbol(RGBABitmapImage image, double barcodeNr, double h, DoubleReference counterReference){
    double j, k, width;
    char widthCharacter;
    char[] widths;
    boolean next;
    RGBA nextColor;

    widths = getWidths(barcodeNr);

    nextColor = getBlack();
    next = true;

    for(j = 0d; j < widths.length; j = j + 1d){
        widthCharacter = widths[(int)j];
        width = getDecimalFromSingleDecimalDigit(widthCharacter, 10d);

        for(k = 0d; k < width; k = k + 1d){
            drawVerticalLine1px(image, counterReference.doubleValue, 0d, h - 1d, nextColor);
            counterReference.doubleValue = counterReference.doubleValue + 1d;
        }

        if(next){
            nextColor = getWhite();
        }else{
            nextColor = getBlack();
        }
        next = !next;
    }
}

This function takes an image, a Code 128 code, a height and a counter. It draws on the barcode of a certain code on the counter column of a certain height. This is simply done by drawing vertical bars with oscillating color.

The second to last symbol of a Code 128 B barcode is a checksum. Checksums makes the reliability of barcode reading very high, because if the checksum is invalid, there must have been an error in reading the barcode off the light sensors.

The checksum is calculuated as follows:

public static double calculateChecksum(char[] chars) {
    double checksum, i, position, value;
    char c;

    checksum = 104d * 1d;

    for(i = 0d; i < chars.length; i = i + 1d){
        position = i + 1d;
        c = chars[(int)i];
        value = asciiToNr(c);
        checksum = checksum + position*value;
    }

    return checksum % 103d;
}

The checksum multiplies each sumbol with its position and sums them. Finally, the sum modulus 103 gives the checksum.

We can now combine these into the function for barcode generation:

public static RGBABitmapImage generateBarcode(char [] chars, double height){
    double w, h, i, barcodeNr, checksum;
    char c;
    DoubleReference counterReference;
    RGBABitmapImage image;

    h = height;
    w = calculateWidth(chars);

    image = createImage(w, h, getWhite());

    counterReference = new DoubleReference();
    counterReference.doubleValue = 10d;

    // 128B start
    drawBarcodeSymbol(image, 104d, h, counterReference);

    for(i = 0d; i < chars.length; i = i + 1d){
        c = chars[(int)i];
        barcodeNr = asciiToNr(c);
        drawBarcodeSymbol(image, barcodeNr, h, counterReference);
    }

    // Checksum
    checksum = calculateChecksum(chars);
    drawBarcodeSymbol(image, checksum, h, counterReference);

    // Stop symbol
    drawBarcodeSymbol(image, 108d, h, counterReference);

    counterReference.doubleValue = counterReference.doubleValue + 10d;

    return image;
}

This function generates the barcode and places it in the image structure. First, the width is calculated, and a new white image is created. Then the quiet zone is skipped. The start symbol is drawn followed by each character symbol. Finally, the checksum and ending symbols are drawn.

It is easy to program rendering of this image. Simply draw the pixels one at a time and store it in an image file or to a canvas on the screen.

Conclusion

Inkeria now has very flexible barcode solution. It can be run in the Wordpress and WooCommerce back-end, in the JavaScript front-end, in Excel spread sheets or in the Java servlets producing the products. They are no longer bound to the inflexible solution discussed in the introduction.

This barcode utility is available in the progsbase library Code128. Here, you can also generate barcodes directly in the browser window. Make sure to try it out using the JavaScript browser launcher.

Thus, barcode generation is available in all the supported languages of progsbase, which, as of writing, are Java, C, C++, JavaScript, C#, R, PHP, Python, Visual Basic .NET and Visual Basic for Applications.

Contact Information

We would be more than happy to help you. Our opening hours are 9–15 (CET).

[email protected]

📞 (+47) 93 68 22 77

Nils Bays vei 50, 0876 Oslo, Norway

Copyright © 2018-24 progsbase.com by Inductive AS.