/** * Construct a PDF417 barcode array * @param string $code The code to be represented by this barcode. * @param int $ecl error correction level (0-8); default -1 = automatic correction level * @param float $aspectratio the width to height of the symbol (excluding quiet zones) * @param array $macro information for macro block */ function __construct($code, $ecl = -1, $aspectratio = 2.0, $macro = array()) { parent::__construct($code); $this->barcode_array = array(); if (is_null($code) or $code == '\\0' or $code == '') { return; } // get the input sequence array $sequence = $this->getInputSequences($code); $codewords = array(); // array of code-words foreach ($sequence as $seq) { $cw = $this->getCompaction($seq[0], $seq[1], true); $codewords = array_merge($codewords, $cw); } if ($codewords[0] == 900) { // Text Alpha is the default mode, so remove the first code array_shift($codewords); } // count number of codewords $numcw = count($codewords); if ($numcw > 925) { // reached maximum data codeword capacity return; } // build macro control block codewords if (!empty($macro)) { $macrocw = array(); // beginning of macro control block $macrocw[] = 928; // segment index $cw = $this->getCompaction(902, sprintf('%05d', $macro['segment_index']), false); $macrocw = array_merge($macrocw, $cw); // file ID $cw = $this->getCompaction(900, $macro['file_id'], false); $macrocw = array_merge($macrocw, $cw); // optional fields $optmodes = array(900, 902, 902, 900, 900, 902, 902); $optsize = array(-1, 2, 4, -1, -1, -1, 2); foreach ($optmodes as $k => $omode) { if (isset($macro['option_' . $k])) { $macrocw[] = 923; $macrocw[] = $k; if ($optsize[$k] == 2) { $macro['option_' . $k] = sprintf('%05d', $macro['option_' . $k]); } elseif ($optsize[$k] == 4) { $macro['option_' . $k] = sprintf('%010d', $macro['option_' . $k]); } $cw = $this->getCompaction($omode, $macro['option_' . $k], false); $macrocw = array_merge($macrocw, $cw); } } if ($macro['segment_index'] == $macro['segment_total'] - 1) { // end of control block $macrocw[] = 922; } // update total codewords $numcw += count($macrocw); } // set error correction level $ecl = $this->getErrorCorrectionLevel($ecl, $numcw); // number of codewords for error correction $errsize = 2 << $ecl; // calculate number of columns (number of codewords per row) and rows $nce = $numcw + $errsize + 1; $cols = round((sqrt(4761 + 68 * $aspectratio * self::ROWHEIGHT * $nce) - 69) / 34); // adjust cols if ($cols < 1) { $cols = 1; } elseif ($cols > 30) { $cols = 30; } $rows = ceil($nce / $cols); $size = $cols * $rows; // adjust rows if ($rows < 3 or $rows > 90) { if ($rows < 3) { $rows = 3; } elseif ($rows > 90) { $rows = 90; } $cols = ceil($size / $rows); $size = $cols * $rows; } if ($size > 928) { // set dimensions to get maximum capacity if (abs($aspectratio - 17 * 29 / 32) < abs($aspectratio - 17 * 16 / 58)) { $cols = 29; $rows = 32; } else { $cols = 16; $rows = 58; } $size = 928; } // calculate padding $pad = $size - $nce; if ($pad > 0) { if ($size - $rows == $nce) { --$rows; $size -= $rows; } else { // add pading $codewords = array_merge($codewords, array_fill(0, $pad, 900)); } } if (!empty($macro)) { // add macro section $codewords = array_merge($codewords, $macrocw); } // Symbol Lenght Descriptor (number of data codewords including Symbol Lenght Descriptor and pad codewords) $sld = $size - $errsize; // add symbol length description array_unshift($codewords, $sld); // calculate error correction $ecw = $this->getErrorCorrection($codewords, $ecl); // add error correction codewords $codewords = array_merge($codewords, $ecw); // add horizontal quiet zones to start and stop patterns $pstart = str_repeat('0', self::QUIETH) . $this->start_pattern; $pstop = $this->stop_pattern . str_repeat('0', self::QUIETH); $this->barcode_array['num_rows'] = $rows * self::ROWHEIGHT + 2 * self::QUIETV; $this->barcode_array['num_cols'] = ($cols + 2) * 17 + 35 + 2 * self::QUIETH; $this->barcode_array['bcode'] = array(); // build rows for vertical quiet zone if (self::QUIETV > 0) { $empty_row = array_fill(0, $this->barcode_array['num_cols'], 0); for ($i = 0; $i < self::QUIETV; ++$i) { // add vertical quiet rows $this->barcode_array['bcode'][] = $empty_row; } } $k = 0; // codeword index $cid = 0; // initial cluster // for each row for ($r = 0; $r < $rows; ++$r) { // row start code $row = $pstart; switch ($cid) { case 0: $L = 30 * intval($r / 3) + intval(($rows - 1) / 3); break; case 1: $L = 30 * intval($r / 3) + $ecl * 3 + ($rows - 1) % 3; break; case 2: $L = 30 * intval($r / 3) + ($cols - 1); break; } // left row indicator $row .= sprintf('%17b', $this->clusters[$cid][$L]); // for each column for ($c = 0; $c < $cols; ++$c) { $row .= sprintf('%17b', $this->clusters[$cid][$codewords[$k]]); ++$k; } switch ($cid) { case 0: $L = 30 * intval($r / 3) + ($cols - 1); break; case 1: $L = 30 * intval($r / 3) + intval(($rows - 1) / 3); break; case 2: $L = 30 * intval($r / 3) + $ecl * 3 + ($rows - 1) % 3; break; } // right row indicator $row .= sprintf('%17b', $this->clusters[$cid][$L]); // row stop code $row .= $pstop; // convert the string to array $arow = preg_split('//', $row, -1, PREG_SPLIT_NO_EMPTY); // duplicate row to get the desired height for ($h = 0; $h < self::ROWHEIGHT; ++$h) { $this->barcode_array['bcode'][] = $arow; } ++$cid; if ($cid > 2) { $cid = 0; } } if (self::QUIETV > 0) { for ($i = 0; $i < self::QUIETV; ++$i) { // add vertical quiet rows $this->barcode_array['bcode'][] = $empty_row; } } }
/** * Construct a Data Matrix barcode array * @param string $code The code to be represented by this barcode. */ function __construct($code) { parent::__construct($code); if (is_null($code) or $code == '\\0' or $code == '') { return; } // get data codewords $cw = $this->getHighLevelEncoding($code); // number of data codewords $nd = count($cw); // check size if ($nd > 1558) { return; } // get minimum required matrix size. foreach ($this->symbattr as $params) { if ($params[11] >= $nd) { break; } } if ($params[11] < $nd) { // too much data return; } elseif ($params[11] > $nd) { // add padding if ($this->last_enc == self::ENC_EDF) { // switch to ASCII encoding $cw[] = 124; ++$nd; } elseif ($this->last_enc != self::ENC_ASCII and $this->last_enc != self::ENC_BASE256) { // switch to ASCII encoding $cw[] = 254; ++$nd; } if ($params[11] > $nd) { // add first pad $cw[] = 129; ++$nd; // add remaining pads for ($i = $nd; $i <= $params[11]; ++$i) { $cw[] = $this->get253StateCodeword(129, $i); } } } // add error correction codewords $cw = $this->getErrorCorrection($cw, $params[13], $params[14], $params[15]); // get placement map $places = $this->getPlacemetMap($params[2], $params[3]); // fill the grid with data $grid = array(); $i = 0; // region data row max index $rdri = $params[4] - 1; // region data column max index $rdci = $params[5] - 1; // for each vertical region for ($vr = 0; $vr < $params[9]; ++$vr) { // for each row on region for ($r = 0; $r < $params[4]; ++$r) { // get row $row = $vr * $params[4] + $r; // for each horizontal region for ($hr = 0; $hr < $params[8]; ++$hr) { // for each column on region for ($c = 0; $c < $params[5]; ++$c) { // get column $col = $hr * $params[5] + $c; // braw bits by case if ($r == 0) { // top finder pattern if ($c % 2) { $grid[$row][$col] = 0; } else { $grid[$row][$col] = 1; } } elseif ($r == $rdri) { // bottom finder pattern $grid[$row][$col] = 1; } elseif ($c == 0) { // left finder pattern $grid[$row][$col] = 1; } elseif ($c == $rdci) { // right finder pattern if ($r % 2) { $grid[$row][$col] = 1; } else { $grid[$row][$col] = 0; } } else { // data bit if ($places[$i] < 2) { $grid[$row][$col] = $places[$i]; } else { // codeword ID $cw_id = floor($places[$i] / 10) - 1; // codeword BIT mask $cw_bit = pow(2, 8 - $places[$i] % 10); $grid[$row][$col] = ($cw[$cw_id] & $cw_bit) == 0 ? 0 : 1; } ++$i; } } } } } $this->barcode_array['num_rows'] = $params[0]; $this->barcode_array['num_cols'] = $params[1]; $this->barcode_array['bcode'] = $grid; }