Generating Valid Code 128 Barcodes with Javascript
Published: 2022-09-27 14:51:21

To generate a valid Code 128 barcode you need to follow some rules. It must contain a start chararacter, that indicates which character set you want to represent; the data characters, the characters that will be encoded; the checksum, a single character for error checking; and finally, a stop character, to indicate the end of the barcode.

In [the ID Automation Code 128 Barcode Font User Manual
](https://www.idautomation.com/barcode-fonts/code-128/user-manual/#Barcode_Font_Character_Set) you can find detailed instructions on what those characters (Start and Stop) are and how to generate a checksum for the data you want to encode. 

For most applications _Set B_ or _C_ is what you want. _Set B_ contains digits, uppercase and lowercase letters, and some special characters. _Set C_ is used to represent numbers from 00 to 99, which is useful when you want to represent huge strings of numbers. _Set A_ contains digits, uppercase letters, and a bunch of control characters, which might be useful in some specific applications.
 
You can also switch between the three code sets in the same barcode, as there are control characters for that purpose in each set. However, this will not be covered in this post. 

To generate the valid code we must pass the text to be encoded to the `encodeToCode128` function. 

```javascript
const checkbox = document.getElementById('withtext')

function toSetC(text) {
  return text.match(/\d{2}/g).map((ascii, index) => {
    var codeC = Number(ascii);
    var charCode = codeC > 94 ? codeC + 100 : codeC + 32;
  	return String.fromCharCode(charCode)
  }).join('');
}

function checkSum128(data, startCode) {
  var sum = startCode;
  for (var i = 0; i < data.length; i++) {
    var code = data.charCodeAt(i);
  	var value = code > 199 ? code - 100 : code - 32;
    sum += (i + 1) * (value);
  }
  
  var checksum = (sum % 103) + 32;
  if (checksum > 126) checksum = checksum + 68 ;
  return String.fromCharCode(checksum);
}

function encodeToCode128(text, codeABC = "B") {
  var startCode = String.fromCharCode(codeABC.toUpperCase().charCodeAt() + 138);
  var stop = String.fromCharCode(206);
  
  text = codeABC == 'C' && toSetC(text) || text;

  var check = checkSum128(text, startCode.charCodeAt(0) - 100);

  text = text.replace(" ", String.fromCharCode(194));

  return startCode + text + check + stop;
}

function renderBarcodes(withText = true) {
  var barcodeElements = document.querySelectorAll(".barcode");
  var codes = [];
  barcodeElements.forEach((e) => {
    var code = e.attributes["data-barcode"]?.value;
    if (!code) return;
    var set = e.attributes["data-set"]?.value;
    e.innerHTML = encodeToCode128(code, set);
    e.classList.toggle('with-text', withText)
  });
}

renderBarcodes();

checkbox.addEventListener('change', (event) => {
  renderBarcodes(event.currentTarget.checked)
});
```

To generate the valid barcode we just add the `barcode` class to an empty `div` and pass the `data-barcode` attribute with the data we want. This is a completely arbitrary parameter name, but it is the parameter the `renderBarcodes` function will look for.

```html
   <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Libre+Barcode+128">

   <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Libre+Barcode+128+Text">

   <input type="checkbox" id="withtext" name="Show Barcode With Text" checked>
   <label for="withtext">Show Barcode With Text</label>
   <br /> <br />
   
   <div class="barcode" data-barcode="https://dev.to/saulodias"></div>
   <br />
   This code contains only digits, and can have a shorter barcode when using Set C
   <div class="barcode" data-barcode="0123456789"></div>
   <br />
   Same data as the barcode above but with a shorter barcode.
   <div class="barcode" data-barcode="0123456789" data-set="C"></div>
```

Here are is the CSS to apply correctly apply the Libre Barcode fonts used.
```css
.barcode {
  font-family: "Libre Barcode 128", "Courier New", Courier, monospace;
  font-weight: normal;
  font-size: 52px;
  white-space: nowrap;
}

.with-text {
  font-family: "Libre Barcode 128 Text";
}
```

See the [JS Fiddle Example here](https://jsfiddle.net/dias26/row0auxj/).

## Length Optimization
Here is an [example switching code set for optimization](https://jsfiddle.net/dias26/ktn2hz1d/)

The challenge is to find the best combination to optimize the number of characters used, making the barcode shorter. This is explained in [more details on Wikipedia.] 
To decide when switch to code C I have used the [criteria in this Wikipedia Page](https://en.wikipedia.org/wiki/Code_128#Barcode_length_optimization)

## Additional notes
If you prefer, the fonts used in the example can be downloaded here:
- [Libre Barcode 128](https://fonts.google.com/specimen/Libre+Barcode+128)
- [Libre Barcode 128 Text](https://fonts.google.com/specimen/Libre+Barcode+128+text)

On Stack Overflow _Taw_ [implemented this in C#](https://stackoverflow.com/questions/39263194/c-sharp-code-128-does-not-print-out). I used his implementation as reference.

P.S. When generating server-side PDFs, which is something I needed to do you might need to install the fonts to the server, if you have any trouble with font-face and/or the CDN fonts. In any case I do not like to use CDN fonts for several reasons out of the scope of this post.