PDFPipe

Linear (1D) / Code 128

Code 128 barcode in a PDF

The general-purpose linear barcode: full ASCII, any length, and the densest of the common linear symbologies for numeric data.

Where the symbol comes from

This API renders HTML to PDF. It does not generate barcodes, so the Code 128 symbol itself is produced by an encoder in your own stack and placed in the markup, either as inline SVG or as a data URI. That split matters more than it sounds: the encoders are mature and correct, and almost every barcode that will not scan failed for a layout reason rather than an encoding one. Everything below is about the layout half.

What it can encode

All 128 ASCII characters, through three switchable subsets. Subset A covers uppercase and control characters, subset B covers upper and lower case, and subset C encodes digits two at a time. That last one is why Code 128 is compact for numbers: a fourteen digit value takes seven symbol characters rather than fourteen. Length is variable and is limited by how wide a symbol you can physically print rather than by the specification.

The check digit, and who computes it

A modulo 103 check character, computed from the weighted sum of the symbol characters and appended by the encoder. It is not part of your data and you do not supply it. If your encoder asks you for a check digit for Code 128, it is asking the wrong question.

Size and quiet zone

The two measurements that decide whether a scanner accepts the symbol, and the two most often lost when a design is adjusted to fit.

  • X-dimension: 0.25mm is the usual practical minimum for a symbol printed on paper and read by a handheld scanner. Below that, printing tolerance rather than the scanner becomes the limit: a 0.19mm bar on a thermal head at 203 dots per inch is one and a half dots, and the printer has to round.
  • Quiet zone: 10 times the X-dimension at each end, with a stated minimum of 6.4mm in most application specifications. This is the field people leave out, because on screen the symbol looks complete without it.

Where it is used

  • carrier and internal logistics labels, where the content is a tracking number
  • warehouse location, bin and licence plate labels
  • healthcare and laboratory specimen labelling
  • anywhere a value has to be both numeric-dense and variable length

Placing it in the markup

The quiet zone is padding on the container rather than part of the encoder's output, so it survives a change of encoder. Dimensions are in millimetres, because a bar width is a physical measurement and a percentage makes it depend on whatever the container happens to be.

html
<!-- The symbol is produced by your encoder, as SVG or as a data URI,
     and placed here. This markup is about the placement, not the encoding. -->
<figure class="barcode">
  <img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0i..." alt="Tracking number H00448812203">
  <figcaption>H00448812203</figcaption>
</figure>

<style>
.barcode {
  margin: 0;
  /* The quiet zone, as padding rather than as part of the image. Doing it
     here means it survives any later change to the encoder's output. */
  padding: 0 7mm;
  text-align: center;
}
.barcode img {
  /* Width in a real print unit so the X-dimension is deterministic.
     A percentage width makes the bar width depend on the container. */
  width: 76mm;
  height: 18mm;
  display: block;
}
.barcode figcaption {
  /* The human-readable fallback. When a scan fails, somebody types this. */
  font: 10pt/1.2 "IBM Plex Mono", monospace;
  letter-spacing: 0.14em;
  margin-top: 1.5mm;
}
</style>

What goes wrong on paper

Setting the image width as a percentage. The X-dimension is then whatever the container happens to be, so the same label renders at a scannable width on A4 and at an unscannable one on a 4 by 6 label. Bar widths are a physical measurement and they belong in millimetres.

First thing to check when it will not scan

The quiet zone, nine times out of ten. A scanner uses the blank space before the start character to work out where the symbol begins, and a label designed to fill its width edge to edge has none. Add 7mm of white either side before changing anything else.

Vector, not a bitmap

Encode to SVG wherever the encoder offers it. A rasterised barcode is resampled when the PDF is printed, and at 203 or 300 dots per inch the bar edges land between printer dots, so the ratio of bar to space drifts by a fraction of a millimetre. That fraction is the whole tolerance. An SVG stays vector inside the PDF and is rendered at the printer's own resolution, which removes the entire failure mode. Where a bitmap is unavoidable, generate it at the final physical size and set image-rendering so nothing smooths the edges.

Frequently asked

Does this API generate Code 128 symbols?

No. It renders HTML to PDF. The symbol is produced by a barcode library in your own application and embedded in the markup as SVG or as a data URI, which is the same way you would put any other generated graphic into a document. What this API is responsible for is that the symbol reaches the page at the size and position you specified.

Why does it scan on screen and fail on paper?

Three reasons, in order of frequency. The quiet zone is present on screen because the browser window is white and absent on paper because the label is not. The symbol was sized as a percentage, so it came out at a different physical width than the one that was tested. Or it is a bitmap, and printing resampled it so the bar-to-space ratio moved outside tolerance.

Can I scale the symbol to fit the space I have?

Uniformly, within the range the symbology allows, and never on one axis. 0.25mm is the usual practical minimum for a symbol printed on paper and read by a handheld scanner. Below that, printing tolerance rather than the scanner becomes the limit: a 0.19mm bar on a thermal head at 203 dots per inch is one and a half dots, and the printer has to round. is the constraint on the way down. Scaling one axis changes the bar-to-space ratio on a linear symbology and makes a 2D symbol non-square, and neither survives a scanner.

Other symbologies

Codes of the same kind, and one from each of the other kinds.

Paste the markup into the playground with your own encoder's output and see what comes out at the real page size.