Mi código de barras. Código128

Una vez en el proceso de actividad productiva, tuve la necesidad de generar un código de barras según el estándar code128. Apareció debido al hecho de que la función en uso (un procedimiento almacenado en la base de datos de Oracle) generó un código de barras con rayas que no era legible en todos los casos. En un momento, los desarrolladores probaron este procedimiento muy mal, pero ya no lo iban a reciclar. El proyecto se terminó hace mucho tiempo, pero no apareció la necesidad de leer.





El primer pensamiento es buscar bibliotecas listas para usar. Fuera de la caja, definimos los criterios: no contactamos a pl / sql, que sea un servicio externo: tal vez una pieza de javascript para generar directamente en la página, o una solicitud de una imagen al servidor más cercano donde php está disponible. Una búsqueda rápida en Internet mostró que el tema fue pisoteado muy de cerca. Hay artesanías a la altura de la rodilla del nivel de un laboratorio de programación, así como poderosas bibliotecas para todas las opciones de codificación, hasta códigos QR. Las opciones de JavaScript tuvieron que descartarse porque en primer lugar, casi todos están "ofuscados" (incluso es incomprensible, ya sea para reducir el volumen, o es una pena mostrar el código fuente), y en segundo lugar, generan una cadena para mostrar en una determinada fuente, la presencia de los cuales no siempre se pueden proporcionar en el sitio del cliente y requieren un procesamiento adicional que escapa a los caracteres especiales.Un estudio cuidadoso de bibliotecas y fragmentos de código php también causó una impresión dolorosa: a primera vista, todo parece estar correcto: las clases están escritas para todas las ocasiones, los comentarios están disponibles, las decoraciones como la elección de colores y marcos, se han preparado ejemplos . Comenzará a profundizar en: quieren php de la versión más reciente (en servidores de combate no siempre es posible obtener esto), o la lógica interna no es perceptible en absoluto, o el código de barras de salida resulta ser más largo que esperado. Aquí está el último atormentado y empujado a su propia realización.Comenzará a profundizar en: quieren php de la versión más reciente (no siempre es posible obtener esto en los servidores de combate), o la lógica interna no es discernible en absoluto, o el código de barras de salida resulta ser más largo que esperado. Aquí está el último embrujado y empujado a su propia realización.Comenzará a profundizar en: quieren php de la versión más reciente (en servidores de combate no siempre es posible obtener esto), o la lógica interna no es perceptible en absoluto, o el código de barras de salida resulta ser más largo que esperado. Aquí está el último embrujado y empujado a su propia realización.





Es hora de familiarizarse con la teoría. Más bien, la conocimos mucho antes, simplemente no queríamos involucrarnos en programación adicional hasta hace poco. Omitiremos los hechos históricos, pero hay una muy buena descripción técnica disponible en http://code128.narod.ru/ (el archivo Descript.doc está en el archivo ) o en Wikipedia. En principio, esto es todo lo que necesitamos para comprender e implementar nuestro propio algoritmo (aquí soy un poco astuto: debe extraer las tablas de anchos de trazo de cualquier biblioteca preparada para no ingresarlas manualmente). Bueno, escribiremos toda esta desgracia en php, al mismo tiempo veremos un par de momentos geniales que todos olvidan o les da vergüenza usar.





, 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">
      
      



Y finalmente. Solo se implementan los alfabetos "B" y "C". Mantenido dentro de unas 100 líneas, sin contar las tablas de conversión. El alfabeto "A" se puede implementar de manera similar, simplemente agregando un constructor y una tabla con alfabetos, pero es recomendable tener en cuenta un código complicado que le permite cambiar brevemente a un carácter de un alfabeto diferente. No tengo ganas, tiempo u otras motivaciones para terminar de escribir yo mismo. El proyecto (semi) terminado probablemente se sumará al cementerio de códigos de barras en el github; si alguien tiene el deseo de continuar con el proyecto, no dude en escribir.








All Articles