My barcode. Code128

Once in the process of production activity, I had a need to generate a barcode according to the code128 standard. It appeared due to the fact that a function in use (a stored procedure in the Oracle database) generated a cool, striped barcode that was not readable in all cases. The developers at one time tested this procedure very poorly, but they were no longer going to recycle it. the project was handed over long ago, but the need for reading did not appear.





The first thought is to search for ready-made libraries. Out of the box, we defined the criteria - we don't contact pl / sql, let it be an external service: perhaps a piece of javascript to generate directly on the page, or an appeal for a picture to the nearest server where php is available. A quick search on the Internet showed that the topic was trampled down very tightly. There are both knee-high handicrafts of the level of a programming laboratory, as well as powerful libraries for all coding options, up to QR codes. JavaScript options had to be dropped because firstly, almost all of them are "obfuscated" (it is even incomprehensible, either to reduce the volume, or it is a shame to show the source code), and secondly, they generate a string for displaying in a certain font, the presence of which cannot always be provided on the client site and requires additional processing for escaping special characters.A careful study of libraries and pieces of php code also made a painful impression - at first glance, everything seems to be correct: the classes are written for all occasions, comments are available, decorations such as choosing colors and frames, examples have been prepared. You will start to delve into - they want either php of the most recent version (it is not always possible to get this on combat servers), or the internal logic is not discernible at all, or the output barcode turns out to be longer than expected. Here is the last haunted and pushed to their own realization.You will start to delve into - they want either php of the most recent version (it is not always possible to get this on combat servers), or the internal logic is not discernible at all, or the output barcode turns out to be longer than expected. Here is the last haunted and pushed to their own realization.You will start to delve into - they want either php of the most recent version (it is not always possible to get this on combat servers), or the internal logic is not discernible at all, or the output barcode turns out to be longer than expected. Here is the latter haunted and pushed to their own realization.





It's time to get a feel for the theory. Rather, we met her much earlier, we just didn't want to get involved in additional programming until recently. We will omit the historical facts, but a very good technical description is available at http://code128.narod.ru/ (in the archive it is the file Descript.doc ) or in Wikipedia. In principle, this is all that we need to understand and implement our own algorithm (here I am a little cunning - from any ready-made library you need to rip out tables of stroke thicknesses so as not to drive them in manually). Well, we will write all this disgrace in php, at the same time we will see a couple of cool moments that everyone forgets or is embarrassed to use.





, code128 (!) 128 , 3 , . «B» - «» , — 2 . php- — «». .





— , . - . — . , .





. «ABC12DE» , B, - B :





- 1 . , 6 . — , , — ? , , .





, — () . . — , () ( 2- «»). , , ! «B» «C» - :)





, - B , . — , , . , :





<?php

class code128 {
    private $code = '';
    private $leafB = NULL, $leafC = NULL;

    public function __construct($text, $mode = 'B')
    {
			if (strlen($text) == 0) return NULL;

			$this->mode = $mode;

			if ($mode == 'B') {
	    		$this->code = substr($text, 0, 1);
	    		$text = substr($text, 1);
			}
			else if ($mode == 'C') {
	    		if (strlen($text) < 2) return NULL;
	    		if (!is_numeric($text[0])) return NULL;
	    		if (!is_numeric($text[1])) return NULL;

	    		$this->code = substr($text, 0, 2);
	    		$text = substr($text, 2);
			}
			else	
	    		return NULL;

			$this->leafB = new code128($text, 'B');
			$this->leafC = new code128($text, 'C');
    }

    public function draw()
    {
				echo "Code [" . $this->code . "]\n";
				if ($this->leafB != NULL) $this->leafB->draw();
				if ($this->leafC != NULL) $this->leafC->draw();
    }
}

    $n = new code128('s92317lsdfa4324', 'B');
    $n->draw();
?>
      
      



— "" . NULL! , php . - . . :





    public function __construct($text, $mode = 'B')
    {
			$this->mode = $mode;

			if ($mode == 'B') {
	    		$this->code = substr($text, 0, 1);
	    		$text = substr($text, 1);
			}
			else if ($mode == 'C') {
	    		$this->code = substr($text, 0, 2);
	    		$text = substr($text, 2);
			}

			if(strlen($text)>0) $this->leafB = new code128($text, 'B');
			if(strlen($text)>1)
	    		if(is_numeric($text[0]) && is_numeric($text[1])) $this->leafC = new code128($text, 'C');
    }

      
      



, , . - : , , .. . code128? , , , :





	if($mode == 'B') list($this->code, $text) = sscanf($text, '%c%s');
	if($mode == 'C') list($this->code, $text) = sscanf($text, '%2d%s');

	if(strlen($text)>0)
	    if(array_key_exists(substr($text, 0, 1), $symCode)) $this->leafB = new code128($text, 'B', $this);
	if(strlen($text)>1)
	    if(array_key_exists(substr($text, 0, 2), $symCode)) $this->leafC = new code128($text, 'C', $this);
      
      



$symCode - , tables.php require . - => .





