Skip to content

Instantly share code, notes, and snippets.

@Sheep-y
Last active July 9, 2021 11:38
Show Gist options
  • Save Sheep-y/baaebc7b9a465dec09d0014520b81933 to your computer and use it in GitHub Desktop.
Save Sheep-y/baaebc7b9a465dec09d0014520b81933 to your computer and use it in GitHub Desktop.
Code 39 barcode drawing function for jsPDF

Adds a jsPDF method to draw a Code 39 barcode in line vector, which is very small and retain perfect sharpness at all resolutions. An optional matrix can be supplied for rotation, sheer, mirror, or other effects.

Does not render text; the drawn barcode is perfectly rectangular. Does not validate text input. Requires EcmaScript 7.

Usage

const doc = new jsPDF();
// Draw at [50,50], width 100. height 20.
doc.code39( "0123456789", 50, 30, 100, 20 );
// Thin lines (scale 2, or use 3 for thick lines).
doc.code39( "0123456789", 55, 60, 90, 20, 2 );
// Rotate clockwise 90' + transpose to [145,90].
doc.code39( "0123456789", 0, 0, 90, 20, 2, [0,-1,145,1,0,90] );
// Anti-clockwise 90' + transpose to [55,180].
doc.code39( "0123456789", 0, 0, 90, 20, 2, [0,1,55,-1,0,180] );
// Sheer + transpose to [50,190]
doc.code39( "0123456789", 0, 0, 90, 20, 2.5, [1,0.3,50,0,1,190] );
doc.save( "test.pdf" );

Code

document.addEventListener( 'DOMContentLoaded', function(){

   // https://gist.github.com/Sheep-y/baaebc7b9a465dec09d0014520b81933/
   Object.getPrototypeOf( jsPDF.prototype ).code39 = function drawCode39 ( text, x, y, w, h, scale = 2.5, matrix = null ) {
      if ( x === undefined || y === undefined || w <= 0 || h <= 0 ) return;
      scale = Math.max( 2, Math.min( +scale, 3 ) );
      const Code39Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%";
      const Code39Bars =
      [ "000110100","100100001","001100001","101100000","000110001","100110000","001110000","000100101","100100100", //0-8
        "001100100","100001001","001001001","101001000","000011001","100011000","001011000","000001101","100001100", //9-H
        "001001100","000011100","100000011","001000011","101000010","000010011","100010010","001010010","000000111", //I-Q
        "100000110","001000110","000010110","110000001","011000001","111000000","010010001","110010000","011010000", //R-Z
        "010000101","110000100","011000100","010010100","010101000","010100010","010001010","000101010" ]; // Symbols

      text = `*${text}*`.toUpperCase();
      const charCount = text.length,  charWidth = w / charCount, lineWidth = charWidth / ( 7 + scale * 3 );
      //console.log( `Code 39 "${text}" at [${x},${y}] height ${h} width ${w} (${charWidth} per char, ${lineWidth} per line}). Matrix ${matrix}.` );
      const spacing = [ lineWidth, scale * lineWidth ], d = lineWidth*(scale-1)/2;
      this.setLineCap( 2 ); // square cap
      for ( let i = 0, draw = true ; i < charCount ; i++, draw = true ) {
         let pos = Code39Chars.indexOf( text[i] ), left = x + charWidth * i;
         for ( let w of Code39Bars[pos].split( "" ).map( e => +e ) ) {
            if ( draw ) {
               this.setLineWidth( spacing[ w ] );
               let dw = w?d:0, x1 = left+dw, y1 = y+dw, x2 = left+dw, y2 = y+h-dw;
               if ( matrix ) {
                  [ x1, y1 ] = applyMatrix( x1, y1 );
                  [ x2, y2 ] = applyMatrix( x2, y2 );
               }
               this.line( x1, y1, x2, y2 );
            }
            left += spacing[ w ];
            draw = ! draw;
         }
      }
      function applyMatrix( x, y ) {
         return [ x * matrix[0] + y * matrix[1] + matrix[2], x * matrix[3] + y * matrix[4] + matrix[5] ];
      }
   };

} );

License

This code is released to the public domain. Do whatever you like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment