From 8181d556dc9b453d67e873a925e004dfe7abe3c5 Mon Sep 17 00:00:00 2001 From: Nicola Asuni Date: Sat, 21 Oct 2023 00:32:33 +0100 Subject: [PATCH] AZTEC Code encoder (#79) * Raise minimum PH version to 5.6 and use constant arrays. * Add AZTEC Encoder --- .github/workflows/check.yml | 3 - README.md | 5 +- VERSION | 2 +- composer.json | 58 +- example/index.php | 2 + src/Barcode.php | 29 +- src/Type/Linear/Imb.php | 12 +- src/Type/Square/Aztec.php | 134 +++++ src/Type/Square/Aztec/Bitstream.php | 344 ++++++++++++ src/Type/Square/Aztec/Codeword.php | 309 ++++++++++ src/Type/Square/Aztec/Data.php | 530 ++++++++++++++++++ src/Type/Square/Aztec/Encode.php | 353 ++++++++++++ src/Type/Square/Aztec/ErrorCorrection.php | 254 +++++++++ src/Type/Square/Aztec/Layers.php | 162 ++++++ src/Type/Square/Datamatrix.php | 2 + src/Type/Square/Datamatrix/Data.php | 14 +- src/Type/Square/Datamatrix/EncodeTxt.php | 20 +- src/Type/Square/Datamatrix/Modes.php | 2 +- src/Type/Square/PdfFourOneSeven.php | 13 +- .../Square/PdfFourOneSeven/Compaction.php | 8 +- src/Type/Square/PdfFourOneSeven/Data.php | 24 +- src/Type/Square/PdfFourOneSeven/Sequence.php | 4 +- src/Type/Square/QrCode.php | 11 +- src/Type/Square/QrCode/ByteStream.php | 10 +- src/Type/Square/QrCode/Data.php | 44 +- src/Type/Square/QrCode/Encode.php | 8 +- src/Type/Square/QrCode/EncodingMode.php | 12 +- src/Type/Square/QrCode/Estimate.php | 16 +- src/Type/Square/QrCode/Init.php | 1 + src/Type/Square/QrCode/InputItem.php | 12 +- src/Type/Square/QrCode/Spec.php | 24 +- src/Type/Square/QrCode/SpecRs.php | 18 +- src/Type/Square/QrCode/Split.php | 38 +- test/BarcodeTest.php | 2 +- test/Square/AztecTest.php | 147 +++++ test/Square/DatamatrixTest.php | 2 +- test/Square/PdfFourOneSevenTest.php | 2 +- test/Square/QrCodeTest.php | 2 +- test/Square/RawTest.php | 2 +- 39 files changed, 2421 insertions(+), 214 deletions(-) create mode 100644 src/Type/Square/Aztec.php create mode 100644 src/Type/Square/Aztec/Bitstream.php create mode 100644 src/Type/Square/Aztec/Codeword.php create mode 100644 src/Type/Square/Aztec/Data.php create mode 100644 src/Type/Square/Aztec/Encode.php create mode 100644 src/Type/Square/Aztec/ErrorCorrection.php create mode 100644 src/Type/Square/Aztec/Layers.php create mode 100644 test/Square/AztecTest.php diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index aa68ef49..671cc402 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -28,9 +28,6 @@ jobs: os: [ubuntu-latest] coverage-extension: [pcov] include: - #- { php-version: '5.3', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } - #- { php-version: '5.4', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } - - { php-version: '5.5', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } - { php-version: '5.6', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } - { php-version: '7.1', experimental: false, os: ubuntu-latest, coverage-extension: 'xdebug' } steps: diff --git a/README.md b/README.md index d518ab88..9a8ddd2f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ This library includes utility PHP classes to generate linear and bidimensional b * CODE11 : CODE 11 * PHARMA : PHARMACODE * PHARMA2T : PHARMACODE TWO-TRACKS +* AZTEC : AZTEC Code (ISO/IEC 24778:2008) * DATAMATRIX : DATAMATRIX (ISO/IEC 16022) * PDF417 : PDF417 (ISO/IEC 15438:2006) * QRCODE : QR-CODE @@ -146,7 +147,7 @@ Create a composer.json in your projects root-directory: ```json { "require": { - "tecnickcom/tc-lib-barcode": "^1.17" + "tecnickcom/tc-lib-barcode": "^1.18" } } ``` @@ -154,7 +155,7 @@ Create a composer.json in your projects root-directory: Or add to an existing project with: ```bash -composer require tecnickcom/tc-lib-barcode ^1.17 +composer require tecnickcom/tc-lib-barcode ^1.18 ``` ## Packaging diff --git a/VERSION b/VERSION index c7c7e646..84cc5294 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.17.38 +1.18.0 diff --git a/composer.json b/composer.json index 3c27c937..7c37fbc8 100644 --- a/composer.json +++ b/composer.json @@ -5,41 +5,45 @@ "homepage": "http://www.tecnick.com", "license": "LGPL-3.0-or-later", "keywords": [ - "tc-lib-barcode", + "3 of 9", + "ANSI MH10.8M-1983", + "AZTEC", "barcode", + "CBC", + "CODABAR", + "CODE 11", + "CODE 128 A B C", "CODE 39", - "ANSI MH10.8M-1983", - "USD-3", - "3 of 9", "CODE 93", - "USS-93", - "Standard 2 of 5", - "Interleaved 2 of 5", - "CODE 128 A B C", - "UPC", - "EAN 8", + "Datamatrix", "EAN 13", - "UPC-A", - "UPC-E", - "MSI", - "POSTNET", - "PLANET", - "RMS4CC", - "Royal Mail", - "CBC", + "EAN 8", + "ECC200", + "Intelligent Mail Barcode", + "Interleaved 2 of 5", + "ISO/IEC 15438:2006", + "ISO/IEC 16022", + "ISO/IEC 24778:2008", "KIX", "Klant", - "Intelligent Mail Barcode", + "MSI", "Onecode", - "USPS-B-3200", - "CODABAR", - "CODE 11", - "PHARMACODE", + "PDF417", "PHARMACODE TWO-TRACKS", - "Datamatrix", - "ECC200", + "PHARMACODE", + "PLANET", + "POSTNET", "QR-Code", - "PDF417" + "RMS4CC", + "Royal Mail", + "Standard 2 of 5", + "tc-lib-barcode", + "UPC-A", + "UPC-E", + "UPC", + "USD-3", + "USPS-B-3200", + "USS-93" ], "authors": [ { @@ -49,7 +53,7 @@ } ], "require": { - "php": ">=5.4", + "php": ">=5.6", "ext-bcmath": "*", "ext-date": "*", "ext-gd": "*", diff --git a/example/index.php b/example/index.php index eab3e953..8d0f0cfd 100644 --- a/example/index.php +++ b/example/index.php @@ -57,6 +57,8 @@ $square = array( 'LRAW' => array('0101010101', '1D RAW MODE (comma-separated rows of 01 strings)'), 'SRAW' => array('0101,1010', '2D RAW MODE (comma-separated rows of 01 strings)'), + 'AZTEC' => array('ABCDabcd01234', 'AZTEC (ISO/IEC 24778:2008)'), + 'AZTEC,50,A,A' => array('ABCDabcd01234', 'AZTEC (ISO/IEC 24778:2008)'), 'PDF417' => array('0123456789', 'PDF417 (ISO/IEC 15438:2006)'), 'QRCODE' => array('0123456789', 'QR-CODE'), 'QRCODE,H,ST,0,0' => array('abcdefghijklmnopqrstuvwxy0123456789', 'QR-CODE WITH PARAMETERS'), diff --git a/src/Barcode.php b/src/Barcode.php index 7e530ce4..0e5278d1 100644 --- a/src/Barcode.php +++ b/src/Barcode.php @@ -35,18 +35,16 @@ class Barcode { /** * Array containing the map between the barcode type and correspondent class - * - * @var array */ - protected static $typeclass = array( + const TYPECLASS = array( + 'C128' => 'Linear\\CodeOneTwoEight', // CODE 128 'C128A' => 'Linear\\CodeOneTwoEight\\CodeOneTwoEightA', // CODE 128 A 'C128B' => 'Linear\\CodeOneTwoEight\\CodeOneTwoEightB', // CODE 128 B 'C128C' => 'Linear\\CodeOneTwoEight\\CodeOneTwoEightC', // CODE 128 C - 'C128' => 'Linear\\CodeOneTwoEight', // CODE 128 - 'C39E+' => 'Linear\\CodeThreeNineExtCheck', // CODE 39 EXTENDED + CHECKSUM - 'C39E' => 'Linear\\CodeThreeNineExt', // CODE 39 EXTENDED - 'C39+' => 'Linear\\CodeThreeNineCheck', // CODE 39 + CHECKSUM 'C39' => 'Linear\\CodeThreeNine', // CODE 39 - ANSI MH10.8M-1983 - USD-3 - 3 of 9. + 'C39+' => 'Linear\\CodeThreeNineCheck', // CODE 39 + CHECKSUM + 'C39E' => 'Linear\\CodeThreeNineExt', // CODE 39 EXTENDED + 'C39E+' => 'Linear\\CodeThreeNineExtCheck', // CODE 39 EXTENDED + CHECKSUM 'C93' => 'Linear\\CodeNineThree', // CODE 93 - USS-93 'CODABAR' => 'Linear\\Codabar', // CODABAR 'CODE11' => 'Linear\\CodeOneOne', // CODE 11 @@ -54,26 +52,27 @@ class Barcode 'EAN2' => 'Linear\\EanTwo', // EAN 2-Digits UPC-Based Extension 'EAN5' => 'Linear\\EanFive', // EAN 5-Digits UPC-Based Extension 'EAN8' => 'Linear\\EanEight', // EAN 8 - 'I25+' => 'Linear\\InterleavedTwoOfFiveCheck', // Interleaved 2 of 5 + CHECKSUM 'I25' => 'Linear\\InterleavedTwoOfFive', // Interleaved 2 of 5 + 'I25+' => 'Linear\\InterleavedTwoOfFiveCheck', // Interleaved 2 of 5 + CHECKSUM 'IMB' => 'Linear\\Imb', // IMB - Intelligent Mail Barcode - Onecode - USPS-B-3200 'IMBPRE' => 'Linear\\ImbPre', // IMB - Intelligent Mail Barcode pre-processed 'KIX' => 'Linear\\KlantIndex', // KIX (Klant index - Customer index) - 'MSI+' => 'Linear\\MsiCheck', // MSI + CHECKSUM (modulo 11) + 'LRAW' => 'Linear\\Raw', // 1D RAW MODE (comma-separated rows of 01 strings) 'MSI' => 'Linear\\Msi', // MSI (Variation of Plessey code) - 'PHARMA2T' => 'Linear\\PharmaTwoTracks', // PHARMACODE TWO-TRACKS + 'MSI+' => 'Linear\\MsiCheck', // MSI + CHECKSUM (modulo 11) 'PHARMA' => 'Linear\\Pharma', // PHARMACODE + 'PHARMA2T' => 'Linear\\PharmaTwoTracks', // PHARMACODE TWO-TRACKS 'PLANET' => 'Linear\\Planet', // PLANET 'POSTNET' => 'Linear\\Postnet', // POSTNET 'RMS4CC' => 'Linear\\RoyalMailFourCc', // RMS4CC (Royal Mail 4-state Customer Bar Code) - 'S25+' => 'Linear\\StandardTwoOfFiveCheck', // Standard 2 of 5 + CHECKSUM 'S25' => 'Linear\\StandardTwoOfFive', // Standard 2 of 5 + 'S25+' => 'Linear\\StandardTwoOfFiveCheck', // Standard 2 of 5 + CHECKSUM 'UPCA' => 'Linear\\UpcA', // UPC-A 'UPCE' => 'Linear\\UpcE', // UPC-E + 'AZTEC' => 'Square\\Aztec', // AZTEC Code (ISO/IEC 24778:2008) 'DATAMATRIX' => 'Square\\Datamatrix', // DATAMATRIX (ISO/IEC 16022) 'PDF417' => 'Square\\PdfFourOneSeven', // PDF417 (ISO/IEC 15438:2006) 'QRCODE' => 'Square\\QrCode', // QR-CODE - 'LRAW' => 'Linear\\Raw', // 1D RAW MODE (comma-separated rows of 01 strings) 'SRAW' => 'Square\\Raw', // 2D RAW MODE (comma-separated rows of 01 strings) ); @@ -84,7 +83,7 @@ class Barcode */ public function getTypes() { - return array_keys(self::$typeclass); + return array_keys(self::TYPECLASS); } /** @@ -116,10 +115,10 @@ public function getBarcodeObj( $params = explode(',', $type); $type = array_shift($params); - if (empty(self::$typeclass[$type])) { + if (!array_key_exists($type, self::TYPECLASS)) { throw new BarcodeException('Unsupported barcode type: ' . $type); } - $bclass = '\\Com\\Tecnick\\Barcode\\Type\\' . self::$typeclass[$type]; + $bclass = '\\Com\\Tecnick\\Barcode\\Type\\' . self::TYPECLASS[$type]; return new $bclass($code, $width, $height, $color, $params, $padding); } } diff --git a/src/Type/Linear/Imb.php b/src/Type/Linear/Imb.php index bee31444..ee77386c 100644 --- a/src/Type/Linear/Imb.php +++ b/src/Type/Linear/Imb.php @@ -67,7 +67,7 @@ class Imb extends \Com\Tecnick\Barcode\Type\Linear * * @var array */ - protected static $asc_chr = array( + const ASC_CHR = array( 4,0,2,6,3,5,1,9,8,7, 1,2,0,6,4,8,2,9,5,3, 0,1,3,7,4,6,8,9,2,0, @@ -82,7 +82,7 @@ class Imb extends \Com\Tecnick\Barcode\Type\Linear * * @var array */ - protected static $dsc_chr = array( + const DSC_CHR = array( 7,1,9,5,8,0,2,4,6,3, 5,8,9,7,3,0,6,1,7,4, 6,8,9,2,5,1,7,5,4,3, @@ -96,7 +96,7 @@ class Imb extends \Com\Tecnick\Barcode\Type\Linear * * @var array */ - protected static $asc_pos = array( + const ASC_POS = array( 3,0,8,11,1,12,8,11,10,6,4,12,2,7,9,6,7,9,2,8,4,0,12,7,10,9,0,7,10,5,7,9, 6,8,2,12,1,4,2,0,1,5,4,6,12,1,0,9,4,7,5,10,2,6,9,11,2,12,6,7,5,11,0,3,2); @@ -105,7 +105,7 @@ class Imb extends \Com\Tecnick\Barcode\Type\Linear * * @var array */ - protected static $dsc_pos = array( + const DSC_POS = array( 2,10,12,5,9,1,5,4,3,9,11,5,10,1,6,3,4,1,10,0,2,11,8,6,1,12,3,8,6,4,4,11, 0,6,1,9,11,5,3,7,3,10,7,11,8,2,10,3,5,8,0,3,12,11,8,4,5,1,3,0,7,12,9,8,10); @@ -312,8 +312,8 @@ protected function setBars() { $chars = $this->getCharsArray(); for ($pos = 0; $pos < 65; ++$pos) { - $asc = (($chars[self::$asc_chr[$pos]] & pow(2, self::$asc_pos[$pos])) > 0); - $dsc = (($chars[self::$dsc_chr[$pos]] & pow(2, self::$dsc_pos[$pos])) > 0); + $asc = (($chars[self::ASC_CHR[$pos]] & pow(2, self::ASC_POS[$pos])) > 0); + $dsc = (($chars[self::DSC_CHR[$pos]] & pow(2, self::DSC_POS[$pos])) > 0); if ($asc and $dsc) { // full bar (F) $this->bars[] = array($this->ncols, 0, 1, 3); diff --git a/src/Type/Square/Aztec.php b/src/Type/Square/Aztec.php new file mode 100644 index 00000000..97bfc987 --- /dev/null +++ b/src/Type/Square/Aztec.php @@ -0,0 +1,134 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square; + +use Com\Tecnick\Barcode\Type\Square\Aztec\Data; +use Com\Tecnick\Barcode\Type\Square\Aztec\Encode; +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec + * + * Aztec Barcode type class + * + * @since 2023-10-12 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2015-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +class Aztec extends \Com\Tecnick\Barcode\Type\Square +{ + /** + * Barcode format + * + * @var string + */ + protected $format = 'AZTEC'; + + /** + * Error correction code percentage of error check words. + * A minimum of 23% + 3 words is recommended by ISO/IEC 24778:2008a. + * + * @var int + */ + protected $ecc = 33; + + /** + * Encoding mode + * + * @var string + */ + protected $hint = 'A'; + + /** + * Mode: + * - A = Automatic selection between Compact (priority) and Full Range. + * - F = Force Full Range mode. + * + * @var string + */ + protected $mode = 'A'; + + /** + * Extended Channel Interpretation (ECI) code to be added at the beginning of the stream. + * See Data:ECI for the list of supported codes. + * NOTE: Even if special FNC1 or ECI flag characters could be inserted + * at any points in the stream, this will only be added at the beginning of the stream. + * + * @var int + */ + protected $eci = -1; + + /** + * Set extra (optional) parameters: + * 1: ECC : Error correction code percentage of error check words. + * A minimum of 23% + 3 words is recommended by ISO/IEC 24778:2008a. + * 2: HINT : Encoding mode: A=Automatic, B=Binary. + * 3: LAYERS : Custom number of layers (0 = auto). + * 4: ECI : Extended Channel Interpretation (ECI) code. Use -1 for FNC1. See $this->eci. + */ + protected function setParameters() + { + parent::setParameters(); + + // ecc percentage + if (!isset($this->params[0]) || !in_array($this->params[0], range(1, 100))) { + $this->params[0] = 33; + } + $this->ecc = intval($this->params[0]); + + // hint + if (!isset($this->params[1]) || !in_array($this->params[1], ['A', 'B'])) { + $this->params[1] = 'A'; + } + $this->hint = $this->params[1]; + + // mode + if (!isset($this->params[2]) || !in_array($this->params[2], ['A', 'F'])) { + $this->params[2] = 'A'; + } + $this->mode = $this->params[2]; + + // eci code. Used to set the charset encoding. See $this->eci. + if (!isset($this->params[3]) || !array_key_exists($this->params[3], Data::ECI)) { + $this->params[3] = -1; + } + $this->eci = intval($this->params[3]); + } + + /** + * Get the bars array + * + * @throws BarcodeException in case of error + */ + protected function setBars() + { + if (strlen((string)$this->code) == 0) { + throw new BarcodeException('Empty input'); + } + try { + $enc = new Encode($this->code, $this->ecc, $this->eci, $this->hint, $this->mode); + $grid = $enc->getGrid(); + $this->processBinarySequence($grid); + } catch (BarcodeException $e) { + throw new BarcodeException('AZTEC: ' . $e->getMessage()); + } + } +} diff --git a/src/Type/Square/Aztec/Bitstream.php b/src/Type/Square/Aztec/Bitstream.php new file mode 100644 index 00000000..05f5d1a9 --- /dev/null +++ b/src/Type/Square/Aztec/Bitstream.php @@ -0,0 +1,344 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Type\Square\Aztec\Data; +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\Bitstream + * + * Bitstream for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) + */ +abstract class Bitstream extends \Com\Tecnick\Barcode\Type\Square\Aztec\Layers +{ + /** + * Performs the high-level encoding for the given code and ECI mode. + * + * @param string $code The code to encode. + * @param int $eci The ECI mode to use. + * @param string $hint The mode to use. + */ + protected function highLevelEncoding($code, $eci = 0, $hint = 'A') + { + $this->addFLG($eci); + $chars = array_values(unpack('C*', $code)); + $chrlen = count($chars); + if ($hint == 'B') { + $this->binaryEncode($chars, $chrlen); + return; + } + $this->autoEncode($chars, $chrlen); + } + + /** + * Forced binary encoding for the given characters. + * + * @param array $chars Integer ASCII values of the characters to encode. + * @param int $chrlen Lenght of the $chars array. + */ + protected function binaryEncode($chars, $chrlen) + { + $bits = Data::MODE_BITS[Data::MODE_BINARY]; + $this->addShift(Data::MODE_BINARY); + if ($chrlen > 62) { + $this->addRawCwd(5, 0); + $this->addRawCwd(11, $chrlen); + for ($idx = 0; $idx < $chrlen; $idx++) { + $this->addRawCwd($bits, $chars[$idx]); + } + return; + } + if ($chrlen > 31) { + $this->addRawCwd(5, 31); + for ($idx = 0; $idx < 31; $idx++) { + $this->addRawCwd($bits, $chars[$idx]); + } + $this->addShift(Data::MODE_BINARY); + $this->addRawCwd(5, ($chrlen - 31)); + for ($idx = 31; $idx < $chrlen; $idx++) { + $this->addRawCwd($bits, $chars[$idx]); + } + return; + } + $this->addRawCwd(5, $chrlen); + for ($idx = 0; $idx < $chrlen; $idx++) { + $this->addRawCwd($bits, $chars[$idx]); + } + } + + /** + * Automatic encoding for the given characters. + * + * @param array $chars Integer ASCII values of the characters to encode. + * @param int $chrlen Lenght of the $chars array. + */ + protected function autoEncode($chars, $chrlen) + { + $idx = 0; + while ($idx < $chrlen) { + if ($this->processBinaryChars($chars, $idx, $chrlen)) { + continue; + } + if ($this->processPunctPairs($chars, $idx, $chrlen)) { + continue; + } + $this->processModeChars($chars, $idx, $chrlen); + } + } + + /** + * Process mode characters. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + */ + protected function processModeChars(&$chars, &$idx, $chrlen) + { + $ord = $chars[$idx]; + if ($this->isSameMode($this->encmode, $ord)) { + $mode = $this->encmode; + } else { + $mode = $this->charMode($ord); + } + $nchr = $this->countModeChars($chars, $idx, $chrlen, $mode); + if ($this->encmode != $mode) { + if (($nchr == 1) && (!empty(Data::SHIFT_MAP[$this->encmode][$mode]))) { + $this->addShift($mode); + } else { + $this->addLatch($mode); + } + } + $this->mergeTmpCwd(); + $idx += $nchr; + } + + /** + * Count consecutive characters in the same mode. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + * @param int $mode The current mode. + * + * @return int + */ + protected function countModeChars(&$chars, $idx, $chrlen, $mode) + { + $this->tmpCdws = array(); + $nbits = Data::MODE_BITS[$mode]; + $count = 0; + do { + $ord = $chars[$idx]; + if ( + (!$this->isSameMode($mode, $ord)) + || (($idx < ($chrlen - 1)) && ($this->punctPairMode($ord, $chars[($idx + 1)]) > 0)) + ) { + return $count; + } + $this->tmpCdws[] = array($nbits, $this->charEnc($mode, $ord)); + $count++; + $idx++; + } while ($idx < $chrlen); + return $count; + } + + /** + * Process consecutive binary characters. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + * + * @return bool True if binary characters have been found and processed. + */ + protected function processBinaryChars(&$chars, &$idx, $chrlen) + { + $binchrs = $this->countBinaryChars($chars, $idx, $chrlen); + if ($binchrs == 0) { + return false; + } + $encmode = $this->encmode; + $this->addShift(Data::MODE_BINARY); + if ($binchrs > 62) { + $this->addRawCwd(5, 0); + $this->addRawCwd(11, $binchrs); + $this->mergeTmpCwdRaw(); + $idx += $binchrs; + $this->encmode = $encmode; + return true; + } + if ($binchrs > 31) { + $nbits = Data::MODE_BITS[Data::MODE_BINARY]; + $this->addRawCwd(5, 31); + for ($bcw = 0; $bcw < 31; $bcw++) { + $this->addRawCwd($nbits, $this->tmpCdws[$bcw][1]); + } + $this->addShift(Data::MODE_BINARY); + $this->addRawCwd(5, ($binchrs - 31)); + for ($bcw = 31; $bcw < $binchrs; $bcw++) { + $this->addRawCwd($nbits, $this->tmpCdws[$bcw][1]); + } + $idx += $binchrs; + $this->encmode = $encmode; + return true; + } + $this->addRawCwd(5, $binchrs); + $this->mergeTmpCwdRaw(); + $idx += $binchrs; + $this->encmode = $encmode; + return true; + } + + /** + * Count consecutive binary characters. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + * + * @return int + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + protected function countBinaryChars(&$chars, $idx, $chrlen) + { + $this->tmpCdws = array(); + $count = 0; + $nbits = Data::MODE_BITS[Data::MODE_BINARY]; + while (($idx < $chrlen) && ($count < 2048)) { + $ord = $chars[$idx]; + if ($this->charMode($ord) != Data::MODE_BINARY) { + return $count; + } + $this->tmpCdws[] = array($nbits, $ord); + $count++; + $idx++; + } + return $count; + } + + /** + * Process consecutive special Punctuation Pairs. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + * + * @return bool True if pair characters have been found and processed. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + */ + protected function processPunctPairs(&$chars, &$idx, $chrlen) + { + + $ppairs = $this->countPunctPairs($chars, $idx, $chrlen); + if ($ppairs == 0) { + return false; + } + switch ($this->encmode) { + case Data::MODE_PUNCT: + break; + case Data::MODE_MIXED: + $this->addLatch(Data::MODE_PUNCT); + break; + case Data::MODE_UPPER: + case Data::MODE_LOWER: + if ($ppairs > 1) { + $this->addLatch(Data::MODE_PUNCT); + } + break; + case Data::MODE_DIGIT: + $common = $this->countPunctAndDigitChars($chars, $idx, $chrlen); + $clen = count($common); + if (($clen > 0) && ($clen < 6)) { + $this->tmpCdws = $common; + $this->mergeTmpCwdRaw(); + $idx += $clen; + return true; + } + if ($ppairs > 2) { + $this->addLatch(Data::MODE_PUNCT); + } + break; + } + $this->mergeTmpCwd(Data::MODE_PUNCT); + $idx += ($ppairs * 2); + return true; + } + + /** + * Count consecutive special Punctuation Pairs. + * + * @param array $chars The array of characters. + * @param int $idx The current character index. + * @param int $chrlen The total number of characters to process. + * + * @return int + */ + protected function countPunctPairs(&$chars, $idx, $chrlen) + { + $this->tmpCdws = array(); + $pairs = 0; + $maxidx = $chrlen - 1; + while ($idx < $maxidx) { + $pmode = $this->punctPairMode($chars[$idx], $chars[($idx + 1)]); + if ($pmode == 0) { + return $pairs; + } + $this->tmpCdws[] = array(5, $pmode); + $pairs++; + $idx += 2; + } + return $pairs; + } + + /** + * Counts the number of consecutive charcters that are in both PUNCT or DIGIT modes. + * Returns the array with the codewords. + * + * @param array &$chars The string to count the characters in. + * @param int $idx The starting index to count from. + * @param int $chrlen The length of the string to count. + * + * @return array + */ + protected function countPunctAndDigitChars(&$chars, $idx, $chrlen) + { + $words = array(); + while ($idx < $chrlen) { + $ord = $chars[$idx]; + if (!$this->isPunctAndDigitChar($ord)) { + return $words; + } + $words[] = array(4, $this->charEnc(Data::MODE_DIGIT, $ord)); + $idx++; + } + return $words; + } +} diff --git a/src/Type/Square/Aztec/Codeword.php b/src/Type/Square/Aztec/Codeword.php new file mode 100644 index 00000000..bf6d377b --- /dev/null +++ b/src/Type/Square/Aztec/Codeword.php @@ -0,0 +1,309 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Type\Square\Aztec\Data; +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\Codeword + * + * Codeword utility methods for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +abstract class Codeword +{ + /** + * Current character encoding mode. + * + * @var int + */ + protected $encmode = Data::MODE_UPPER; + + /** + * Array containing the high-level encoding bitstream. + * + * @var array + */ + protected $bitstream = array(); + + /** + * Temporary array of codewords. + * + * @var array + */ + protected $tmpCdws = array(); + + /** + * Array of data words. + * + * @var array + */ + protected $words = array(); + + /** + * Count the total number of bits in the bitstream. + * + * @var int + */ + protected $totbits = 0; + + /** + * Encodes a character using the specified mode and ordinal value. + * + * @param int $mode The encoding mode. + * @param int $ord The ordinal value of the character to encode. + * + * @return int The encoded character. + */ + protected function charEnc($mode, $ord) + { + return array_key_exists($ord, DATA::CHAR_ENC[$mode]) ? DATA::CHAR_ENC[$mode][$ord] : 0; + } + + /** + * Returns the character mode for a given ASCII code. + * + * @param int $ord The ASCII code of the character. + * + * @return int The character mode. + */ + protected function charMode($ord) + { + return array_key_exists($ord, DATA::CHAR_MODES) ? DATA::CHAR_MODES[$ord] : Data::MODE_BINARY; + } + + /** + * Checks if current character is supported by the current code. + * + * @param int $mode The mode to check. + * @param int $ord The character ASCII value to compare against. + * + * @return bool Returns true if the mode is the same as the ordinal value, false otherwise. + */ + protected function isSameMode($mode, $ord) + { + return ( + ($mode == $this->charMode($ord)) + || (($ord == 32) && ($mode != Data::MODE_PUNCT)) + || (($mode == Data::MODE_PUNCT) && (($ord == 13) || ($ord == 44) || ($ord == 46))) + ); + } + + /** + * Returns true if the character is in common between the PUNCT and DIGIT modes. + * Characters ' ' (32), '.' (46) and ',' (44) are in common between the PUNCT and DIGIT modes. + * + * @param int $ord Integer ASCII code of the character to check. + * + * @return bool + */ + protected function isPunctAndDigitChar($ord) + { + return (($ord == 32) || ($ord == 44) || ($ord == 46)); + } + + /** + * Returns the PUNCT two-bytes code if the given two characters are a punctuation pair. + * Punct codes 2–5 encode two bytes each. + * + * @param int $ord The current curacter code. + * @param int $next The next character code. + * + * @return int + */ + protected function punctPairMode($ord, $next) + { + $key = (($ord << 8) + $next); + switch ($key) { + case ((13 << 8) + 10): // '\r\n' (CR LF) + return 2; + case ((46 << 8) + 32): // '. ' (. SP) + return 3; + case ((44 << 8) + 32): // ', ' (, SP) + return 4; + case ((58 << 8) + 32): // ': ' (: SP) + return 5; + } + return 0; // no punct pair + } + + /** + * Append a new Codeword as a big-endian bit sequence. + * + * @param array $bitstream Array of bits to append to. + * @param int $totbits Number of bits in the bitstream. + * @param int $wsize The number of bits in the codeword. + * @param int $value The value of the codeword. + */ + protected function appendWordToBitstream(array &$bitstream, &$totbits, $wsize, $value) + { + for ($idx = ($wsize - 1); $idx >= 0; $idx--) { + $bitstream[] = (($value >> $idx) & 1); + } + $totbits += $wsize; + } + + /** + * Convert the bitstream to words. + * + * @param array $bitstream Array of bits to convert. + * @param int $totbits Number of bits in the bitstream. + * @param int $wsize The word size. + * + * @return array + */ + protected function bitstreamToWords(array $bitstream, $totbits, $wsize) + { + $words = array(); + $numwords = intval(ceil($totbits / $wsize)); + for ($idx = 0; $idx < $numwords; $idx++) { + $wrd = 0; + for ($bit = 0; $bit < $wsize; $bit++) { + $pos = (($idx * $wsize) + $bit); + if (!empty($bitstream[$pos]) || !isset($bitstream[$pos])) { + $wrd |= (1 << ($wsize - $bit - 1)); // reverse order + } + } + $words[] = $wrd; + } + return $words; + } + + /** + * Add a new Codeword as a big-endian bit sequence. + * + * @param int $bits The number of bits in the codeword. + * @param int $value The value of the codeword. + */ + protected function addRawCwd($bits, $value) + { + $this->appendWordToBitstream($this->bitstream, $this->totbits, $bits, $value); + } + + /** + * Adds a Codeword. + * + * @param int $mode The encoding mode. + * @param int $value The value to encode. + */ + protected function addCdw($mode, $value) + { + $this->addRawCwd(Data::MODE_BITS[$mode], $value); + } + + /** + * Latch to another mode. + * + * @param int $mode The new encoding mode. + */ + protected function addLatch($mode) + { + $latch = Data::LATCH_MAP[$this->encmode][$mode]; + foreach ($latch as $cdw) { + $this->addRawCwd($cdw[0], $cdw[1]); + } + $this->encmode = $mode; + } + + /** + * Shift to another mode. + */ + protected function addShift($mode) + { + $shift = Data::SHIFT_MAP[$this->encmode][$mode]; + foreach ($shift as $cdw) { + $this->addRawCwd($cdw[0], $cdw[1]); + } + } + + /** + * Merges the temporary codewords array with the current codewords array. + * Shift to the specified mode. + * + * @param int $mode The encoding mode for the codewords. + */ + protected function mergeTmpCwdWithShift($mode) + { + foreach ($this->tmpCdws as $item) { + $this->addShift($mode); + $this->addRawCwd($item[0], $item[1]); + } + } + + /** + * Merges the temporary codewords array with the current codewords array. + * No shift is performed. + */ + protected function mergeTmpCwdRaw() + { + foreach ($this->tmpCdws as $item) { + $this->addRawCwd($item[0], $item[1]); + } + } + + /** + * Merge temporary codewords with current codewords based on the encoding mode. + * + * @param int $mode The encoding mode to use for merging codewords. + * If negative, the current encoding mode will be used. + */ + protected function mergeTmpCwd($mode = -1) + { + if (($mode < 0) || ($this->encmode == $mode)) { + $this->mergeTmpCwdRaw(); + } else { + $this->mergeTmpCwdWithShift($mode); + } + $this->tmpCdws = array(); + } + + /** + * Adds the FLG (Function Length Group) codeword to the data codewords. + * + * @param int $eci Extended Channel Interpretation value. If negative, the function does nothing. + */ + protected function addFLG($eci) + { + if ($eci < 0) { + return; + } + if ($this->encmode != Data::MODE_PUNCT) { + $this->addShift(Data::MODE_PUNCT); + } + if ($eci == 0) { + $this->addRawCwd(3, 0); // FNC1 + return; + } + $seci = (string)$eci; + $digits = strlen($seci); + $this->addRawCwd(3, $digits); // 1–6 digits + for ($idx = 0; $idx < $digits; $idx++) { + $this->addCdw( + Data::MODE_DIGIT, + $this->charEnc(Data::MODE_DIGIT, ord($seci[$idx])) + ); + } + } +} diff --git a/src/Type/Square/Aztec/Data.php b/src/Type/Square/Aztec/Data.php new file mode 100644 index 00000000..a516f1a6 --- /dev/null +++ b/src/Type/Square/Aztec/Data.php @@ -0,0 +1,530 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\Data + * + * Data for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +class Data +{ + /** + * Code character encoding mode for uppercase letters. + */ + const MODE_UPPER = 0; + + /** + * Code character encoding mode for lowercase letters. + */ + const MODE_LOWER = 1; + + /** + * Code character encoding mode for digits. + */ + const MODE_DIGIT = 2; + + /** + * Code character encoding mode for mixed cases. + */ + const MODE_MIXED = 3; + + /** + * Code character encoding mode for punctuation. + */ + const MODE_PUNCT = 4; + + /** + * Code character encoding mode for binary. + */ + const MODE_BINARY = 5; + + /** + * Number of bits for each character encoding mode. + */ + const MODE_BITS = array( + 5, // 0 = MODE_UPPER + 5, // 1 = MODE_LOWER + 4, // 2 = MODE_DIGIT + 5, // 3 = MODE_MIXED + 5, // 4 = MODE_PUNCT + 8 // 5 = MODE_BINARY + ); + + /** + * Code character encoding for each mode. + */ + const CHAR_ENC = array( + // MODE_UPPER (initial mode) + 0 => array( + 32 => 1, // ' ' (SP) + 65 => 2, // 'A' + 66 => 3, // 'B' + 67 => 4, // 'C' + 68 => 5, // 'D' + 69 => 6, // 'E' + 70 => 7, // 'F' + 71 => 8, // 'G' + 72 => 9, // 'H' + 73 => 10, // 'I' + 74 => 11, // 'J' + 75 => 12, // 'K' + 76 => 13, // 'L' + 77 => 14, // 'M' + 78 => 15, // 'N' + 79 => 16, // 'O' + 80 => 17, // 'P' + 81 => 18, // 'Q' + 82 => 19, // 'R' + 83 => 20, // 'S' + 84 => 21, // 'T' + 85 => 22, // 'U' + 86 => 23, // 'V' + 87 => 24, // 'W' + 88 => 25, // 'X' + 89 => 26, // 'Y' + 90 => 27 // 'Z' + ), + // MODE_LOWER + 1 => array( + 32 => 1, // ' ' (SP) + 97 => 2, // 'a' + 98 => 3, // 'b' + 99 => 4, // 'c' + 100 => 5, // 'd' + 101 => 6, // 'e' + 102 => 7, // 'f' + 103 => 8, // 'g' + 104 => 9, // 'h' + 105 => 10, // 'i' + 106 => 11, // 'j' + 107 => 12, // 'k' + 108 => 13, // 'l' + 109 => 14, // 'm' + 110 => 15, // 'n' + 111 => 16, // 'o' + 112 => 17, // 'p' + 113 => 18, // 'q' + 114 => 19, // 'r' + 115 => 20, // 's' + 116 => 21, // 't' + 117 => 22, // 'u' + 118 => 23, // 'v' + 119 => 24, // 'w' + 120 => 25, // 'x' + 121 => 26, // 'y' + 122 => 27 // 'z' + ), + // MODE_DIGIT + 2 => array( + 32 => 1, // ' ' (SP) + 44 => 12, // ',' + 46 => 13, // '.' + 48 => 2, // '0' + 49 => 3, // '1' + 50 => 4, // '2' + 51 => 5, // '3' + 52 => 6, // '4' + 53 => 7, // '5' + 54 => 8, // '6' + 55 => 9, // '7' + 56 => 10, // '8' + 57 => 11 // '9' + ), + // MODE_MIXED + 3 => array( + 1 => 2, // '^A' (SOH) + 2 => 3, // '^B' (STX) + 3 => 4, // '^C' (ETX) + 4 => 5, // '^D' (EOT) + 5 => 6, // '^E' (ENQ) + 6 => 7, // '^F' (ACK) + 7 => 8, // '^G' (BEL) + 8 => 9, // '^H' (BS) + 9 => 10, // '^I' (HT) + 10 => 11, // '^J' (LF) + 11 => 12, // '^K' (VT) + 12 => 13, // '^L' (FF) + 13 => 14, // '^M' (CR) + 27 => 15, // '^[' (ESC) + 28 => 16, // '^\' (FS) + 29 => 17, // '^]' (GS) + 30 => 18, // '^^' (RS) + 31 => 19, // '^_' (US) + 64 => 20, // '@' + 92 => 21, // '\' + 94 => 22, // '^' + 95 => 23, // '_' + 96 => 24, // '`' + 124 => 25, // '|' + 126 => 26, // '~' + 127 => 27 // '^?' (DEL) + ), + // MODE_PUNCT + 4 => array( + 13 => 1, // '\r' (CR) + 33 => 6, // '!' + 34 => 7, // '"' + 35 => 8, // '#' + 36 => 9, // '$' + 37 => 10, // '%' + 38 => 11, // '&' + 39 => 12, // ''' + 40 => 13, // '(' + 41 => 14, // ')' + 42 => 15, // '*' + 43 => 16, // '+' + 44 => 17, // ',' + 45 => 18, // '-' + 46 => 19, // '.' + 47 => 20, // '/' + 58 => 21, // ':' + 59 => 22, // ';' + 60 => 23, // '<' + 61 => 24, // '=' + 62 => 25, // '>' + 63 => 26, // '?' + 91 => 27, // '[' + 93 => 28, // ']' + 123 => 29, // '{' + 125 => 30 // '}' + ), + // MODE_BINARY (all 8-bit values are valid) + 5 => array() + ); + + /** + * Map character ASCII codes to their non-binary mode. + * Exceptions are: + * - the space ' ' character (32) that maps for modes 0,1,2. + * - the carriage return '\r' character (13) that maps for modes 3,4. + * - the comma ',' and dot '.' characters (44,46) that map for modes 2,4. + */ + const CHAR_MODES = array( + 1 => 3, // '^A' (SOH) + 2 => 3, // '^B' (STX) + 3 => 3, // '^C' (ETX) + 4 => 3, // '^D' (EOT) + 5 => 3, // '^E' (ENQ) + 6 => 3, // '^F' (ACK) + 7 => 3, // '^G' (BEL) + 8 => 3, // '^H' (BS) + 9 => 3, // '^I' (HT) + 10 => 3, // '^J' (LF) + 11 => 3, // '^K' (VT) + 12 => 3, // '^L' (FF) + 13 => 3, // '^M' (CR) [3,4] + 27 => 3, // '^[' (ESC) + 28 => 3, // '^\' (FS) + 29 => 3, // '^]' (GS) + 30 => 3, // '^^' (RS) + 31 => 3, // '^_' (US) + 32 => 0, // ' ' [0,1,2] + 33 => 4, // '!' + 34 => 4, // '"' + 35 => 4, // '#' + 36 => 4, // '$' + 37 => 4, // '%' + 38 => 4, // '&' + 39 => 4, // ''' + 40 => 4, // '(' + 41 => 4, // ')' + 42 => 4, // '*' + 43 => 4, // '+'f + 44 => 2, // ',' [2,4] + 45 => 4, // '-' + 46 => 2, // '.' [2,4] + 47 => 4, // '/' + 48 => 2, // '0' + 49 => 2, // '1' + 50 => 2, // '2' + 51 => 2, // '3' + 52 => 2, // '4' + 53 => 2, // '5' + 54 => 2, // '6' + 55 => 2, // '7' + 56 => 2, // '8' + 57 => 2, // '9' + 58 => 4, // ':' + 59 => 4, // ';' + 60 => 4, // '<' + 61 => 4, // '=' + 62 => 4, // '>' + 63 => 4, // '?' + 64 => 3, // '@' + 65 => 0, // 'A' + 66 => 0, // 'B' + 67 => 0, // 'C' + 68 => 0, // 'D' + 69 => 0, // 'E' + 70 => 0, // 'F' + 71 => 0, // 'G' + 72 => 0, // 'H' + 73 => 0, // 'I' + 74 => 0, // 'J' + 75 => 0, // 'K' + 76 => 0, // 'L' + 77 => 0, // 'M' + 78 => 0, // 'N' + 79 => 0, // 'O' + 80 => 0, // 'P' + 81 => 0, // 'Q' + 82 => 0, // 'R' + 83 => 0, // 'S' + 84 => 0, // 'T' + 85 => 0, // 'U' + 86 => 0, // 'V' + 87 => 0, // 'W' + 88 => 0, // 'X' + 89 => 0, // 'Y' + 90 => 0, // 'Z' + 91 => 4, // '[' + 92 => 3, // '\' + 93 => 4, // ']' + 94 => 3, // '^' + 95 => 3, // '_' + 96 => 3, // '`' + 97 => 1, // 'a' + 98 => 1, // 'b' + 99 => 1, // 'c' + 100 => 1, // 'd' + 101 => 1, // 'e' + 102 => 1, // 'f' + 103 => 1, // 'g' + 104 => 1, // 'h' + 105 => 1, // 'i' + 106 => 1, // 'j' + 107 => 1, // 'k' + 108 => 1, // 'l' + 109 => 1, // 'm' + 110 => 1, // 'n' + 111 => 1, // 'o' + 112 => 1, // 'p' + 113 => 1, // 'q' + 114 => 1, // 'r' + 115 => 1, // 's' + 116 => 1, // 't' + 117 => 1, // 'u' + 118 => 1, // 'v' + 119 => 1, // 'w' + 120 => 1, // 'x' + 121 => 1, // 'y' + 122 => 1, // 'z' + 123 => 4, // '{' + 124 => 3, // '|' + 125 => 4, // '}' + 126 => 3, // '~' + 127 => 3 // '^?' (DEL) + ); + + /** + * Latch map for changing character encoding mode. + * Numbers represent: [number of bits to change, latch code value]. + */ + const LATCH_MAP = array( + // MODE_UPPER + 0 => array ( + 1 => array(array(5,28)), // -> LOWER + 2 => array(array(5,30)), // -> DIGIT + 3 => array(array(5,29)), // -> MIXED + 4 => array(array(5,29),array(5,30)) // -> MIXED -> PUNCT + ), + // MODE_LOWER + 1 => array ( + 0 => array(array(5,30),array(4,14)), // -> DIGIT -> UPPER + 2 => array(array(5,30)), // -> DIGIT + 3 => array(array(5,29)), // -> MIXED + 4 => array(array(5,29),array(5,30)) // -> MIXED -> PUNCT + ), + // MODE_DIGIT + 2 => array ( + 0 => array(array(4,14)), // -> UPPER + 1 => array(array(4,14),array(5,28)), // -> UPPER -> LOWER + 3 => array(array(4,14),array(5,29)), // -> UPPER -> MIXED + 4 => array(array(4,14),array(5,29),array(5,30)) // -> UPPER -> MIXED -> PUNCT + ), + // MODE_MIXED + 3 => array ( + 0 => array(array(5,29)), // -> UPPER + 1 => array(array(5,28)), // -> LOWER + 2 => array(array(5,29),array(5,30)), // -> UPPER -> DIGIT + 4 => array(array(5, 30)) // -> PUNCT + ), + // MODE_PUNCT + 4 => array ( + 0 => array(array(5,31)), // -> UPPER + 1 => array(array(5,31),array(5,28)), // -> UPPER -> LOWER + 2 => array(array(5,31),array(5,30)), // -> UPPER -> DIGIT + 3 => array(array(5,31),array(5,29)), // -> UPPER -> MIXED + ) + ); + + /** + * Shift map for changing character encoding mode. + * Numbers represent: [number of bits to change, shift code value]. + */ + const SHIFT_MAP = array( + // MODE_UPPER + 0 => array( + 1 => array(), + 2 => array(), + 3 => array(), + 4 => array(array(5,0)), // -> PUNCT + 5 => array(array(5,31)) // -> BINARY + ), + // MODE_LOWER + 1 => array ( + 0 => array(array(5,28)), // -> UPPER + 2 => array(), + 3 => array(), + 4 => array(array(5,0)), // -> PUNCT + 5 => array(array(5,31)) // -> BINARY + ), + // MODE_DIGIT + 2 => array ( + 0 => array(array(4,15)), // -> UPPER + 1 => array(), + 3 => array(), + 4 => array(array(4,0)), // -> PUNCT + 5 => array(array(4,14),array(5,31)) // -> LATCH UPPER -> BINARY + ), + // MODE_MIXED + 3 => array ( + 0 => array(), + 1 => array(), + 2 => array(), + 4 => array(array(5,0)), // -> PUNCT + 5 => array(array(5,31)) // -> BINARY + ), + // MODE_PUNCT + 4 => array ( + 0 => array(), + 1 => array(), + 2 => array(), + 3 => array(), + 5 => array(array(5,31),array(5,31)) // -> LATCH UPPER -> BINARY + ) + ); + + /** + * Extended Channel Interpretation (ECI) codes. + */ + const ECI = array( + 0 => 'FNC1', // Function 1 character + 2 => 'Cp437', // Code page 437 + 3 => 'ISO-8859-1', // ISO/IEC 8859-1 - Latin-1 (Default encoding) + 4 => 'ISO-8859-2', // ISO/IEC 8859-2 - Latin-2 + 5 => 'ISO-8859-3', // ISO/IEC 8859-3 - Latin-3 + 6 => 'ISO-8859-4', // ISO/IEC 8859-4 - Latin-4 + 7 => 'ISO-8859-5', // ISO/IEC 8859-5 - Latin/Cyrillic + 8 => 'ISO-8859-6', // ISO/IEC 8859-6 - Latin/Arabic + 9 => 'ISO-8859-7', // ISO/IEC 8859-7 - Latin/Greek + 10 => 'ISO-8859-8', // ISO/IEC 8859-8 - Latin/Hebrew + 11 => 'ISO-8859-9', // ISO/IEC 8859-9 - Latin-5 + 12 => 'ISO-8859-10', // ISO/IEC 8859-10 - Latin-6 + 13 => 'ISO-8859-11', // ISO/IEC 8859-11 - Latin/Thai + 15 => 'ISO-8859-13', // ISO/IEC 8859-13 - Latin-7 + 16 => 'ISO-8859-14', // ISO/IEC 8859-14 - Latin-8 (Celtic) + 17 => 'ISO-8859-15', // ISO/IEC 8859-15 - Latin-9 + 18 => 'ISO-8859-16', // ISO/IEC 8859-16 - Latin-10 + 20 => 'Shift JIS', // + 21 => 'Cp1250', // Windows-1250 - Superset of Latin-2 + 22 => 'Cp1251', // Windows-1251 - Latin/Cyrillic + 23 => 'Cp1252', // Windows-1252 - Superset of Latin-1 + 24 => 'Cp1256', // Windows-1256 - Arabic + 25 => 'UTF-16BE', // UnicodeBig, UnicodeBigUnmarked + 26 => 'UTF-8', // + 27 => 'US-ASCII', // + 28 => 'Big5', // + 29 => 'GB18030', // GB2312, EUC_CN, GBK + 30 => 'EUC-KR' // + ); + + /** + * Size and capacities of Aztec Compact Code symbols by number of layers. + * The array entries are: + * - 0: symbol x size; + * - 1: codeword count; + * - 2: codeword size; + * - 3: symbol bit capacity; + * - 4: symbol data digits capacity; + * - 5: symbol data text capacity; + * - 6: symbol data bytes capacity. + */ + const SIZE_COMPACT = array( + 1 => array(15, 17, 6, 102, 13, 12, 6), + 2 => array(19, 40, 6, 240, 40, 33, 19), + 3 => array(23, 51, 8, 408, 70, 57, 33), + 4 => array(27, 76, 8, 608, 110, 89, 53) + ); + + /** + * Size and capacities of Aztec Full-range Code symbols by number of layers. + * The array entries are: + * - 0: symbol x size; + * - 1: codeword count; + * - 2: codeword size; + * - 3: symbol bit capacity; + * - 4: symbol data digits capacity; + * - 5: symbol data text capacity; + * - 6: symbol data bytes capacity. + */ + const SIZE_FULL = array( + 1 => array( 19, 21, 6, 126, 18, 15, 8), + 2 => array( 23, 48, 6, 288, 49, 40, 24), + 3 => array( 27, 60, 8, 480, 84, 68, 40), + 4 => array( 31, 88, 8, 704, 128, 104, 62), + 5 => array( 37, 120, 8, 960, 178, 144, 87), + 6 => array( 41, 156, 8, 1248, 232, 187, 114), + 7 => array( 45, 196, 8, 1568, 294, 236, 145), + 8 => array( 49, 240, 8, 1920, 362, 291, 179), + 9 => array( 53, 230, 10, 2300, 433, 348, 214), + 10 => array( 57, 272, 10, 2720, 516, 414, 256), + 11 => array( 61, 316, 10, 3160, 601, 482, 298), + 12 => array( 67, 364, 10, 3640, 691, 554, 343), + 13 => array( 71, 416, 10, 4160, 793, 636, 394), + 14 => array( 75, 470, 10, 4700, 896, 718, 446), + 15 => array( 79, 528, 10, 5280, 1008, 808, 502), + 16 => array( 83, 588, 10, 5880, 1123, 900, 559), + 17 => array( 87, 652, 10, 6520, 1246, 998, 621), + 18 => array( 91, 720, 10, 7200, 1378, 1104, 687), + 19 => array( 95, 790, 10, 7900, 1511, 1210, 753), + 20 => array(101, 864, 10, 8640, 1653, 1324, 824), + 21 => array(105, 940, 10, 9400, 1801, 1442, 898), + 22 => array(109, 1020, 10, 10200, 1956, 1566, 976), + 23 => array(113, 920, 12, 11040, 2116, 1694, 1056), + 24 => array(117, 992, 12, 11904, 2281, 1826, 1138), + 25 => array(121, 1066, 12, 12792, 2452, 1963, 1224), + 26 => array(125, 1144, 12, 13728, 2632, 2107, 1314), + 27 => array(131, 1224, 12, 14688, 2818, 2256, 1407), + 28 => array(135, 1306, 12, 15672, 3007, 2407, 1501), + 29 => array(139, 1392, 12, 16704, 3205, 2565, 1600), + 30 => array(143, 1480, 12, 17760, 3409, 2728, 1702), + 31 => array(147, 1570, 12, 18840, 3616, 2894, 1806), + 32 => array(151, 1664, 12, 19968, 3832, 3067, 1914) + ); +} diff --git a/src/Type/Square/Aztec/Encode.php b/src/Type/Square/Aztec/Encode.php new file mode 100644 index 00000000..bf8de3bb --- /dev/null +++ b/src/Type/Square/Aztec/Encode.php @@ -0,0 +1,353 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Type\Square\Aztec\Data; +use Com\Tecnick\Barcode\Type\Square\Aztec\ErrorCorrection; +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\Encode + * + * Encode for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +class Encode extends \Com\Tecnick\Barcode\Type\Square\Aztec\Bitstream +{ + /** + * Bidimensional grid containing the encoded data. + * + * @var array + */ + protected $grid = array(); + + /** + * Coordinate of the grid center. + * + * @var int + */ + protected $gridcenter = 0; + + /** + * Aztec main encoder. + * + * @param string $code The code to encode. + * @param int $ecc The error correction code percentage of error check words. + * @param int $eci The ECI mode to use. + * @param string $hint The mode to use. + * @param string $mode The mode to use (A = Automatic; F = Full Range mode). + */ + public function __construct($code, $ecc = 33, $eci = 0, $hint = 'A', $mode = 'A') + { + $this->highLevelEncoding($code, $eci, $hint); + if (!$this->sizeAndBitStuffing($ecc, $mode)) { + throw new BarcodeException('Data too long'); + } + $wsize = $this->layer[2]; + $nbits = $this->layer[3]; + $numcdw = $this->addCheckWords($this->bitstream, $this->totbits, $nbits, $wsize); + $this->setGrid(); + $this->drawMode($numcdw); + $this->drawData(); + } + + /** + * Returns the bidimensional grid containing the encoded data. + * + * @return array + */ + public function getGrid() + { + return $this->grid; + } + + /** + * Returns the Check Codewords array for the given data words. + * + * @param array $bitstream Array of bits. + * @param int $totbits Number of bits in the bitstream. + * @param int $nbits Number of bits per layer. + * @param int $wsize Word size. + * + * @return int The number of data codewords. + */ + protected function addCheckWords(array &$bitstream, &$totbits, $nbits, $wsize) + { + $cdw = $this->bitstreamToWords($bitstream, $totbits, $wsize); + $numcdw = count($cdw); + $totwords = intval($nbits / $wsize); + $eccwords = ($totwords - $numcdw); + $ecc = new ErrorCorrection($wsize); + $checkwords = $ecc->checkwords($cdw, $eccwords); + // append check codewords + foreach ($checkwords as $val) { + $this->appendWordToBitstream($bitstream, $totbits, $wsize, $val); + } + return $numcdw; + } + + /** + * Initialize the grid with all patterns. + */ + protected function setGrid() + { + // initialize grid + $size = $this->layer[0]; + $row = array_fill(0, $size, 0); + $this->grid = array_fill(0, $size, $row); + // draw center + $center = intval(($size - 1) / 2); + $this->gridcenter = $center; + $this->grid[$center][$center] = 1; + // draw finder pattern (bulls-eye) + $bewidth = $this->compact ? 11 : 15; + $bemid = intval(($bewidth - 1) / 2); + for ($rng = 2; $rng < $bemid; $rng += 2) { + // center cross points + $this->grid[($center + $rng)][($center)] = 1; + $this->grid[($center - $rng)][($center)] = 1; + $this->grid[($center)][($center + $rng)] = 1; + $this->grid[($center)][($center - $rng)] = 1; + // corner points + $this->grid[($center + $rng)][($center + $rng)] = 1; + $this->grid[($center + $rng)][($center - $rng)] = 1; + $this->grid[($center - $rng)][($center + $rng)] = 1; + $this->grid[($center - $rng)][($center - $rng)] = 1; + for ($pos = 1; $pos < $rng; $pos++) { + // horizontal points + $this->grid[($center + $rng)][($center + $pos)] = 1; + $this->grid[($center + $rng)][($center - $pos)] = 1; + $this->grid[($center - $rng)][($center + $pos)] = 1; + $this->grid[($center - $rng)][($center - $pos)] = 1; + // vertical points + $this->grid[($center + $pos)][($center + $rng)] = 1; + $this->grid[($center + $pos)][($center - $rng)] = 1; + $this->grid[($center - $pos)][($center + $rng)] = 1; + $this->grid[($center - $pos)][($center - $rng)] = 1; + } + } + // draw orientation patterns + $this->grid[($center - $bemid)][($center - $bemid)] = 1; // TL + $this->grid[($center - $bemid)][($center - $bemid + 1)] = 1; // TL-R + $this->grid[($center - $bemid + 1)][($center - $bemid)] = 1; // TL-B + $this->grid[($center - $bemid)][($center + $bemid)] = 1; // TR-T + $this->grid[($center - $bemid + 1)][($center + $bemid)] = 1; // TR-B + $this->grid[($center + $bemid - 1)][($center + $bemid)] = 1; // BR + if ($this->compact) { + return; + } + // draw reference grid for full mode + $halfsize = intval(($size - 1) / 2); + // central cross + for ($pos = 8; $pos <= $halfsize; $pos += 2) { + // horizontal + $this->grid[($center)][($center - $pos)] = 1; + $this->grid[($center)][($center + $pos)] = 1; + // vertical + $this->grid[($center - $pos)][($center)] = 1; + $this->grid[($center + $pos)][($center)] = 1; + } + // grid lines + for ($pos = 2; $pos <= $halfsize; $pos += 2) { + for ($ref = 16; $ref <= $halfsize; $ref += 16) { + // horizontal + $this->grid[($center - $ref)][($center - $pos)] = 1; + $this->grid[($center - $ref)][($center + $pos)] = 1; + $this->grid[($center + $ref)][($center - $pos)] = 1; + $this->grid[($center + $ref)][($center + $pos)] = 1; + // vertical + $this->grid[($center - $pos)][($center - $ref)] = 1; + $this->grid[($center - $pos)][($center + $ref)] = 1; + $this->grid[($center + $pos)][($center - $ref)] = 1; + $this->grid[($center + $pos)][($center + $ref)] = 1; + } + } + } + + /** + * Add the mode message to the grid. + * + * @param int $numcdw Number of data codewords. + * + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + protected function drawMode($numcdw) + { + $modebs = array(); + $nbits = 0; + $center = $this->gridcenter; + $modebits = 40; + $layersbits = 5; + $codewordsbits = 11; + $sidelen = 10; + $srow = -7; + $scol = -5; + if ($this->compact) { + $modebits = 28; + $layersbits = 2; + $codewordsbits = 6; + $sidelen = 7; + $srow = -5; + $scol = -3; + } + $this->appendWordToBitstream($modebs, $nbits, $layersbits, ($this->numlayers - 1)); + $this->appendWordToBitstream($modebs, $nbits, $codewordsbits, ($numcdw - 1)); + $this->addCheckWords($modebs, $nbits, $modebits, 4); + // draw the mode message in the grid clockwise starting from the top left corner + $bit = 0; + // top + $ypos = ($center + $srow); + $xpos = ($center + $scol); + for ($pos = 0; $pos < $sidelen; $pos++) { + $xpos += $this->skipModeRefGrid($pos); + $this->grid[$ypos][$xpos] = (empty($modebs[$bit++]) ? 0 : 1); + $xpos++; + } + // right + $ypos += 2; + $xpos++; + for ($pos = 0; $pos < $sidelen; $pos++) { + $ypos += $this->skipModeRefGrid($pos); + $this->grid[$ypos][$xpos] = (empty($modebs[$bit++]) ? 0 : 1); + $ypos++; + } + // bottom + $ypos++; + $xpos -= 2; + for ($pos = 0; $pos < $sidelen; $pos++) { + $xpos -= $this->skipModeRefGrid($pos); + $this->grid[$ypos][$xpos] = (empty($modebs[$bit++]) ? 0 : 1); + $xpos--; + } + // left + $ypos -= 2; + $xpos--; + for ($pos = 0; $pos < $sidelen; $pos++) { + $ypos -= $this->skipModeRefGrid($pos); + $this->grid[$ypos][$xpos] = (empty($modebs[$bit++]) ? 0 : 1); + $ypos--; + } + } + + /** + * Returns a bit from the end of the bitstream and update the index. + * + * @param int $bit Index of the bit to pop. + * + * @return int + */ + protected function popBit(&$bit) + { + return (empty($this->bitstream[$bit--]) ? 0 : 1); + } + + + /** + * Returns 1 if the current position must be skipped in Full mode. + * + * @param int $pos Position in the grid. + * + * @return int + */ + protected function skipModeRefGrid($pos) + { + return intval((!$this->compact) && ($pos == 5)); + } + + + /** + * Returns the offset for the specified position to skip the reference grid. + * + * @param int $pos Position in the grid. + * + * @return int + */ + protected function skipRefGrid($pos) + { + return intval((!$this->compact) && (($pos % 16) == 0)); + } + + /** + * Draw the data bitstream in the grid in Full mode. + */ + protected function drawData() + { + $center = $this->gridcenter; + $llen = 16; // width of the first layer side + $srow = -8; // start top row offset from the center (LSB) + $scol = -7; // start top column offset from the center (LSB) + if ($this->compact) { + $llen = 13; + $srow = -6; + $scol = -5; + } + $skip = 0; // skip reference grid while drwaing dominoes + $bit = ($this->totbits - 1); // index of last bitstream bit (first to draw) + for ($layer = 0; $layer < $this->numlayers; $layer++) { + // top + $ypos = ($center + $srow); + $xpos = ($center + $scol); + for ($pos = 0; $pos < $llen; $pos++) { + $xpos += $this->skipRefGrid($xpos - $center); // skip reference grid + $this->grid[$ypos][$xpos] = $this->popBit($bit); + $this->grid[($ypos - 1 - $skip)][$xpos] = $this->popBit($bit); + $xpos++; + } + // right + $ypos++; + $xpos -= (2 + $skip); + for ($pos = 0; $pos < $llen; $pos++) { + $ypos += $this->skipRefGrid($ypos - $center); // skip reference grid + $this->grid[$ypos][$xpos] = $this->popBit($bit); + $this->grid[$ypos][($xpos + 1 + $skip)] = $this->popBit($bit); + $ypos++; + } + // bottom + $ypos -= (2 + $skip); + $xpos--; + for ($pos = 0; $pos < $llen; $pos++) { + $xpos -= $this->skipRefGrid($xpos - $center); // skip reference grid + $this->grid[$ypos][$xpos] = $this->popBit($bit); + $this->grid[($ypos + 1 + $skip)][$xpos] = $this->popBit($bit); + $xpos--; + } + // left + $ypos--; + $xpos += (2 + $skip); + for ($pos = 0; $pos < $llen; $pos++) { + $ypos -= $this->skipRefGrid($ypos - $center); // skip reference grid + $this->grid[$ypos][$xpos] = $this->popBit($bit); + $this->grid[$ypos][($xpos - 1 - $skip)] = $this->popBit($bit); + $ypos--; + } + $llen += 4; + $srow = ($ypos - $center); + $srow -= $this->skipRefGrid($srow); + $scol = ($xpos - 1 - $center); + $scol -= $this->skipRefGrid($scol); + $skip = $this->skipRefGrid($srow - 1); + } + } +} diff --git a/src/Type/Square/Aztec/ErrorCorrection.php b/src/Type/Square/Aztec/ErrorCorrection.php new file mode 100644 index 00000000..73566c23 --- /dev/null +++ b/src/Type/Square/Aztec/ErrorCorrection.php @@ -0,0 +1,254 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\ErrorCorrection + * + * ErrorCorrection for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +class ErrorCorrection +{ + /** + * Galois Field primitive by word size. + */ + const GF = array( + 4 => 19, // 10011 GF(16) (x^4 + x + 1) Mode message + 6 => 67, // 1000011 GF(64) (x^6 + x + 1) 01–02 layers + 8 => 301, // 100101101 GF(256) (x^8 + x^5 + x^3 + x^2 + 1) 03–08 layers + 10 => 1033, // 10000001001 GF(1024) (x^10 + x^3 + 1) 09–22 layers + 12 => 4201 // 1000001101001 GF(4096) (x^12 + x^6 + x^5 + x^3 + 1) 23–32 layers + ); + + /** + * Map the log and exp (inverse log) tables by word size. + * NOTE: It is equal to 2^word_size. + */ + const TSIZE = array( + 4 => 16, + 6 => 64, + 8 => 256, + 10 => 1024, + 12 => 4096 + ); + + /** + * Log table. + */ + protected $tlog = array(); + + /** + * Exponential (inverse log) table. + */ + protected $texp = array(); + + /** + * Size of the log and exp tables. + */ + protected $tsize = 0; + + /** + * Initialize the the Reed-Solomon Error Correction. + * + * @param int $wsize Size of a word in bits. + */ + public function __construct($wsize) + { + $this->genTables($wsize); + } + + /** + * Returns the Reed-Solomon Error Correction Codewords added to the input data. + * + * @param array $data Array of data codewords to process. + * @param int $necc Number of error correction bytes. + * + * @return array + */ + public function checkwords(array $data, $necc) + { + $coeff = $this->getCoefficients($data, $necc); + return array_pad($coeff, -$necc, 0); + } + + /** + * Generates log and exp (inverse log) tables. + * + * @param int $wsize Size of the word in bits. + */ + protected function genTables($wsize) + { + $this->tsize = self::TSIZE[$wsize]; + $this->tlog = array_fill(0, $this->tsize, 0); + $this->texp = $this->tlog; + $primitive = self::GF[$wsize]; + $val = 1; + $sizeminusone = ($this->tsize - 1); + for ($idx = 0; $idx < $this->tsize; $idx++) { + $this->texp[$idx] = $val; + $val <<= 1; // multiply by 2 + if ($val >= $this->tsize) { + $val ^= $primitive; + $val &= $sizeminusone; + } + } + for ($idx = 0; $idx < $this->tsize - 1; $idx++) { + $this->tlog[$this->texp[$idx]] = $idx; + } + } + + /** + * Calculates the coefficients of the error correction polynomial. + * + * @param array $data Array of data codewords to process. + * @param int $necc Number of error correction bytes. + * + * @return array Array of coefficients. + */ + protected function getCoefficients(array $data, $necc) + { + $gen = array(1); + for ($idx = 1; $idx <= $necc; $idx++) { + $gen = $this->multiplyCoeff(array(1, $this->texp[$idx]), $gen); + } + $deg = ($necc + 1); + $coeff = $this->multiplyByMonomial($data, 1, $necc); + $len = count($coeff); + while (($len >= $deg) && ($coeff[0] != 0)) { + $scale = $this->multiply($coeff[0], 1); + $largercoeffs = $this->multiplyByMonomial($gen, $scale, ($len - $deg)); + $coeff = $this->addOrSubtract($coeff, $largercoeffs); + $len = count($coeff); + } + return $coeff; + } + + /** + * Returns the product of two coefficient arrays. + * + * @param array $acf First array of coefficients. + * @param array $bcf Second array of coefficients. + * + * @return array + */ + protected function multiplyCoeff(array $acf, array $bcf) + { + $alen = count($acf); + $blen = count($bcf); + $coeff = array_fill(0, ($alen + $blen - 1), 0); + for ($aid = 0; $aid < $alen; $aid++) { + for ($bid = 0; $bid < $blen; $bid++) { + $coeff[$aid + $bid] ^= ($this->multiply($acf[$aid], $bcf[$bid])); + } + } + return $this->trimCoefficients($coeff); + } + + /** + * Returns the product of $aval and $bval in GF(size). + * + * @param int $aval First value. + * @param int $bval Second value. + * + * @return int + */ + protected function multiply($aval, $bval) + { + if ($aval == 0 || $bval == 0) { + return 0; + } + return $this->texp[($this->tlog[$aval] + $this->tlog[$bval]) % ($this->tsize - 1)]; + } + + /** + * Left-trim coefficients array. + * + * @param array $coeff Array of coefficients. + * + * @return array + */ + protected function trimCoefficients($coeff) + { + while (!empty($coeff) && $coeff[0] == 0) { + array_shift($coeff); + } + return $coeff; + } + + /** + * Returns the product of a polynomial by a monomial. + * + * @param array $coeff Array of polynomial coefficients. + * @param int $mon Monomial. + * @param int $deg Degree of the monomial. + * + * @return array + */ + protected function multiplyByMonomial(array $coeff, $mon, $deg) + { + // if ($mon == 0) { + // return array(0); + // } + $ncf = count($coeff); + $prod = array_fill(0, ($ncf + $deg), 0); + for ($idx = 0; $idx < $ncf; $idx++) { + $prod[$idx] = $this->multiply($coeff[$idx], $mon); + } + return $this->trimCoefficients($prod); + } + + /** + * Adds or subtracts two coefficient arrays. + * + * @param array $smaller The smaller array of coefficients. + * @param array $larger The larger array of coefficients. + * + * @return array + */ + protected function addOrSubtract(array $smaller, array $larger) + { + // if ($smaller[0] == 0) { + // return $larger; + // } + // if ($larger[0] == 0) { + // return $smaller; + // } + $slen = count($smaller); + $llen = count($larger); + // if ($slen > $llen) { + // // swap arrays + // list($smaller, $larger) = array($larger, $smaller); + // list($slen, $llen) = array($llen, $slen); + // } + $lendiff = ($llen - $slen); + $coeff = array_slice($larger, 0, $lendiff); + for ($idx = $lendiff; $idx < $llen; $idx++) { + $coeff[$idx] = ($smaller[($idx - $lendiff)] ^ $larger[$idx]); + } + return $this->trimCoefficients($coeff); + } +} diff --git a/src/Type/Square/Aztec/Layers.php b/src/Type/Square/Aztec/Layers.php new file mode 100644 index 00000000..3330cb28 --- /dev/null +++ b/src/Type/Square/Aztec/Layers.php @@ -0,0 +1,162 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Com\Tecnick\Barcode\Type\Square\Aztec; + +use Com\Tecnick\Barcode\Type\Square\Aztec\Data; +use Com\Tecnick\Barcode\Exception as BarcodeException; + +/** + * Com\Tecnick\Barcode\Type\Square\Aztec\Layers + * + * Layers for Aztec Barcode type class + * + * @since 2023-10-13 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +abstract class Layers extends \Com\Tecnick\Barcode\Type\Square\Aztec\Codeword +{ + /** + * True for compact mode (up to 4 layers), false for full-range mode (up to 32 layers). + * + * @var bool + */ + protected $compact = true; + + /** + * Number of data layers. + * + * @var int + */ + protected $numlayers = 0; + + /** + * Size data for the selected layer. + * + * @var array + */ + protected $layer = array(); + + /** + * Returns the minimum number of layers required. + * + * @param array $data Either the Data::SIZE_COMPACT or Data::SIZE_FULL array. + * @param int $numbits The number of bits to encode. + * + * @return int + */ + protected function getMinLayers($data, $numbits) + { + if ($numbits <= $data[count($data)][3]) { + foreach ($data as $numlayers => $size) { + if ($numbits <= $size[3]) { + return $numlayers; + } + } + } + return 0; + } + + /** + * Select the layer by the number of bits to encode. + * + * @param int $numbits The number of bits to encode. + * @param string $mode The mode to use (A = Automatic; F = Full Range mode). + * + * @return bool Returns true if the size computation was successful, false otherwise. + */ + protected function setLayerByBits($numbits, $mode = 'A') + { + $this->numlayers = 0; + if ($mode == 'A') { + $this->compact = true; + $this->numlayers = $this->getMinLayers(Data::SIZE_COMPACT, $numbits); + } + if ($this->numlayers == 0) { + $this->compact = false; + $this->numlayers = $this->getMinLayers(Data::SIZE_FULL, $numbits); + } + if ($this->numlayers == 0) { + return false; + } + $this->layer = $this->compact ? Data::SIZE_COMPACT[$this->numlayers] : Data::SIZE_FULL[$this->numlayers]; + return true; + } + + /** + * Computes the type and number of required layers and performs bit stuffing + * + * @param int $ecc The error correction level. + * @param string $mode The mode to use (A = Automatic; F = Full Range mode). + * + * @return bool Returns true if the size computation was successful, false otherwise. + */ + protected function sizeAndBitStuffing($ecc, $mode = 'A') + { + $nsbits = 0; + $eccbits = (11 + intval(($this->totbits * $ecc) / 100)); + do { + if (!$this->setLayerByBits(($this->totbits + $nsbits + $eccbits), $mode)) { + return false; + } + $nsbits = $this->bitStuffing(); + } while (($nsbits + $eccbits) > $this->layer[3]); + $this->bitstream = array(); + $this->totbits = 0; + $this->mergeTmpCwdRaw(); + return true; + } + + /** + * Bit-stuffing the bitstream into Reed–Solomon codewords. + * The resulting codewords are stored in the temporary tmpCdws array. + * + * @return int The number of bits in the bitstream after bit stuffing. + */ + protected function bitStuffing() + { + $nsbits = 0; + $wsize = $this->layer[2]; + $mask = ((1 << $wsize) - 2); // b-1 bits at 1 and last bit at 0 + $this->tmpCdws = array(); + for ($wid = 0; $wid < $this->totbits; $wid += $wsize) { + $word = 0; + for ($idx = 0; $idx < $wsize; $idx++) { + $bid = ($wid + $idx); + if (($bid >= $this->totbits) || ($this->bitstream[$bid] == 1)) { + $word |= (1 << ($wsize - 1 - $idx)); // the first bit is MSB + } + } + // If the first b−1 bits of a code word have the same value, + // an extra bit with the complementary value is inserted into the data stream. + if (($word & $mask) == $mask) { + $word &= $mask; + $wid--; + } elseif (($word & $mask) == 0) { + $word |= 1; + $wid--; + } + $this->tmpCdws[] = array($wsize, $word); + $nsbits += $wsize; + } + return $nsbits; + } +} diff --git a/src/Type/Square/Datamatrix.php b/src/Type/Square/Datamatrix.php index 4855136e..7fc8897e 100644 --- a/src/Type/Square/Datamatrix.php +++ b/src/Type/Square/Datamatrix.php @@ -86,10 +86,12 @@ class Datamatrix extends \Com\Tecnick\Barcode\Type\Square protected function setParameters() { parent::setParameters(); + // shape if (isset($this->params[0]) && ($this->params[0] == 'R')) { $this->shape = 'R'; } + // mode if (isset($this->params[1]) && ($this->params[1] == 'GS1')) { $this->gsonemode = true; diff --git a/src/Type/Square/Datamatrix/Data.php b/src/Type/Square/Datamatrix/Data.php index 6228278a..9169117d 100644 --- a/src/Type/Square/Datamatrix/Data.php +++ b/src/Type/Square/Datamatrix/Data.php @@ -93,10 +93,8 @@ class Data *
  • data codewords per block
  • *
  • error codewords per block
  • * - * - * @var array */ - public static $symbattr = array( + const SYMBATTR = array( 'S' => array( // square form // 10x10 array( @@ -675,10 +673,8 @@ class Data /** * Map encodation modes whit character sets. - * - * @var array */ - public static $chset_id = array( + const CHSET_ID = array( self::ENC_C40 => 'C40', self::ENC_TXT => 'TXT', self::ENC_X12 => 'X12' @@ -686,10 +682,8 @@ class Data /** * Basic set of characters for each encodation mode. - * - * @var array */ - public static $chset = array( + const CHSET = array( 'C40' => array( // Basic set for C40 'S1' => 0x00, 'S2' => 0x01, @@ -960,7 +954,7 @@ class Data */ public static function getPaddingSize($shape, $ncw) { - foreach (Data::$symbattr[$shape] as $params) { + foreach (Data::SYMBATTR[$shape] as $params) { if ($params[11] >= $ncw) { return $params; } diff --git a/src/Type/Square/Datamatrix/EncodeTxt.php b/src/Type/Square/Datamatrix/EncodeTxt.php index b4f05549..af3852eb 100644 --- a/src/Type/Square/Datamatrix/EncodeTxt.php +++ b/src/Type/Square/Datamatrix/EncodeTxt.php @@ -45,18 +45,18 @@ class EncodeTxt extends \Com\Tecnick\Barcode\Type\Square\Datamatrix\Steps */ public function encodeTXTC40shift(&$chr, &$enc, &$temp_cw, &$ptr) { - if (isset(Data::$chset['SH1'][$chr])) { + if (array_key_exists($chr, Data::CHSET['SH1'])) { $temp_cw[] = 0; // shift 1 - $shiftset = Data::$chset['SH1']; - } elseif (isset($chr, Data::$chset['SH2'][$chr])) { + $shiftset = Data::CHSET['SH1']; + } elseif (array_key_exists($chr, Data::CHSET['SH2'])) { $temp_cw[] = 1; // shift 2 - $shiftset = Data::$chset['SH2']; - } elseif (($enc == Data::ENC_C40) && isset(Data::$chset['S3C'][$chr])) { + $shiftset = Data::CHSET['SH2']; + } elseif (($enc == Data::ENC_C40) && array_key_exists($chr, Data::CHSET['S3C'])) { $temp_cw[] = 2; // shift 3 - $shiftset = Data::$chset['S3C']; - } elseif (($enc == Data::ENC_TXT) && isset(Data::$chset['S3T'][$chr])) { + $shiftset = Data::CHSET['S3C']; + } elseif (($enc == Data::ENC_TXT) && array_key_exists($chr, Data::CHSET['S3T'])) { $temp_cw[] = 2; // shift 3 - $shiftset = Data::$chset['S3T']; + $shiftset = Data::CHSET['S3T']; } else { throw new BarcodeException('Error'); } @@ -171,9 +171,9 @@ public function encodeTXT(&$cdw, &$cdw_num, &$pos, &$data_length, &$data, &$enc) $ptr = 0; $epos = $pos; // get charset ID - $set_id = Data::$chset_id[$enc]; + $set_id = Data::CHSET_ID[$enc]; // get basic charset for current encoding - $charset = Data::$chset[$set_id]; + $charset = Data::CHSET[$set_id]; do { $chr = $this->encodeTXTC40($data, $enc, $temp_cw, $ptr, $epos, $charset); if ($ptr >= 3) { diff --git a/src/Type/Square/Datamatrix/Modes.php b/src/Type/Square/Datamatrix/Modes.php index 925696b8..a560aa39 100644 --- a/src/Type/Square/Datamatrix/Modes.php +++ b/src/Type/Square/Datamatrix/Modes.php @@ -211,7 +211,7 @@ protected function isASCIINUMMode($chr) protected function getMaxDataCodewords($numcw) { $mdc = 0; - foreach (Data::$symbattr[$this->shape] as $matrix) { + foreach (Data::SYMBATTR[$this->shape] as $matrix) { if ($matrix[11] >= $numcw) { $mdc = $matrix[11]; break; diff --git a/src/Type/Square/PdfFourOneSeven.php b/src/Type/Square/PdfFourOneSeven.php index 7507748e..2749ed93 100644 --- a/src/Type/Square/PdfFourOneSeven.php +++ b/src/Type/Square/PdfFourOneSeven.php @@ -103,14 +103,17 @@ class PdfFourOneSeven extends \Com\Tecnick\Barcode\Type\Square\PdfFourOneSeven\C protected function setParameters() { parent::setParameters(); + // aspect ratio if (!empty($this->params[0]) && (($aspectratio = floatval($this->params[0])) >= 1)) { $this->aspectratio = $aspectratio; } + // error correction level (auto) if (isset($this->params[1]) && (($ecl = intval($this->params[1])) >= 0) && ($ecl <= 8)) { $this->ecl = $ecl; } + // macro block $this->setMacroBlockParam(); } @@ -283,7 +286,7 @@ public function getBinSequence() $codewords = $this->getCodewords($rows, $cols, $ecl); $barcode = ''; // add horizontal quiet zones to start and stop patterns - $pstart = str_repeat('0', $this->quiet_horizontal) . Data::$start_pattern; + $pstart = str_repeat('0', $this->quiet_horizontal) . Data::START_PATTERN; $this->nrows = ($rows * $this->row_height) + (2 * $this->quiet_vertical); $this->ncols = (($cols + 2) * 17) + 35 + (2 * $this->quiet_horizontal); // build rows for vertical quiet zone @@ -312,16 +315,16 @@ public function getBinSequence() break; } // left row indicator - $row .= sprintf('%17b', Data::$clusters[$cid][$rval]); + $row .= sprintf('%17b', Data::CLUSTERS[$cid][$rval]); // for each column for ($cix = 0; $cix < $cols; ++$cix) { - $row .= sprintf('%17b', Data::$clusters[$cid][$codewords[$kcw]]); + $row .= sprintf('%17b', Data::CLUSTERS[$cid][$codewords[$kcw]]); ++$kcw; } // right row indicator - $row .= sprintf('%17b', Data::$clusters[$cid][$cval]); + $row .= sprintf('%17b', Data::CLUSTERS[$cid][$cval]); // row stop code - $row .= Data::$stop_pattern . str_repeat('0', $this->quiet_horizontal); + $row .= Data::STOP_PATTERN . str_repeat('0', $this->quiet_horizontal); $brow = ',' . str_repeat($row, $this->row_height); $barcode .= $brow; ++$cid; diff --git a/src/Type/Square/PdfFourOneSeven/Compaction.php b/src/Type/Square/PdfFourOneSeven/Compaction.php index fb656b20..27fe8d3d 100644 --- a/src/Type/Square/PdfFourOneSeven/Compaction.php +++ b/src/Type/Square/PdfFourOneSeven/Compaction.php @@ -50,7 +50,7 @@ protected function processTextCompactionSub(&$txtarr, &$submode, $sub, $code, $k // $sub is the new submode if ( ((($idx + 1) == $codelen) || ((($idx + 1) < $codelen) - && (array_search(ord($code[($idx + 1)]), Data::$textsubmodes[$submode]) !== false))) + && (array_search(ord($code[($idx + 1)]), Data::TEXT_SUB_MODES[$submode]) !== false))) && (($sub == 3) || (($sub == 0) && ($submode == 1))) ) { // shift (temporary change only for this char) @@ -63,7 +63,7 @@ protected function processTextCompactionSub(&$txtarr, &$submode, $sub, $code, $k } } else { // latch - $txtarr = array_merge($txtarr, Data::$textlatch['' . $submode . $sub]); + $txtarr = array_merge($txtarr, Data::TEXT_LATCH['' . $submode . $sub]); // set new submode $submode = $sub; } @@ -84,14 +84,14 @@ protected function processTextCompaction($code, &$codewords) $codelen = strlen($code); for ($idx = 0; $idx < $codelen; ++$idx) { $chval = ord($code[$idx]); - if (($key = array_search($chval, Data::$textsubmodes[$submode])) !== false) { + if (($key = array_search($chval, Data::TEXT_SUB_MODES[$submode])) !== false) { // we are on the same sub-mode $txtarr[] = $key; } else { // the sub-mode is changed for ($sub = 0; $sub < 4; ++$sub) { // search new sub-mode - if (($sub != $submode) && (($key = array_search($chval, Data::$textsubmodes[$sub])) !== false)) { + if (($sub != $submode) && (($key = array_search($chval, Data::TEXT_SUB_MODES[$sub])) !== false)) { $this->processTextCompactionSub($txtarr, $submode, $sub, $code, $key, $idx, $codelen); break; } diff --git a/src/Type/Square/PdfFourOneSeven/Data.php b/src/Type/Square/PdfFourOneSeven/Data.php index 6feb8305..0068118c 100644 --- a/src/Type/Square/PdfFourOneSeven/Data.php +++ b/src/Type/Square/PdfFourOneSeven/Data.php @@ -33,24 +33,18 @@ abstract class Data { /** * Start pattern - * - * @var string */ - public static $start_pattern = '11111111010101000'; + const START_PATTERN = '11111111010101000'; /** * Stop pattern - * - * @var string */ - public static $stop_pattern = '111111101000101001'; + const STOP_PATTERN = '111111101000101001'; /** * Array of text Compaction Sub-Modes (values 0xFB - 0xFF are used for submode changers) - * - * @var array */ - public static $textsubmodes = array( + const TEXT_SUB_MODES = array( array( // Alpha 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a, 0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54, @@ -75,10 +69,8 @@ abstract class Data /** * Array of switching codes for Text Compaction Sub-Modes - * - * @var array */ - public static $textlatch = array( + const TEXT_LATCH = array( '01' => array(27), '02' => array(28), '03' => array(28,25), @@ -113,10 +105,8 @@ abstract class Data * 926 : Identifier for a general purpose ECI format * 927 : Identifier for an ECI of a character set or code page * 928 : Macro marker codeword to indicate the beginning of a Macro PDF Control Block - * - * @var array */ - public static $clusters = array( + const CLUSTERS = array( array( // cluster 0 ----------------------------------------------------------------------- 0x1d5c0,0x1eaf0,0x1f57c,0x1d4e0,0x1ea78,0x1f53e,0x1a8c0,0x1d470,0x1a860,0x15040, // 10 0x1a830,0x15020,0x1adc0,0x1d6f0,0x1eb7c,0x1ace0,0x1d678,0x1eb3e,0x158c0,0x1ac70, // 20 @@ -407,10 +397,8 @@ abstract class Data /** * Array of factors of the Reed-Solomon polynomial equations used for error correction; * One sub array for each correction level (0-8). - * - * @var array */ - public static $rsfactors = array( + const RS_FACTORS = array( array( // ECL 0 (2 factors) ------------------------------------------------------------------------------- 0x01b,0x395 // 2 ), diff --git a/src/Type/Square/PdfFourOneSeven/Sequence.php b/src/Type/Square/PdfFourOneSeven/Sequence.php index 37929c72..36f514f5 100644 --- a/src/Type/Square/PdfFourOneSeven/Sequence.php +++ b/src/Type/Square/PdfFourOneSeven/Sequence.php @@ -76,10 +76,10 @@ protected function getErrorCorrectionLevel($ecl, $numcw) protected function getErrorCorrection($codewords, $ecl) { // get error correction coefficients - $ecc = Data::$rsfactors[$ecl]; + $ecc = Data::RS_FACTORS[$ecl]; // number of error correction factors $eclsize = (2 << $ecl); - // maximum index for $rsfactors[$ecl] + // maximum index for RS_FACTORS[$ecl] $eclmaxid = ($eclsize - 1); // initialize array of error correction codewords $ecw = array_fill(0, $eclsize, 0); diff --git a/src/Type/Square/QrCode.php b/src/Type/Square/QrCode.php index 0e7da948..60b08175 100644 --- a/src/Type/Square/QrCode.php +++ b/src/Type/Square/QrCode.php @@ -121,17 +121,18 @@ class QrCode extends \Com\Tecnick\Barcode\Type\Square protected function setParameters() { parent::setParameters(); + // level - if (!isset($this->params[0]) || !isset(Data::$errCorrLevels[$this->params[0]])) { + if (!isset($this->params[0]) || !array_key_exists($this->params[0], Data::ECC_LEVELS)) { $this->params[0] = 'L'; } - $this->level = Data::$errCorrLevels[$this->params[0]]; + $this->level = Data::ECC_LEVELS[$this->params[0]]; // hint - if (!isset($this->params[1]) || !isset(Data::$encodingModes[$this->params[1]])) { + if (!isset($this->params[1]) || !array_key_exists($this->params[1], Data::ENC_MODES)) { $this->params[1] = '8B'; } - $this->hint = Data::$encodingModes[$this->params[1]]; + $this->hint = Data::ENC_MODES[$this->params[1]]; // version if (!isset($this->params[2]) || ($this->params[2] < 0) || ($this->params[2] > Data::QRSPEC_VERSION_MAX)) { @@ -238,7 +239,7 @@ protected function toUpper($data) while ($pos < $len) { $mode = $this->bsObj->getEncodingMode($data, $pos); - if ($mode == Data::$encodingModes['KJ']) { + if ($mode == Data::ENC_MODES['KJ']) { $pos += 2; } else { if ((ord($data[$pos]) >= ord('a')) && (ord($data[$pos]) <= ord('z'))) { diff --git a/src/Type/Square/QrCode/ByteStream.php b/src/Type/Square/QrCode/ByteStream.php index e7f1b862..3387404c 100644 --- a/src/Type/Square/QrCode/ByteStream.php +++ b/src/Type/Square/QrCode/ByteStream.php @@ -193,19 +193,19 @@ public function encodeBitStream($inputitem, $version) $inputitem['bstream'] = $this->appendBitstream($inputitem['bstream'], $st2['bstream']); } else { switch ($inputitem['mode']) { - case Data::$encodingModes['NM']: + case Data::ENC_MODES['NM']: $inputitem = $this->encodeModeNum($inputitem, $version); break; - case Data::$encodingModes['AN']: + case Data::ENC_MODES['AN']: $inputitem = $this->encodeModeAn($inputitem, $version); break; - case Data::$encodingModes['8B']: + case Data::ENC_MODES['8B']: $inputitem = $this->encodeMode8($inputitem, $version); break; - case Data::$encodingModes['KJ']: + case Data::ENC_MODES['KJ']: $inputitem = $this->encodeModeKanji($inputitem, $version); break; - case Data::$encodingModes['ST']: + case Data::ENC_MODES['ST']: $inputitem = $this->encodeModeStructure($inputitem); break; } diff --git a/src/Type/Square/QrCode/Data.php b/src/Type/Square/QrCode/Data.php index f92eb2d3..c159b9cb 100644 --- a/src/Type/Square/QrCode/Data.php +++ b/src/Type/Square/QrCode/Data.php @@ -46,22 +46,22 @@ class Data // ----------------------------------------------------- /** - * Matrix index to get width from $capacity array. + * Matrix index to get width from CAPACITY array. */ const QRCAP_WIDTH = 0; /** - * Matrix index to get number of words from $capacity array. + * Matrix index to get number of words from CAPACITY array. */ const QRCAP_WORDS = 1; /** - * Matrix index to get remainder from $capacity array. + * Matrix index to get remainder from CAPACITY array. */ const QRCAP_REMINDER = 2; /** - * Matrix index to get error correction level from $capacity array. + * Matrix index to get error correction level from CAPACITY array. */ const QRCAP_EC = 3; @@ -113,10 +113,8 @@ class Data * 8B : Encoding mode 8bit byte data. In theory, 2953 characters or less can be stored in a QRcode. * KJ : Encoding mode KANJI. A KANJI character (multibyte character) is encoded to 13bit length. * ST : Encoding mode STRUCTURED - * - * @var array */ - public static $encodingModes = array('NL' => -1, 'NM' => 0, 'AN' => 1, '8B' => 2, 'KJ' => 3, 'ST' => 4); + const ENC_MODES = array('NL' => -1, 'NM' => 0, 'AN' => 1, '8B' => 2, 'KJ' => 3, 'ST' => 4); /** * Array of valid error correction levels @@ -126,17 +124,13 @@ class Data * M : About 15% or less errors can be corrected. * Q : About 25% or less errors can be corrected. * H : About 30% or less errors can be corrected. - * - * @var array */ - public static $errCorrLevels = array('L' => 0, 'M' => 1, 'Q' => 2, 'H' => 3); + const ECC_LEVELS = array('L' => 0, 'M' => 1, 'Q' => 2, 'H' => 3); /** * Alphabet-numeric conversion table. - * - * @var array */ - public static $anTable = array( + const AN_TABLE = array( -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // @@ -150,10 +144,8 @@ class Data /** * Array Table of the capacity of symbols. * See Table 1 (pp.13) and Table 12-16 (pp.30-36), JIS X0510:2004. - * - * @var array */ - public static $capacity = array( + const CAPACITY = array( array( 0, 0, 0, array( 0, 0, 0, 0)), // array( 21, 26, 0, array( 7, 10, 13, 17)), // 1 array( 25, 44, 7, array( 10, 16, 22, 28)), // @@ -199,10 +191,8 @@ class Data /** * Array Length indicator. - * - * @var array */ - public static $lengthTableBits = array( + const LEN_TABLE_BITS = array( array(10, 12, 14), array( 9, 11, 13), array( 8, 16, 16), @@ -212,10 +202,8 @@ class Data /** * Array Table of the error correction code (Reed-Solomon block). * See Table 12-16 (pp.30-36), JIS X0510:2004. - * - * @var array */ - public static $eccTable = array( + const ECC_TABLE = array( array(array( 0, 0), array( 0, 0), array( 0, 0), array( 0, 0)), // array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // 1 array(array( 1, 0), array( 1, 0), array( 1, 0), array( 1, 0)), // @@ -264,10 +252,8 @@ class Data * This array includes only the second and the third position of the alignment patterns. * Rest of them can be calculated from the distance between them. * See Table 1 in Appendix E (pp.71) of JIS X0510:2004. - * - * @var array */ - public static $alignmentPattern = array( + const ALIGN_PATTERN = array( array( 0, 0), array( 0, 0), array(18, 0), array(22, 0), array(26, 0), array(30, 0), // 1- 5 array(34, 0), array(22, 38), array(24, 42), array(26, 46), array(28, 50), // 6-10 @@ -283,10 +269,8 @@ class Data * Array Version information pattern (BCH coded). * See Table 1 in Appendix D (pp.68) of JIS X0510:2004. * size: [QRSPEC_VERSION_MAX - 6] - * - * @var array */ - public static $versionPattern = array( + const VERSION_PATTERN = array( 0x07c94, 0x085bc, 0x09a99, 0x0a4d3, 0x0bbf6, 0x0c762, 0x0d847, 0x0e60d, // 0x0f928, 0x10b78, 0x1145d, 0x12a17, 0x13532, 0x149a6, 0x15683, 0x168c9, // 0x177ec, 0x18ec4, 0x191e1, 0x1afab, 0x1b08e, 0x1cc1a, 0x1d33f, 0x1ed75, // @@ -296,10 +280,8 @@ class Data /** * Array Format information - * - * @var array */ - public static $formatInfo = array( + const FORMAT_INFO = array( array(0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976), // array(0x5412, 0x5125, 0x5e7c, 0x5b4b, 0x45f9, 0x40ce, 0x4f97, 0x4aa0), // array(0x355f, 0x3068, 0x3f31, 0x3a06, 0x24b4, 0x2183, 0x2eda, 0x2bed), // diff --git a/src/Type/Square/QrCode/Encode.php b/src/Type/Square/QrCode/Encode.php index 8b2dc106..3efa96fb 100644 --- a/src/Type/Square/QrCode/Encode.php +++ b/src/Type/Square/QrCode/Encode.php @@ -48,7 +48,7 @@ protected function encodeModeNum($inputitem, $version) $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, $val); $inputitem['bstream'] = $this->appendNum( $inputitem['bstream'], - $this->getLengthIndicator(Data::$encodingModes['NM'], $version), + $this->getLengthIndicator(Data::ENC_MODES['NM'], $version), $inputitem['size'] ); for ($i = 0; $i < $words; ++$i) { @@ -83,7 +83,7 @@ protected function encodeModeAn($inputitem, $version) $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x02); $inputitem['bstream'] = $this->appendNum( $inputitem['bstream'], - $this->getLengthIndicator(Data::$encodingModes['AN'], $version), + $this->getLengthIndicator(Data::ENC_MODES['AN'], $version), $inputitem['size'] ); for ($idx = 0; $idx < $words; ++$idx) { @@ -112,7 +112,7 @@ protected function encodeMode8($inputitem, $version) $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x4); $inputitem['bstream'] = $this->appendNum( $inputitem['bstream'], - $this->getLengthIndicator(Data::$encodingModes['8B'], $version), + $this->getLengthIndicator(Data::ENC_MODES['8B'], $version), $inputitem['size'] ); for ($idx = 0; $idx < $inputitem['size']; ++$idx) { @@ -135,7 +135,7 @@ protected function encodeModeKanji($inputitem, $version) $inputitem['bstream'] = $this->appendNum($inputitem['bstream'], 4, 0x8); $inputitem['bstream'] = $this->appendNum( $inputitem['bstream'], - $this->getLengthIndicator(Data::$encodingModes['KJ'], $version), + $this->getLengthIndicator(Data::ENC_MODES['KJ'], $version), (int)($inputitem['size'] / 2) ); for ($idx = 0; $idx < $inputitem['size']; $idx += 2) { diff --git a/src/Type/Square/QrCode/EncodingMode.php b/src/Type/Square/QrCode/EncodingMode.php index 76b04454..bcca051d 100644 --- a/src/Type/Square/QrCode/EncodingMode.php +++ b/src/Type/Square/QrCode/EncodingMode.php @@ -43,13 +43,13 @@ abstract class EncodingMode extends \Com\Tecnick\Barcode\Type\Square\QrCode\Inpu public function getEncodingMode($data, $pos) { if (!isset($data[$pos])) { - return Data::$encodingModes['NL']; + return Data::ENC_MODES['NL']; } if ($this->isDigitAt($data, $pos)) { - return Data::$encodingModes['NM']; + return Data::ENC_MODES['NM']; } if ($this->isAlphanumericAt($data, $pos)) { - return Data::$encodingModes['AN']; + return Data::ENC_MODES['AN']; } return $this->getEncodingModeKj($data, $pos); } @@ -64,13 +64,13 @@ public function getEncodingMode($data, $pos) */ protected function getEncodingModeKj($data, $pos) { - if (($this->hint == Data::$encodingModes['KJ']) && isset($data[($pos + 1)])) { + if (($this->hint == Data::ENC_MODES['KJ']) && isset($data[($pos + 1)])) { $word = ((ord($data[$pos]) << 8) | ord($data[($pos + 1)])); if ((($word >= 0x8140) && ($word <= 0x9ffc)) || (($word >= 0xe040) && ($word <= 0xebbf))) { - return Data::$encodingModes['KJ']; + return Data::ENC_MODES['KJ']; } } - return Data::$encodingModes['8B']; + return Data::ENC_MODES['8B']; } /** diff --git a/src/Type/Square/QrCode/Estimate.php b/src/Type/Square/QrCode/Estimate.php index bc2d56d0..98174625 100644 --- a/src/Type/Square/QrCode/Estimate.php +++ b/src/Type/Square/QrCode/Estimate.php @@ -67,7 +67,7 @@ abstract class Estimate */ public function getLengthIndicator($mode, $version) { - if ($mode == Data::$encodingModes['ST']) { + if ($mode == Data::ENC_MODES['ST']) { return 0; } if ($version <= 9) { @@ -77,7 +77,7 @@ public function getLengthIndicator($mode, $version) } else { $len = 2; } - return Data::$lengthTableBits[$mode][$len]; + return Data::LEN_TABLE_BITS[$mode][$len]; } /** @@ -178,7 +178,7 @@ public function estimateVersion($items, $level) protected function getMinimumVersion($size, $level) { for ($idx = 1; $idx <= Data::QRSPEC_VERSION_MAX; ++$idx) { - $words = (Data::$capacity[$idx][Data::QRCAP_WORDS] - Data::$capacity[$idx][Data::QRCAP_EC][$level]); + $words = (Data::CAPACITY[$idx][Data::QRCAP_WORDS] - Data::CAPACITY[$idx][Data::QRCAP_EC][$level]); if ($words >= $size) { return $idx; } @@ -204,19 +204,19 @@ protected function estimateBitStreamSize($items, $version) } foreach ($items as $item) { switch ($item['mode']) { - case Data::$encodingModes['NM']: + case Data::ENC_MODES['NM']: $bits = $this->estimateBitsModeNum($item['size']); break; - case Data::$encodingModes['AN']: + case Data::ENC_MODES['AN']: $bits = $this->estimateBitsModeAn($item['size']); break; - case Data::$encodingModes['8B']: + case Data::ENC_MODES['8B']: $bits = $this->estimateBitsMode8($item['size']); break; - case Data::$encodingModes['KJ']: + case Data::ENC_MODES['KJ']: $bits = $this->estimateBitsModeKanji($item['size']); break; - case Data::$encodingModes['ST']: + case Data::ENC_MODES['ST']: return Data::STRUCTURE_HEADER_BITS; default: return 0; diff --git a/src/Type/Square/QrCode/Init.php b/src/Type/Square/QrCode/Init.php index df3aa31b..43dc9719 100644 --- a/src/Type/Square/QrCode/Init.php +++ b/src/Type/Square/QrCode/Init.php @@ -301,6 +301,7 @@ protected function checkRsCharParamsB($symsize, $nroots, $pad) throw new BarcodeException('Invalid parameters'); } } + /** * Initialize a Reed-Solomon codec and returns an array of values. * diff --git a/src/Type/Square/QrCode/InputItem.php b/src/Type/Square/QrCode/InputItem.php index dc3812f1..599df87f 100644 --- a/src/Type/Square/QrCode/InputItem.php +++ b/src/Type/Square/QrCode/InputItem.php @@ -41,7 +41,7 @@ abstract class InputItem extends \Com\Tecnick\Barcode\Type\Square\QrCode\Estimat */ public function lookAnTable($chr) { - return (($chr > 127) ? -1 : Data::$anTable[$chr]); + return (($chr > 127) ? -1 : Data::AN_TABLE[$chr]); } /** @@ -106,15 +106,15 @@ protected function check($mode, $size, $data) return false; } switch ($mode) { - case Data::$encodingModes['NM']: + case Data::ENC_MODES['NM']: return $this->checkModeNum($size, $data); - case Data::$encodingModes['AN']: + case Data::ENC_MODES['AN']: return $this->checkModeAn($size, $data); - case Data::$encodingModes['KJ']: + case Data::ENC_MODES['KJ']: return $this->checkModeKanji($size, $data); - case Data::$encodingModes['8B']: + case Data::ENC_MODES['8B']: return true; - case Data::$encodingModes['ST']: + case Data::ENC_MODES['ST']: return true; } return false; diff --git a/src/Type/Square/QrCode/Spec.php b/src/Type/Square/QrCode/Spec.php index 9bdc80e7..a35480b1 100644 --- a/src/Type/Square/QrCode/Spec.php +++ b/src/Type/Square/QrCode/Spec.php @@ -42,7 +42,7 @@ class Spec extends \Com\Tecnick\Barcode\Type\Square\QrCode\SpecRs */ public function getDataLength($version, $level) { - return (Data::$capacity[$version][Data::QRCAP_WORDS] - Data::$capacity[$version][Data::QRCAP_EC][$level]); + return (Data::CAPACITY[$version][Data::QRCAP_WORDS] - Data::CAPACITY[$version][Data::QRCAP_EC][$level]); } /** @@ -55,7 +55,7 @@ public function getDataLength($version, $level) */ public function getECCLength($version, $level) { - return Data::$capacity[$version][Data::QRCAP_EC][$level]; + return Data::CAPACITY[$version][Data::QRCAP_EC][$level]; } /** @@ -67,7 +67,7 @@ public function getECCLength($version, $level) */ public function getWidth($version) { - return Data::$capacity[$version][Data::QRCAP_WIDTH]; + return Data::CAPACITY[$version][Data::QRCAP_WIDTH]; } /** @@ -79,7 +79,7 @@ public function getWidth($version) */ public function getRemainder($version) { - return Data::$capacity[$version][Data::QRCAP_REMINDER]; + return Data::CAPACITY[$version][Data::QRCAP_REMINDER]; } /** @@ -92,7 +92,7 @@ public function getRemainder($version) */ public function maximumWords($mode, $version) { - if ($mode == Data::$encodingModes['ST']) { + if ($mode == Data::ENC_MODES['ST']) { return 3; } if ($version <= 9) { @@ -102,9 +102,9 @@ public function maximumWords($mode, $version) } else { $lval = 2; } - $bits = Data::$lengthTableBits[$mode][$lval]; + $bits = Data::LEN_TABLE_BITS[$mode][$lval]; $words = (1 << $bits) - 1; - if ($mode == Data::$encodingModes['KJ']) { + if ($mode == Data::ENC_MODES['KJ']) { $words *= 2; // the number of bytes is required } return $words; @@ -125,14 +125,14 @@ public function getEccSpec($version, $level, $spec) if (count($spec) < 5) { $spec = array(0, 0, 0, 0, 0); } - $bv1 = Data::$eccTable[$version][$level][0]; - $bv2 = Data::$eccTable[$version][$level][1]; + $bv1 = Data::ECC_TABLE[$version][$level][0]; + $bv2 = Data::ECC_TABLE[$version][$level][1]; $data = $this->getDataLength($version, $level); $ecc = $this->getECCLength($version, $level); if ($bv2 == 0) { $spec[0] = $bv1; - $spec[1] = (int)($data / $bv1); - $spec[2] = (int)($ecc / $bv1); + $spec[1] = (int)($data / $bv1); /* @phpstan-ignore-line */ + $spec[2] = (int)($ecc / $bv1); /* @phpstan-ignore-line */ $spec[3] = 0; $spec[4] = 0; } else { @@ -163,6 +163,6 @@ public function getFormatInfo($maskNo, $level) ) { return 0; } - return Data::$formatInfo[$level][$maskNo]; + return Data::FORMAT_INFO[$level][$maskNo]; } } diff --git a/src/Type/Square/QrCode/SpecRs.php b/src/Type/Square/QrCode/SpecRs.php index bfb382e2..ea4dd1db 100644 --- a/src/Type/Square/QrCode/SpecRs.php +++ b/src/Type/Square/QrCode/SpecRs.php @@ -151,7 +151,7 @@ public function rsEccLength($spec) */ public function createFrame($version) { - $width = Data::$capacity[$version][Data::QRCAP_WIDTH]; + $width = Data::CAPACITY[$version][Data::QRCAP_WIDTH]; $frameLine = str_repeat("\0", $width); $frame = array_fill(0, $width, $frameLine); // Finder pattern @@ -297,7 +297,7 @@ public function getVersionPattern($version) if (($version < 7) || ($version > Data::QRSPEC_VERSION_MAX)) { return 0; } - return Data::$versionPattern[($version - 7)]; + return Data::VERSION_PATTERN[($version - 7)]; } /** @@ -314,28 +314,28 @@ public function putAlignmentPattern($version, $frame, $width) if ($version < 2) { return $frame; } - $dval = Data::$alignmentPattern[$version][1] - Data::$alignmentPattern[$version][0]; + $dval = Data::ALIGN_PATTERN[$version][1] - Data::ALIGN_PATTERN[$version][0]; if ($dval < 0) { $wdt = 2; } else { - $wdt = (int)(($width - Data::$alignmentPattern[$version][0]) / $dval + 2); + $wdt = (int)(($width - Data::ALIGN_PATTERN[$version][0]) / $dval + 2); } if ($wdt * $wdt - 3 == 1) { - $psx = Data::$alignmentPattern[$version][0]; - $psy = Data::$alignmentPattern[$version][0]; + $psx = Data::ALIGN_PATTERN[$version][0]; + $psy = Data::ALIGN_PATTERN[$version][0]; $frame = $this->putAlignmentMarker($frame, $psx, $psy); return $frame; } - $cpx = Data::$alignmentPattern[$version][0]; + $cpx = Data::ALIGN_PATTERN[$version][0]; $wdo = $wdt - 1; for ($xpos = 1; $xpos < $wdo; ++$xpos) { $frame = $this->putAlignmentMarker($frame, 6, $cpx); $frame = $this->putAlignmentMarker($frame, $cpx, 6); $cpx += $dval; } - $cpy = Data::$alignmentPattern[$version][0]; + $cpy = Data::ALIGN_PATTERN[$version][0]; for ($y = 0; $y < $wdo; ++$y) { - $cpx = Data::$alignmentPattern[$version][0]; + $cpx = Data::ALIGN_PATTERN[$version][0]; for ($xpos = 0; $xpos < $wdo; ++$xpos) { $frame = $this->putAlignmentMarker($frame, $cpx, $cpy); $cpx += $dval; diff --git a/src/Type/Square/QrCode/Split.php b/src/Type/Square/QrCode/Split.php index b37ebca4..68dde4c5 100644 --- a/src/Type/Square/QrCode/Split.php +++ b/src/Type/Square/QrCode/Split.php @@ -91,14 +91,14 @@ public function getSplittedString($data) while (strlen($data) > 0) { $mode = $this->bsObj->getEncodingMode($data, 0); switch ($mode) { - case Data::$encodingModes['NM']: + case Data::ENC_MODES['NM']: $length = $this->eatNum($data); break; - case Data::$encodingModes['AN']: + case Data::ENC_MODES['AN']: $length = $this->eatAn($data); break; - case Data::$encodingModes['KJ']: - if ($this->hint == Data::$encodingModes['KJ']) { + case Data::ENC_MODES['KJ']: + if ($this->hint == Data::ENC_MODES['KJ']) { $length = $this->eatKanji($data); } else { $length = $this->eat8($data); @@ -128,13 +128,13 @@ public function getSplittedString($data) */ protected function eatNum($data) { - $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM'], $this->version); + $lng = $this->bsObj->getLengthIndicator(Data::ENC_MODES['NM'], $this->version); $pos = 0; while ($this->bsObj->isDigitAt($data, $pos)) { $pos++; } $mode = $this->bsObj->getEncodingMode($data, $pos); - if ($mode == Data::$encodingModes['8B']) { + if ($mode == Data::ENC_MODES['8B']) { $dif = $this->bsObj->estimateBitsModeNum($pos) + 4 + $lng + $this->bsObj->estimateBitsMode8(1) // + 4 + l8 - $this->bsObj->estimateBitsMode8($pos + 1); // - 4 - l8 @@ -142,7 +142,7 @@ protected function eatNum($data) return $this->eat8($data); } } - if ($mode == Data::$encodingModes['AN']) { + if ($mode == Data::ENC_MODES['AN']) { $dif = $this->bsObj->estimateBitsModeNum($pos) + 4 + $lng + $this->bsObj->estimateBitsModeAn(1) // + 4 + la - $this->bsObj->estimateBitsModeAn($pos + 1);// - 4 - la @@ -152,7 +152,7 @@ protected function eatNum($data) } $this->items = $this->bsObj->appendNewInputItem( $this->items, - Data::$encodingModes['NM'], + Data::ENC_MODES['NM'], $pos, str_split($data) ); @@ -167,8 +167,8 @@ protected function eatNum($data) */ protected function eatAn($data) { - $lag = $this->bsObj->getLengthIndicator(Data::$encodingModes['AN'], $this->version); - $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM'], $this->version); + $lag = $this->bsObj->getLengthIndicator(Data::ENC_MODES['AN'], $this->version); + $lng = $this->bsObj->getLengthIndicator(Data::ENC_MODES['NM'], $this->version); $pos = 1 ; while ($this->bsObj->isAlphanumericAt($data, $pos)) { if ($this->bsObj->isDigitAt($data, $pos)) { @@ -198,7 +198,7 @@ protected function eatAn($data) } $this->items = $this->bsObj->appendNewInputItem( $this->items, - Data::$encodingModes['AN'], + Data::ENC_MODES['AN'], $pos, str_split($data) ); @@ -214,12 +214,12 @@ protected function eatAn($data) protected function eatKanji($data) { $pos = 0; - while ($this->bsObj->getEncodingMode($data, $pos) == Data::$encodingModes['KJ']) { + while ($this->bsObj->getEncodingMode($data, $pos) == Data::ENC_MODES['KJ']) { $pos += 2; } $this->items = $this->bsObj->appendNewInputItem( $this->items, - Data::$encodingModes['KJ'], + Data::ENC_MODES['KJ'], $pos, str_split($data) ); @@ -234,16 +234,16 @@ protected function eatKanji($data) */ protected function eat8($data) { - $lag = $this->bsObj->getLengthIndicator(Data::$encodingModes['AN'], $this->version); - $lng = $this->bsObj->getLengthIndicator(Data::$encodingModes['NM'], $this->version); + $lag = $this->bsObj->getLengthIndicator(Data::ENC_MODES['AN'], $this->version); + $lng = $this->bsObj->getLengthIndicator(Data::ENC_MODES['NM'], $this->version); $pos = 1; $dataStrLen = strlen($data); while ($pos < $dataStrLen) { $mode = $this->bsObj->getEncodingMode($data, $pos); - if ($mode == Data::$encodingModes['KJ']) { + if ($mode == Data::ENC_MODES['KJ']) { break; } - if ($mode == Data::$encodingModes['NM']) { + if ($mode == Data::ENC_MODES['NM']) { $qix = $pos; while ($this->bsObj->isDigitAt($data, $qix)) { $qix++; @@ -256,7 +256,7 @@ protected function eat8($data) } else { $pos = $qix; } - } elseif ($mode == Data::$encodingModes['AN']) { + } elseif ($mode == Data::ENC_MODES['AN']) { $qix = $pos; while ($this->bsObj->isAlphanumericAt($data, $qix)) { $qix++; @@ -275,7 +275,7 @@ protected function eat8($data) } $this->items = $this->bsObj->appendNewInputItem( $this->items, - Data::$encodingModes['8B'], + Data::ENC_MODES['8B'], $pos, str_split($data) ); diff --git a/test/BarcodeTest.php b/test/BarcodeTest.php index 9f31f216..c35fa967 100644 --- a/test/BarcodeTest.php +++ b/test/BarcodeTest.php @@ -40,7 +40,7 @@ public function testGetTypes() { $testObj = $this->getTestObject(); $types = $testObj->getTypes(); - $this->assertEquals(36, count($types)); + $this->assertEquals(37, count($types)); } public function testGetBarcodeObjException() diff --git a/test/Square/AztecTest.php b/test/Square/AztecTest.php new file mode 100644 index 00000000..1c4d4da3 --- /dev/null +++ b/test/Square/AztecTest.php @@ -0,0 +1,147 @@ + + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + * + * This file is part of tc-lib-barcode software library. + */ + +namespace Test\Square; + +use PHPUnit\Framework\TestCase; +use Test\TestUtil; + +/** + * AZTEC Barcode class test + * + * @since 2023-10-20 + * @category Library + * @package Barcode + * @author Nicola Asuni + * @copyright 2023-2023 Nicola Asuni - Tecnick.com LTD + * @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT) + * @link https://github.com/tecnickcom/tc-lib-barcode + */ +class AztecTest extends TestUtil +{ + protected function getTestObject() + { + return new \Com\Tecnick\Barcode\Barcode(); + } + + public function testInvalidInput() + { + $this->bcExpectException('\Com\Tecnick\Barcode\Exception'); + $testObj = $this->getTestObject(); + $testObj->getBarcodeObj('AZTEC', ''); + } + + public function testCapacityException() + { + $this->bcExpectException('\Com\Tecnick\Barcode\Exception'); + $testObj = $this->getTestObject(); + $code = str_pad('', 2000, '0123456789'); + $testObj->getBarcodeObj('AZTEC,100,B,F,3', $code); + } + + /** + * @dataProvider getGridDataProvider + */ + public function testGetGrid($options, $code, $expected) + { + $testObj = $this->getTestObject(); + $bobj = $testObj->getBarcodeObj('AZTEC' . $options, $code); + $grid = $bobj->getGrid(); + $this->assertEquals($expected, md5($grid)); + } + + public static function getGridDataProvider() + { + return array( + array(',100,A,A,0', 'A', 'c48da49052f674edc66fa02e52334b17'), + array('', ' ABCDEFGHIJKLMNOPQRSTUVWXYZ', '74f1e68830f0c635cd01167245743098'), + array('', ' abcdefghijklmnopqrstuvwxyz', '100ebf910c88922b0ccee88256ba0c81'), + array('', ' ,.0123456789', 'ee2a70b7c88a9e0956b1896983e93f91'), + array('', "\r" . '!"#$%&\'()*+,-./:;<=>?[]{}', '6965459e50f7c3029de42ef5dc5c1fdf'), + array('', chr(1) . chr(2) . chr(3) . chr(4) . chr(5) + . chr(6) . chr(7) . chr(8) . chr(9) . chr(10) + . chr(11) . chr(12) . chr(13) . chr(27) . chr(28) + . chr(29) . chr(30) . chr(31) . chr(64) . chr(92) + . chr(94) . chr(95) . chr(96) . chr(124) . chr(126) + . chr(127), 'b8961abf38519b529f7dc6a20e8f3e59'), + array('', 'AaB0C#D' . chr(126), '9b1f2af28b8d9d222de93dfe6a09a047'), + array('', 'aAb0c#d' . chr(126), 'f4c58cabbdb5d94fa0cc1c31d510936a'), + array('', '#A$a%0&' . chr(126), 'a17634a1db6372efbf8ea25a303c38f8'), + array('', chr(1) . 'A' . chr(1) . 'a' . chr(1) . '0' . chr(1) . '#', 'c1a585888c7a1eb424ff98bbf7b32d46'), + array('', 'PUNCT pairs , . : ' . "\r\n", '35281793cc5247b291abb8e3fe5ed853'), + array('', 'ABCDEabcdeABCDE012345ABCDE?[]{}ABCDE' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5), '4ae19b80469a1afff8e490f5afaa8b73'), + array('', 'abcdeABCDEabcde012345abcde?[]{}abcde' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5), 'b0158bfe19c6fe20042128d59e40ca3b'), + array('', '?[]{}ABCDE?[]{}abcde?[]{}012345?[]{}' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5), '71ba0ed8c308c93af6af7cd23a76355a'), + array('', chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . 'ABCDE' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . 'abcde' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . '012345' + . chr(1) . chr(2) . chr(3) . chr(4) . chr(5) . '?[]{}', 'f31e14be0b2c1f903e77af11e6c901b0'), + array('', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit,' + . ' sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' + . ' Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris' + . ' nisi ut aliquip ex ea commodo consequat.' + . ' Duis aute irure dolor in reprehenderit in voluptate velit esse' + . ' cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat' + . ' cupidatat non proident,' . + ' sunt in culpa qui officia deserunt mollit anim id est laborum.', 'bb2b103d59e035a581fed0619090f89c'), + array('', chr(128) . chr(129) . chr(130) . chr(131) . chr(132), 'da92b009c1f4430e2f62c76c5f708121'), + array('', chr(128) . chr(129) . chr(130) . chr(131) . chr(132) + . chr(133) . chr(134) . chr(135) . chr(136) . chr(137) + . chr(138) . chr(139) . chr(140) . chr(141) . chr(142) + . chr(143) . chr(144) . chr(145) . chr(146) . chr(147) + . chr(148) . chr(149) . chr(150) . chr(151) . chr(152) + . chr(153) . chr(154) . chr(155) . chr(156) . chr(157) + . chr(158) . chr(159) . chr(160), 'f3dfdda6d6fdbd747c86f042fc649193'), + array('', chr(128) . chr(129) . chr(130) . chr(131) . chr(132) + . chr(133) . chr(134) . chr(135) . chr(136) . chr(137) + . chr(138) . chr(139) . chr(140) . chr(141) . chr(142) + . chr(143) . chr(144) . chr(145) . chr(146) . chr(147) + . chr(148) . chr(149) . chr(150) . chr(151) . chr(152) + . chr(153) . chr(154) . chr(155) . chr(156) . chr(157) + . chr(158) . chr(159) . chr(160) . chr(161) . chr(162) + . chr(163) . chr(164) . chr(165) . chr(166) . chr(167) + . chr(168) . chr(169) . chr(170) . chr(171) . chr(172) + . chr(173) . chr(174) . chr(175) . chr(176) . chr(177) + . chr(178) . chr(179) . chr(180) . chr(181) . chr(182) + . chr(183) . chr(184) . chr(185) . chr(186) . chr(187) + . chr(188) . chr(189) . chr(190), 'ecbce8806e1522c123f316a7af9fd9d0'), + array('', '012345: : : : : : : : ', 'b7ae80e65d754dc17fe116aaddd33c24'), + array('', '012345. , ', '92b442e5f1b33be91c576eddc12bcca7'), + array('', '012345. , . , . , . , ', '598fd97d8a28b1514cd0bf88369c68e9'), + array('', '~~~~~~. , ', 'c40fc61717a7e802d7458897197227b1'), + array('', '******. , ', 'abbe0bdfdc10ad059ad2c415e79dab31'), + array('', chr(188) . chr(189) . chr(190) . '. , ', 'c9ae209e0c6d03014753363affffee8b') + ); + } + + /** + * @dataProvider getStringDataProvider + */ + public function testStrings($code) + { + $testObj = $this->getTestObject(); + $bobj = $testObj->getBarcodeObj('AZTEC,50,B,F', $code); + $this->assertNotNull($bobj); + } + + public static function getStringDataProvider() + { + return \Test\TestStrings::$data; + } +} diff --git a/test/Square/DatamatrixTest.php b/test/Square/DatamatrixTest.php index 5a52695a..89d62f8f 100644 --- a/test/Square/DatamatrixTest.php +++ b/test/Square/DatamatrixTest.php @@ -20,7 +20,7 @@ use Test\TestUtil; /** - * Barcode class test + * Datamatrix Barcode class test * * @since 2015-02-21 * @category Library diff --git a/test/Square/PdfFourOneSevenTest.php b/test/Square/PdfFourOneSevenTest.php index 3489ba2b..f2074894 100644 --- a/test/Square/PdfFourOneSevenTest.php +++ b/test/Square/PdfFourOneSevenTest.php @@ -20,7 +20,7 @@ use Test\TestUtil; /** - * Barcode class test + * PDF417 Barcode class test * * @since 2015-02-21 * @category Library diff --git a/test/Square/QrCodeTest.php b/test/Square/QrCodeTest.php index 7bfb1792..7301837e 100644 --- a/test/Square/QrCodeTest.php +++ b/test/Square/QrCodeTest.php @@ -20,7 +20,7 @@ use Test\TestUtil; /** - * Barcode class test + * QR-Code Barcode class test * * @since 2015-02-21 * @category Library diff --git a/test/Square/RawTest.php b/test/Square/RawTest.php index 5150032b..6fd6e9d6 100644 --- a/test/Square/RawTest.php +++ b/test/Square/RawTest.php @@ -19,7 +19,7 @@ use PHPUnit\Framework\TestCase; /** - * Barcode class test + * Raw Barcode class test * * @since 2015-02-21 * @category Library