public function __construct($code, $ecl = -1, $aspectratio = 2, $macro = array())
{
$barcode_array = array();
if (is_null($code) or $code == '\\0' or $code == '') {
return false;
}
// 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 false;
}
// 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 * 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', QUIETH) . $this->start_pattern;
$pstop = $this->stop_pattern . str_repeat('0', QUIETH);
$barcode_array['num_rows'] = $rows * ROWHEIGHT + 2 * QUIETV;
$barcode_array['num_cols'] = ($cols + 2) * 17 + 35 + 2 * QUIETH;
$barcode_array['bcode'] = array();
// build rows for vertical quiet zone
if (QUIETV > 0) {
$empty_row = array_fill(0, $barcode_array['num_cols'], 0);
for ($i = 0; $i < QUIETV; ++$i) {
// add vertical quiet rows
$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 < ROWHEIGHT; ++$h) {
$barcode_array['bcode'][] = $arow;
}
++$cid;
if ($cid > 2) {
$cid = 0;
}
}
if (QUIETV > 0) {
for ($i = 0; $i < QUIETV; ++$i) {
// add vertical quiet rows
$barcode_array['bcode'][] = $empty_row;
}
}
$this->barcode_array = $barcode_array;
}