* http://greyworld.net/ * * *WARNING* This code is not for production (e.g. is incomplete, and NOT tested) */ /** Class */ class Code39 { /** Thick line's width multiplicator over thin line's width. */ private $bcThinThickRatio = 3; /** Coding map. * 0 = thin line, 1 = thick line */ private $bcMap = array( '0' => '000110100', '1' => '100100001', '2' => '001100001', '3' => '101100000', '4' => '000110001', '5' => '100110000', '6' => '001110000', '7' => '000100101', '8' => '100100100', '9' => '001100100', 'A' => '100001001', 'B' => '001001001', 'C' => '101001000', 'D' => '000011001', 'E' => '100011000', 'F' => '001011000', 'G' => '000001101', 'H' => '100001100', 'I' => '001001100', 'J' => '000011100', 'K' => '100000011', 'L' => '001000011', 'M' => '101000010', 'N' => '000010011', 'O' => '100010010', 'P' => '001010010', 'Q' => '000000111', 'R' => '100000110', 'S' => '001000110', 'T' => '000010110', 'U' => '110000001', 'V' => '011000001', 'W' => '111000000', 'X' => '010010001', 'Y' => '110010000', 'Z' => '011010000', '-' => '010000101', '*' => '010010100', '+' => '010001010', '$' => '010101000', '%' => '000101010', '/' => '010100010', '.' => '110000100', ' ' => '011000100' ); /** Draw the barcode. * @param $text (string) text to render * @param $height (int) height * @param $hunits (string) $height's units (cm, mm, in, px, whatever SVG supports) * @param $bcHeight (int) internal units height * @param $fntHeight (int) font's height in internal units (0 to disable), included in bcHeight * * @retval (array) 0: width, 1: array of text (svg) lines */ function render($text, $height, $hunits, $bcHeight, $fntHeight = 0) { // Append/prepend '*' as per specification $final_text = '*' . $text . '*'; $barcode = array(); $barcode_len = 0; $cnt = 0; foreach (str_split($final_text) as $character) { list($charWidth, $charCode) = $this->charToCode($character); $barcode_len += $charWidth; $barcode[] = array('char' => $character, 'code' => $charCode, 'width' => $charWidth); } $img = array(); $img[] = ''; if ($fntHeight > 2) { $textHeight = $fntHeight - 2; $textY = -2; } else { $textHeight = $fntHeight; $textY = 0; } $heightWithFnt = $bcHeight; $bcHeight -= $fntHeight; $width = $barcode_len * $height / $heightWithFnt; $textY += $heightWithFnt; $img[] = sprintf('', $width, $hunits, $height, $hunits, $barcode_len, $heightWithFnt); $img[] = sprintf('%s', htmlspecialchars($final_text)); $img[] = ''; $img[] = sprintf('', $barcode_len, $heightWithFnt); $xpos = 0; foreach ($barcode as $char) { $img[] = ''; $img[] = ''.htmlspecialchars($char['char']).''; if ($fntHeight > 0) { $img[] = sprintf('%s', $xpos + (int)($char['width']/2), $textY, $textHeight, $char['char']); } foreach ($char['code'] as $cdef ) { if ($cdef['color'] == 'black') { $img[] = sprintf('', $xpos, 0, $cdef['width'], $bcHeight); } $xpos += $cdef['width']; } $img[] = ''; } $img[] = ''; $img[] = ''; return array($width, $img); } // render() /** Convert a character to 3of9 code */ private function charToCode($char) { $code = $this->bcMap[$char] . '0'; $color = 1; // 1: Black, 0: White, start with black $totalWidth = 0; $result = array(); foreach (str_split($code) as $line) { $line_width = $line ? $this->bcThinThickRatio : 1; $result[] = array('color' => $color ? 'black' : 'white', 'width' => $line_width); $totalWidth += $line_width; // Invert color $color = $color ? 0 : 1; } // $totalWidth should be constant: 6*thin_width + 3*thick_width + thin_width // $totalWidth = 7 + 3 * $this->bcThinThickRatio return array($totalWidth, $result); } // charToCode() } // Code39