$symCode = array(
/*	alphabet B	alphabet C */
	' ' => 0,	'00' => 0,
	'!' => 1,	'01' => 1,
	'"' => 2,	'02' => 2,
	'#' => 3,	'03' => 3,
	'$' => 4,	'04' => 4,
	'%' => 5,	'05' => 5,
	'&' => 6,	'06' => 6,

      
      



, . : - . ( ), . — 1, 1 2 . 2? . . . ? — « » . — . — , , . — , . , - :)





require 'tables.php';

class code128 {
    private $code = NULL;
    private $text = '';
    private $mode = 'Auto';
    private $len = 1;
    private $leafB = NULL, $leafC = NULL, $parent = NULL, $minCode = NULL;

    public function __construct($text, $mode = 'Auto', $parent = NULL)
    {
			global $symCode;
			$this->parent = $parent;
			$this->text = $text;
			$this->mode = $mode;

			if($parent != NULL) {
	    		$this->len = $this->parent->len + 1;
	    		if($this->parent->mode != $mode) $this->len++;
	     }

	    if($mode == 'B') list($this->code, $text) = sscanf($text, '%c%s');
	    if($mode == 'C') list($this->code, $text) = sscanf($text, '%2d%s');

	    if(strlen($text)>0)
	       if(array_key_exists(substr($text, 0, 1), $symCode)) $this->leafB = new code128($text, 'B', $this);
	    if(strlen($text)>1)
	       if(array_key_exists(substr($text, 0, 2), $symCode)) $this->leafC = new code128($text, 'C', $this);

	    if($this->leafB == NULL && $this->leafC == NULL) $this->minCode = $this;
	    else {
	       $this->minCode = ($this->leafB != NULL) ? $this->leafB->minCode : $this->leafC->minCode;
	       if($this->leafC != NULL)
		        if($this->minCode->len > $this->leafC->minCode->len) $this->minCode = $this->leafC->minCode;
	    }

	    return $this;
     }

      
      



, - (). . : . , , (push) . , PHP , .





 private function getCode()
 {
		$stack = array();
		$p = $this->minCode;

		while($p != NULL) {
	    	array_push($stack, $p->code);

	    	if($p->parent != NULL) {
						if($p->parent->mode == 'Auto') { array_push($stack, 'Start'.$p->mode); break;}
						if($p->mode != $p->parent->mode) array_push($stack, 'Code'.$p->mode);
	    	}

	    	$p = $p->parent;
		}

		return $stack;
  }
      
      



— array_pop. , . — // .





- , . . SVG. — , . , , dpi .





  private function printPattern($code, $posX, $res, $height)
  {
		for($i = 0; $i < strlen($code); $i++) {
	    	$w = $res*intval($code[$i]);

	    	if(!($i%2))
						echo "  <rect x='$posX' y='0' width='$w' height='$height' fill='#0'/>\n";

	    	$posX += $w;
			}

			return $posX;
   }

   public function printSVG($resolution=1, $height=50)
   {
			global $symCode;
			global $barPattern;

			$s = $this->getCode();

			$pos = 1;
			$offset = $resolution*11;
			$width = ((count($s) + 4)*11 + 2)*$resolution;

			echo "<svg xmlns='http://www.w3.org/2000/svg' width='$width' height='$height'>\n";

			$start = $symCode[array_pop($s)];
			$checksum = $start;

			$offset = $this->printPattern($barPattern[$start], $offset, $resolution, $height);

			while(!empty($s)) {
	    		$code = $symCode[array_pop($s)];
	    		$offset = $this->printPattern($barPattern[$code], $offset, $resolution, $height);
	    		$checksum += $code*$pos;
	    		$pos++;
			}

			$offset = $this->printPattern($barPattern[$checksum%103], $offset, $resolution, $height);
			$offset = $this->printPattern($barPattern[$symCode['Stop']], $offset, $resolution, $height);

			echo "</svg>\n";
    }

      
      



$barPattern. tables.php $symCode. . - :





$barPattern = array(
	'212222',	/* 0 */
	'222122',	/* 1 */
	'222221',	/* 2 */
	'121223',	/* 3 */
	'121322',	/* 4 */
      
      



? :





    header('Content-Type: image/svg+xml');
    echo "<?xml version='1.0' encoding='UTF-8' standalone='no'?>\n\n";

    $n = new code128(html_entity_decode($_SERVER["QUERY_STRING"]));
    $n->printSVG();
      
      



, html- :





<img src="barcode128.php?ad32324adsFAE13413ldsFf">
      
      



And finally. Only alphabets "B" and "C" are implemented. Kept within about 100 lines, not counting the conversion tables. The alphabet "A" can be implemented in a similar way, simply by adding a constructor and a table with alphabets, but it is advisable to take into account one tricky code that allows you to briefly switch to one character of a different alphabet. I have no desire, time, or other motivations to finish writing myself. The (semi) finished project will probably add to the graveyard of barcoders on the github - if anyone has a desire to continue the project - do not hesitate to write.








All Articles