PK AT-D"A A + lib/Qrcode/Decoder/ErrorCorrectionLevel.phpnu ٘ See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels * defined by the QR code standard.
* * @author Sean Owen */ class ErrorCorrectionLevel { private static $FOR_BITS; private $bits; private $ordinal; public function __construct($bits, $ordinal = 0) { $this->bits = $bits; $this->ordinal = $ordinal; } public static function Init() { self::$FOR_BITS = [ new ErrorCorrectionLevel(0x00, 1), //M new ErrorCorrectionLevel(0x01, 0), //L new ErrorCorrectionLevel(0x02, 3), //H new ErrorCorrectionLevel(0x03, 2), //Q ]; } /** L = ~7% correction */ // self::$L = new ErrorCorrectionLevel(0x01); /** M = ~15% correction */ //self::$M = new ErrorCorrectionLevel(0x00); /** Q = ~25% correction */ //self::$Q = new ErrorCorrectionLevel(0x03); /** H = ~30% correction */ //self::$H = new ErrorCorrectionLevel(0x02); /** * @param bits int containing the two bits encoding a QR Code's error correction level * * @return ErrorCorrectionLevel representing the encoded error correction level */ public static function forBits($bits) { if ($bits < 0 || $bits >= count(self::$FOR_BITS)) { throw new \InvalidArgumentException(); } $level = self::$FOR_BITS[$bits]; // $lev = self::$$bit; return $level; } public function getBits() { return $this->bits; } public function toString() { return $this->bits; } public function getOrdinal() { return $this->ordinal; } } ErrorCorrectionLevel::Init(); PK ATfs9 s9 - lib/Qrcode/Decoder/DecodedBitStreamParser.phpnu ٘ QR Codes can encode text as bits in one of several modes, and can use multiple modes * in one QR Code. This class decodes the bits back into text. * *See ISO 18004:2006, 6.4.3 - 6.4.7
* * @author Sean Owen */ final class DecodedBitStreamParser { /** * See ISO 18004:2006, 6.4.4 Table 5 */ private static $ALPHANUMERIC_CHARS = [ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ', '$', '%', '*', '+', '-', '.', '/', ':', ]; private static $GB2312_SUBSET = 1; public static function decode($bytes, $version, $ecLevel, $hints) { $bits = new BitSource($bytes); $result = '';//new StringBuilder(50); $byteSegments = []; $symbolSequence = -1; $parityData = -1; try { $currentCharacterSetECI = null; $fc1InEffect = false; $mode = ''; do { // While still another segment to read... if ($bits->available() < 4) { // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here $mode = Mode::$TERMINATOR; } else { $mode = Mode::forBits($bits->readBits(4)); // mode is encoded by 4 bits } if ($mode != Mode::$TERMINATOR) { if ($mode == Mode::$FNC1_FIRST_POSITION || $mode == Mode::$FNC1_SECOND_POSITION) { // We do little with FNC1 except alter the parsed result a bit according to the spec $fc1InEffect = true; } else if ($mode == Mode::$STRUCTURED_APPEND) { if ($bits->available() < 16) { throw FormatException::getFormatInstance(); } // sequence number and parity is added later to the result metadata // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue $symbolSequence = $bits->readBits(8); $parityData = $bits->readBits(8); } else if ($mode == Mode::$ECI) { // Count doesn't apply to ECI $value = self::parseECIValue($bits); $currentCharacterSetECI = CharacterSetECI::getCharacterSetECIByValue($value); if ($currentCharacterSetECI == null) { throw FormatException::getFormatInstance(); } } else { // First handle Hanzi mode which does not start with character count if ($mode == Mode::$HANZI) { //chinese mode contains a sub set indicator right after mode indicator $subset = $bits->readBits(4); $countHanzi = $bits->readBits($mode->getCharacterCountBits($version)); if ($subset == self::$GB2312_SUBSET) { self::decodeHanziSegment($bits, $result, $countHanzi); } } else { // "Normal" QR code modes: // How many characters will follow, encoded in this mode? $count = $bits->readBits($mode->getCharacterCountBits($version)); if ($mode == Mode::$NUMERIC) { self::decodeNumericSegment($bits, $result, $count); } else if ($mode == Mode::$ALPHANUMERIC) { self::decodeAlphanumericSegment($bits, $result, $count, $fc1InEffect); } else if ($mode == Mode::$BYTE) { self::decodeByteSegment($bits, $result, $count, $currentCharacterSetECI, $byteSegments, $hints); } else if ($mode == Mode::$KANJI) { self::decodeKanjiSegment($bits, $result, $count); } else { throw FormatException::getFormatInstance(); } } } } } while ($mode != Mode::$TERMINATOR); } catch (\InvalidArgumentException $iae) { // from readBits() calls throw FormatException::getFormatInstance(); } return new DecoderResult($bytes, $result, empty($byteSegments) ? null : $byteSegments, $ecLevel == null ? null : 'L',//ErrorCorrectionLevel::toString($ecLevel), $symbolSequence, $parityData); } private static function parseECIValue($bits) { $firstByte = $bits->readBits(8); if (($firstByte & 0x80) == 0) { // just one byte return $firstByte & 0x7F; } if (($firstByte & 0xC0) == 0x80) { // two bytes $secondByte = $bits->readBits(8); return (($firstByte & 0x3F) << 8) | $secondByte; } if (($firstByte & 0xE0) == 0xC0) { // three bytes $secondThirdBytes = $bits->readBits(16); return (($firstByte & 0x1F) << 16) | $secondThirdBytes; } throw FormatException::getFormatInstance(); } /** * See specification GBT 18284-2000 */ private static function decodeHanziSegment($bits, &$result, $count) { // Don't crash trying to read more bits than we have available. if ($count * 13 > $bits->available()) { throw FormatException::getFormatInstance(); } // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as GB2312 afterwards $buffer = fill_array(0, 2 * $count, 0); $offset = 0; while ($count > 0) { // Each 13 bits encodes a 2-byte character $twoBytes = $bits->readBits(13); $assembledTwoBytes = (($twoBytes / 0x060) << 8) | ($twoBytes % 0x060); if ($assembledTwoBytes < 0x003BF) { // In the 0xA1A1 to 0xAAFE range $assembledTwoBytes += 0x0A1A1; } else { // In the 0xB0A1 to 0xFAFE range $assembledTwoBytes += 0x0A6A1; } $buffer[$offset] = (($assembledTwoBytes >> 8) & 0xFF);//(byte) $buffer[$offset + 1] = ($assembledTwoBytes & 0xFF);//(byte) $offset += 2; $count--; } $result .= iconv('GB2312', 'UTF-8', implode($buffer)); } private static function decodeNumericSegment($bits, &$result, $count) { // Read three digits at a time while ($count >= 3) { // Each 10 bits encodes three digits if ($bits->available() < 10) { throw FormatException::getFormatInstance(); } $threeDigitsBits = $bits->readBits(10); if ($threeDigitsBits >= 1000) { throw FormatException::getFormatInstance(); } $result .= (self::toAlphaNumericChar($threeDigitsBits / 100)); $result .= (self::toAlphaNumericChar(($threeDigitsBits / 10) % 10)); $result .= (self::toAlphaNumericChar($threeDigitsBits % 10)); $count -= 3; } if ($count == 2) { // Two digits left over to read, encoded in 7 bits if ($bits->available() < 7) { throw FormatException::getFormatInstance(); } $twoDigitsBits = $bits->readBits(7); if ($twoDigitsBits >= 100) { throw FormatException::getFormatInstance(); } $result .= (self::toAlphaNumericChar($twoDigitsBits / 10)); $result .= (self::toAlphaNumericChar($twoDigitsBits % 10)); } else if ($count == 1) { // One digit left over to read if ($bits->available() < 4) { throw FormatException::getFormatInstance(); } $digitBits = $bits->readBits(4); if ($digitBits >= 10) { throw FormatException::getFormatInstance(); } $result .= (self::toAlphaNumericChar($digitBits)); } } private static function toAlphaNumericChar($value) { if ($value >= count(self::$ALPHANUMERIC_CHARS)) { throw FormatException::getFormatInstance(); } return self::$ALPHANUMERIC_CHARS[$value]; } private static function decodeAlphanumericSegment($bits, &$result, $count, $fc1InEffect) { // Read two characters at a time $start = strlen($result); while ($count > 1) { if ($bits->available() < 11) { throw FormatException::getFormatInstance(); } $nextTwoCharsBits = $bits->readBits(11); $result .= (self::toAlphaNumericChar($nextTwoCharsBits / 45)); $result .= (self::toAlphaNumericChar($nextTwoCharsBits % 45)); $count -= 2; } if ($count == 1) { // special case: one character left if ($bits->available() < 6) { throw FormatException::getFormatInstance(); } $result .= self::toAlphaNumericChar($bits->readBits(6)); } // See section 6.4.8.1, 6.4.8.2 if ($fc1InEffect) { // We need to massage the result a bit if in an FNC1 mode: for ($i = $start; $i < strlen($result); $i++) { if ($result[$i] == '%') { if ($i < strlen($result) - 1 && $result[$i + 1] == '%') { // %% is rendered as % $result = substr_replace($result, '', $i + 1, 1);//deleteCharAt(i + 1); } else { // In alpha mode, % should be converted to FNC1 separator 0x1D $result . setCharAt($i, chr(0x1D)); } } } } } private static function decodeByteSegment($bits, &$result, $count, $currentCharacterSetECI, &$byteSegments, $hints) { // Don't crash trying to read more bits than we have available. if (8 * $count > $bits->available()) { throw FormatException::getFormatInstance(); } $readBytes = fill_array(0, $count, 0); for ($i = 0; $i < $count; $i++) { $readBytes[$i] = $bits->readBits(8);//(byte) } $text = implode(array_map('chr', $readBytes)); $encoding = ''; if ($currentCharacterSetECI == null) { // The spec isn't clear on this mode; see // section 6.4.5: t does not say which encoding to assuming // upon decoding. I have seen ISO-8859-1 used as well as // Shift_JIS -- without anything like an ECI designator to // give a hint. $encoding = mb_detect_encoding($text, $hints); } else { $encoding = $currentCharacterSetECI->name(); } // $result.= mb_convert_encoding($text ,$encoding);//(new String(readBytes, encoding)); $result .= $text;//(new String(readBytes, encoding)); $byteSegments = array_merge($byteSegments, $readBytes); } private static function decodeKanjiSegment($bits, &$result, $count) { // Don't crash trying to read more bits than we have available. if ($count * 13 > $bits->available()) { throw FormatException::getFormatInstance(); } // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards $buffer = [0, 2 * $count, 0]; $offset = 0; while ($count > 0) { // Each 13 bits encodes a 2-byte character $twoBytes = $bits->readBits(13); $assembledTwoBytes = (($twoBytes / 0x0C0) << 8) | ($twoBytes % 0x0C0); if ($assembledTwoBytes < 0x01F00) { // In the 0x8140 to 0x9FFC range $assembledTwoBytes += 0x08140; } else { // In the 0xE040 to 0xEBBF range $assembledTwoBytes += 0x0C140; } $buffer[$offset] = ($assembledTwoBytes >> 8);//(byte) $buffer[$offset + 1] = $assembledTwoBytes; //(byte) $offset += 2; $count--; } // Shift_JIS may not be supported in some environments: $result .= iconv('shift-jis', 'utf-8', implode($buffer)); } private function DecodedBitStreamParser() { } } PK ATrpbc c lib/Qrcode/Decoder/Version.phpnu ٘ versionNumber = $versionNumber; $this->alignmentPatternCenters = $alignmentPatternCenters; $this->ecBlocks = $ecBlocks; $total = 0; if(is_array($ecBlocks)) { $ecCodewords = $ecBlocks[0]->getECCodewordsPerBlock(); $ecbArray = $ecBlocks[0]->getECBlocks(); }else{ $ecCodewords = $ecBlocks->getECCodewordsPerBlock(); $ecbArray = $ecBlocks->getECBlocks(); } foreach ($ecbArray as $ecBlock) { $total += $ecBlock->getCount() * ($ecBlock->getDataCodewords() + $ecCodewords); } $this->totalCodewords = $total; } public function getVersionNumber() { return $this->versionNumber; } public function getAlignmentPatternCenters() { return $this->alignmentPatternCenters; } public function getTotalCodewords() { return $this->totalCodewords; } public function getDimensionForVersion() { return 17 + 4 * $this->versionNumber; } public function getECBlocksForLevel($ecLevel) { return $this->ecBlocks[$ecLevel->getOrdinal()]; } /** *Deduces version information purely from QR Code dimensions.
* * @param dimension dimension in modules * @return Version for a QR Code of that dimension * @throws FormatException if dimension is not 1 mod 4 */ public static function getProvisionalVersionForDimension($dimension) { if ($dimension % 4 != 1) { throw FormatException::getFormatInstance(); } try { return self::getVersionForNumber(($dimension - 17) / 4); } catch (\InvalidArgumentException $ignored) { throw FormatException::getFormatInstance(); } } public static function getVersionForNumber($versionNumber) { if ($versionNumber < 1 || $versionNumber > 40) { throw new \InvalidArgumentException(); } if(!self::$VERSIONS){ self::$VERSIONS = self::buildVersions(); } return self::$VERSIONS[$versionNumber - 1]; } static function decodeVersionInformation($versionBits) { $bestDifference = PHP_INT_MAX; $bestVersion = 0; for ($i = 0; $i < count(self::$VERSION_DECODE_INFO); $i++) { $targetVersion = self::$VERSION_DECODE_INFO[$i]; // Do the version info bits match exactly? done. if ($targetVersion == $versionBits) { return self::getVersionForNumber($i + 7); } // Otherwise see if this is the closest to a real version info bit string // we have seen so far $bitsDifference = FormatInformation::numBitsDiffering($versionBits, $targetVersion); if ($bitsDifference < $bestDifference) { $bestVersion = $i + 7; $bestDifference = $bitsDifference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 8 bits. if ($bestDifference <= 3) { return self::getVersionForNumber($bestVersion); } // If we didn't find a close enough match, fail return null; } /** * See ISO 18004:2006 Annex E */ function buildFunctionPattern() { $dimension = self::getDimensionForVersion(); $bitMatrix = new BitMatrix($dimension); // Top left finder pattern + separator + format $bitMatrix->setRegion(0, 0, 9, 9); // Top right finder pattern + separator + format $bitMatrix->setRegion($dimension - 8, 0, 8, 9); // Bottom left finder pattern + separator + format $bitMatrix->setRegion(0, $dimension - 8, 9, 8); // Alignment patterns $max = count($this->alignmentPatternCenters); for ($x = 0; $x < $max; $x++) { $i = $this->alignmentPatternCenters[$x] - 2; for ($y = 0; $y < $max; $y++) { if (($x == 0 && ($y == 0 || $y == $max - 1)) || ($x == $max - 1 && $y == 0)) { // No alignment patterns near the three finder paterns continue; } $bitMatrix->setRegion($this->alignmentPatternCenters[$y] - 2, $i, 5, 5); } } // Vertical timing pattern $bitMatrix->setRegion(6, 9, 1, $dimension - 17); // Horizontal timing pattern $bitMatrix->setRegion(9, 6, $dimension - 17, 1); if ($this->versionNumber > 6) { // Version info, top right $bitMatrix->setRegion($dimension - 11, 0, 3, 6); // Version info, bottom left $bitMatrix->setRegion(0, $dimension - 11, 6, 3); } return $bitMatrix; } /** * See ISO 18004:2006 6.5.1 Table 9 */ private static function buildVersions() { return array( new Version(1, array(), array(new ECBlocks(7, array(new ECB(1, 19))), new ECBlocks(10, array(new ECB(1, 16))), new ECBlocks(13, array(new ECB(1, 13))), new ECBlocks(17, array(new ECB(1, 9))))), new Version(2, array(6, 18), array(new ECBlocks(10, array(new ECB(1, 34))), new ECBlocks(16, array(new ECB(1, 28))), new ECBlocks(22, array(new ECB(1, 22))), new ECBlocks(28, array(new ECB(1, 16))))), new Version(3, array(6, 22), array( new ECBlocks(15, array(new ECB(1, 55))), new ECBlocks(26, array(new ECB(1, 44))), new ECBlocks(18, array(new ECB(2, 17))), new ECBlocks(22, array(new ECB(2, 13))))), new Version(4, array(6, 26), array(new ECBlocks(20, array(new ECB(1, 80))), new ECBlocks(18, array(new ECB(2, 32))), new ECBlocks(26, array(new ECB(2, 24))), new ECBlocks(16, array(new ECB(4, 9))))), new Version(5, array(6, 30), array(new ECBlocks(26, array(new ECB(1, 108))), new ECBlocks(24, array(new ECB(2, 43))), new ECBlocks(18, array(new ECB(2, 15), new ECB(2, 16))), new ECBlocks(22, array(new ECB(2, 11), new ECB(2, 12))))), new Version(6, array(6, 34), array(new ECBlocks(18, array(new ECB(2, 68))), new ECBlocks(16, array(new ECB(4, 27))), new ECBlocks(24, array(new ECB(4, 19))), new ECBlocks(28, array(new ECB(4, 15))))), new Version(7, array(6, 22, 38), array(new ECBlocks(20, array(new ECB(2, 78))), new ECBlocks(18, array(new ECB(4, 31))), new ECBlocks(18, array(new ECB(2, 14), new ECB(4, 15))), new ECBlocks(26, array(new ECB(4, 13), new ECB(1, 14))))), new Version(8, array(6, 24, 42), array(new ECBlocks(24, array(new ECB(2, 97))), new ECBlocks(22, array(new ECB(2, 38), new ECB(2, 39))), new ECBlocks(22, array(new ECB(4, 18), new ECB(2, 19))), new ECBlocks(26, array(new ECB(4, 14), new ECB(2, 15))))), new Version(9, array(6, 26, 46), array(new ECBlocks(30, array(new ECB(2, 116))), new ECBlocks(22, array(new ECB(3, 36), new ECB(2, 37))), new ECBlocks(20, array(new ECB(4, 16), new ECB(4, 17))), new ECBlocks(24, array(new ECB(4, 12), new ECB(4, 13))))), new Version(10, array(6, 28, 50), array(new ECBlocks(18, array(new ECB(2, 68), new ECB(2, 69))), new ECBlocks(26, array(new ECB(4, 43), new ECB(1, 44))), new ECBlocks(24, array(new ECB(6, 19), new ECB(2, 20))), new ECBlocks(28, array(new ECB(6, 15), new ECB(2, 16))))), new Version(11, array(6, 30, 54), array(new ECBlocks(20, array(new ECB(4, 81))), new ECBlocks(30, array(new ECB(1, 50), new ECB(4, 51))), new ECBlocks(28, array(new ECB(4, 22), new ECB(4, 23))), new ECBlocks(24, array(new ECB(3, 12), new ECB(8, 13))))), new Version(12, array(6, 32, 58), array(new ECBlocks(24, array(new ECB(2, 92), new ECB(2, 93))), new ECBlocks(22, array(new ECB(6, 36), new ECB(2, 37))), new ECBlocks(26, array(new ECB(4, 20), new ECB(6, 21))), new ECBlocks(28, array(new ECB(7, 14), new ECB(4, 15))))), new Version(13, array(6, 34, 62), array(new ECBlocks(26, array(new ECB(4, 107))), new ECBlocks(22, array(new ECB(8, 37), new ECB(1, 38))), new ECBlocks(24, array(new ECB(8, 20), new ECB(4, 21))), new ECBlocks(22, array(new ECB(12, 11), new ECB(4, 12))))), new Version(14, array(6, 26, 46, 66), array(new ECBlocks(30, array(new ECB(3, 115), new ECB(1, 116))), new ECBlocks(24, array(new ECB(4, 40), new ECB(5, 41))), new ECBlocks(20, array(new ECB(11, 16), new ECB(5, 17))), new ECBlocks(24, array(new ECB(11, 12), new ECB(5, 13))))), new Version(15, array(6, 26, 48, 70), array(new ECBlocks(22, array(new ECB(5, 87), new ECB(1, 88))), new ECBlocks(24, array(new ECB(5, 41), new ECB(5, 42))), new ECBlocks(30, array(new ECB(5, 24), new ECB(7, 25))), new ECBlocks(24, array(new ECB(11, 12), new ECB(7, 13))))), new Version(16, array(6, 26, 50, 74), array(new ECBlocks(24, array(new ECB(5, 98), new ECB(1, 99))), new ECBlocks(28, array(new ECB(7, 45), new ECB(3, 46))), new ECBlocks(24, array(new ECB(15, 19), new ECB(2, 20))), new ECBlocks(30, array(new ECB(3, 15), new ECB(13, 16))))), new Version(17, array(6, 30, 54, 78), array(new ECBlocks(28, array(new ECB(1, 107), new ECB(5, 108))), new ECBlocks(28, array(new ECB(10, 46), new ECB(1, 47))), new ECBlocks(28, array(new ECB(1, 22), new ECB(15, 23))), new ECBlocks(28, array(new ECB(2, 14), new ECB(17, 15))))), new Version(18, array(6, 30, 56, 82), array(new ECBlocks(30, array(new ECB(5, 120), new ECB(1, 121))), new ECBlocks(26, array(new ECB(9, 43), new ECB(4, 44))), new ECBlocks(28, array(new ECB(17, 22), new ECB(1, 23))), new ECBlocks(28, array(new ECB(2, 14), new ECB(19, 15))))), new Version(19, array(6, 30, 58, 86), array(new ECBlocks(28, array(new ECB(3, 113), new ECB(4, 114))), new ECBlocks(26, array(new ECB(3, 44), new ECB(11, 45))), new ECBlocks(26, array(new ECB(17, 21), new ECB(4, 22))), new ECBlocks(26, array(new ECB(9, 13), new ECB(16, 14))))), new Version(20, array(6, 34, 62, 90), array(new ECBlocks(28, array(new ECB(3, 107), new ECB(5, 108))), new ECBlocks(26, array(new ECB(3, 41), new ECB(13, 42))), new ECBlocks(30, array(new ECB(15, 24), new ECB(5, 25))), new ECBlocks(28, array(new ECB(15, 15), new ECB(10, 16))))), new Version(21, array(6, 28, 50, 72, 94), array( new ECBlocks(28, array(new ECB(4, 116), new ECB(4, 117))), new ECBlocks(26, array(new ECB(17, 42))), new ECBlocks(28, array(new ECB(17, 22), new ECB(6, 23))), new ECBlocks(30, array(new ECB(19, 16), new ECB(6, 17))))), new Version(22, array(6, 26, 50, 74, 98), array(new ECBlocks(28, array(new ECB(2, 111), new ECB(7, 112))), new ECBlocks(28, array(new ECB(17, 46))), new ECBlocks(30, array(new ECB(7, 24), new ECB(16, 25))), new ECBlocks(24, array(new ECB(34, 13))))), new Version(23, array(6, 30, 54, 78, 102), new ECBlocks(30, array(new ECB(4, 121), new ECB(5, 122))), new ECBlocks(28, array(new ECB(4, 47), new ECB(14, 48))), new ECBlocks(30, array(new ECB(11, 24), new ECB(14, 25))), new ECBlocks(30, array(new ECB(16, 15), new ECB(14, 16)))), new Version(24, array(6, 28, 54, 80, 106), array(new ECBlocks(30, array(new ECB(6, 117), new ECB(4, 118))), new ECBlocks(28, array(new ECB(6, 45), new ECB(14, 46))), new ECBlocks(30, array(new ECB(11, 24), new ECB(16, 25))), new ECBlocks(30, array(new ECB(30, 16), new ECB(2, 17))))), new Version(25, array(6, 32, 58, 84, 110), array(new ECBlocks(26, array(new ECB(8, 106), new ECB(4, 107))), new ECBlocks(28, array(new ECB(8, 47), new ECB(13, 48))), new ECBlocks(30, array(new ECB(7, 24), new ECB(22, 25))), new ECBlocks(30, array(new ECB(22, 15), new ECB(13, 16))))), new Version(26, array(6, 30, 58, 86, 114), array(new ECBlocks(28, array(new ECB(10, 114), new ECB(2, 115))), new ECBlocks(28, array(new ECB(19, 46), new ECB(4, 47))), new ECBlocks(28, array(new ECB(28, 22), new ECB(6, 23))), new ECBlocks(30, array(new ECB(33, 16), new ECB(4, 17))))), new Version(27, array(6, 34, 62, 90, 118), array(new ECBlocks(30, array(new ECB(8, 122), new ECB(4, 123))), new ECBlocks(28, array(new ECB(22, 45), new ECB(3, 46))), new ECBlocks(30, array(new ECB(8, 23), new ECB(26, 24))), new ECBlocks(30, array(new ECB(12, 15), new ECB(28, 16))))), new Version(28, array(6, 26, 50, 74, 98, 122), array(new ECBlocks(30, array(new ECB(3, 117), new ECB(10, 118))), new ECBlocks(28, array(new ECB(3, 45), new ECB(23, 46))), new ECBlocks(30, array(new ECB(4, 24), new ECB(31, 25))), new ECBlocks(30, array(new ECB(11, 15), new ECB(31, 16))))), new Version(29, array(6, 30, 54, 78, 102, 126), array(new ECBlocks(30, array(new ECB(7, 116), new ECB(7, 117))), new ECBlocks(28, array(new ECB(21, 45), new ECB(7, 46))), new ECBlocks(30, array(new ECB(1, 23), new ECB(37, 24))), new ECBlocks(30, array(new ECB(19, 15), new ECB(26, 16))))), new Version(30, array(6, 26, 52, 78, 104, 130), array(new ECBlocks(30, array(new ECB(5, 115), new ECB(10, 116))), new ECBlocks(28, array(new ECB(19, 47), new ECB(10, 48))), new ECBlocks(30, array(new ECB(15, 24), new ECB(25, 25))), new ECBlocks(30, array(new ECB(23, 15), new ECB(25, 16))))), new Version(31, array(6, 30, 56, 82, 108, 134), array(new ECBlocks(30, array(new ECB(13, 115), new ECB(3, 116))), new ECBlocks(28, array(new ECB(2, 46), new ECB(29, 47))), new ECBlocks(30, array(new ECB(42, 24), new ECB(1, 25))), new ECBlocks(30, array(new ECB(23, 15), new ECB(28, 16))))), new Version(32, array(6, 34, 60, 86, 112, 138), array(new ECBlocks(30, array(new ECB(17, 115))), new ECBlocks(28, array(new ECB(10, 46), new ECB(23, 47))), new ECBlocks(30, array(new ECB(10, 24), new ECB(35, 25))), new ECBlocks(30, array(new ECB(19, 15), new ECB(35, 16))))), new Version(33, array(6, 30, 58, 86, 114, 142), array(new ECBlocks(30, array(new ECB(17, 115), new ECB(1, 116))), new ECBlocks(28, array(new ECB(14, 46), new ECB(21, 47))), new ECBlocks(30, array(new ECB(29, 24), new ECB(19, 25))), new ECBlocks(30, array(new ECB(11, 15), new ECB(46, 16))))), new Version(34, array(6, 34, 62, 90, 118, 146), array(new ECBlocks(30, array(new ECB(13, 115), new ECB(6, 116))), new ECBlocks(28, array(new ECB(14, 46), new ECB(23, 47))), new ECBlocks(30, array(new ECB(44, 24), new ECB(7, 25))), new ECBlocks(30, array(new ECB(59, 16), new ECB(1, 17))))), new Version(35, array(6, 30, 54, 78, 102, 126, 150), array(new ECBlocks(30, array(new ECB(12, 121), new ECB(7, 122))), new ECBlocks(28, array(new ECB(12, 47), new ECB(26, 48))), new ECBlocks(30, array(new ECB(39, 24), new ECB(14, 25))), new ECBlocks(30, array(new ECB(22, 15), new ECB(41, 16))))), new Version(36, array(6, 24, 50, 76, 102, 128, 154), array(new ECBlocks(30, array(new ECB(6, 121), new ECB(14, 122))), new ECBlocks(28, array(new ECB(6, 47), new ECB(34, 48))), new ECBlocks(30, array(new ECB(46, 24), new ECB(10, 25))), new ECBlocks(30, array(new ECB(2, 15), new ECB(64, 16))))), new Version(37, array(6, 28, 54, 80, 106, 132, 158), array(new ECBlocks(30, array(new ECB(17, 122), new ECB(4, 123))), new ECBlocks(28, array(new ECB(29, 46), new ECB(14, 47))), new ECBlocks(30, array(new ECB(49, 24), new ECB(10, 25))), new ECBlocks(30, array(new ECB(24, 15), new ECB(46, 16))))), new Version(38, array(6, 32, 58, 84, 110, 136, 162), array(new ECBlocks(30, array(new ECB(4, 122), new ECB(18, 123))), new ECBlocks(28, array(new ECB(13, 46), new ECB(32, 47))), new ECBlocks(30, array(new ECB(48, 24), new ECB(14, 25))), new ECBlocks(30, array(new ECB(42, 15), new ECB(32, 16))))), new Version(39, array(6, 26, 54, 82, 110, 138, 166), array(new ECBlocks(30, array(new ECB(20, 117), new ECB(4, 118))), new ECBlocks(28, array(new ECB(40, 47), new ECB(7, 48))), new ECBlocks(30, array(new ECB(43, 24), new ECB(22, 25))), new ECBlocks(30, array(new ECB(10, 15), new ECB(67, 16))))), new Version(40, array(6, 30, 58, 86, 114, 142, 170), array(new ECBlocks(30, array(new ECB(19, 118), new ECB(6, 119))), new ECBlocks(28, array(new ECB(18, 47), new ECB(31, 48))), new ECBlocks(30, array(new ECB(34, 24), new ECB(34, 25))), new ECBlocks(30, array(new ECB(20, 15), new ECB(61, 16))))) ); } } /** *Encapsulates a set of error-correction blocks in one symbol version. Most versions will * use blocks of differing sizes within one version, so, this encapsulates the parameters for * each set of blocks. It also holds the number of error-correction codewords per block since it * will be the same across all blocks within one version.
*/ final class ECBlocks { private $ecCodewordsPerBlock; private $ecBlocks; function __construct($ecCodewordsPerBlock, $ecBlocks) { $this->ecCodewordsPerBlock = $ecCodewordsPerBlock; $this->ecBlocks = $ecBlocks; } public function getECCodewordsPerBlock() { return $this->ecCodewordsPerBlock; } public function getNumBlocks() { $total = 0; foreach ($this->ecBlocks as $ecBlock) { $total += $ecBlock->getCount(); } return $total; } public function getTotalECCodewords() { return $this->ecCodewordsPerBlock * $this->getNumBlocks(); } public function getECBlocks() { return $this->ecBlocks; } } /** *Encapsualtes the parameters for one error-correction block in one symbol version. * This includes the number of data codewords, and the number of times a block with these * parameters is used consecutively in the QR code version's format.
*/ final class ECB { private $count; private $dataCodewords; function __construct($count, $dataCodewords) { $this->count = $count; $this->dataCodewords = $dataCodewords; } public function getCount() { return $this->count; } public function getDataCodewords() { return $this->dataCodewords; } //@Override public function toString() { die('Version ECB toString()'); // return parent::$versionNumber; } } PK ATq{5 5 lib/Qrcode/Decoder/DataMask.phpnu ٘ Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, * including areas used for finder patterns, timing patterns, etc. These areas should be unused * after the point they are unmasked anyway. * *Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position * and j is row position. In fact, as the text says, i is row position and j is column position.
* * @author Sean Owen */ abstract class DataMask { /** * See ISO 18004:2006 6.8.1 */ private static $DATA_MASKS = []; public function __construct() { } public static function Init() { self::$DATA_MASKS = [ new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111(), ]; } /** * @param reference a value between 0 and 7 indicating one of the eight possible * data mask patterns a QR Code may use * * @return DataMask encapsulating the data mask pattern */ public static function forReference($reference) { if ($reference < 0 || $reference > 7) { throw new \InvalidArgumentException(); } return self::$DATA_MASKS[$reference]; } /** *Implementations of this method reverse the data masking process applied to a QR Code and * make its bits ready to read.
* * @param bits representation of QR Code bits * @param dimension dimension of QR Code, represented by bits, being unmasked */ final public function unmaskBitMatrix($bits, $dimension) { for ($i = 0; $i < $dimension; $i++) { for ($j = 0; $j < $dimension; $j++) { if ($this->isMasked($i, $j)) { $bits->flip($j, $i); } } } } abstract public function isMasked($i, $j); } DataMask::Init(); /** * 000: mask bits for which (x + y) mod 2 == 0 */ final class DataMask000 extends DataMask { // @Override public function isMasked($i, $j) { return (($i + $j) & 0x01) == 0; } } /** * 001: mask bits for which x mod 2 == 0 */ final class DataMask001 extends DataMask { //@Override public function isMasked($i, $j) { return ($i & 0x01) == 0; } } /** * 010: mask bits for which y mod 3 == 0 */ final class DataMask010 extends DataMask { //@Override public function isMasked($i, $j) { return $j % 3 == 0; } } /** * 011: mask bits for which (x + y) mod 3 == 0 */ final class DataMask011 extends DataMask { //@Override public function isMasked($i, $j) { return ($i + $j) % 3 == 0; } } /** * 100: mask bits for which (x/2 + y/3) mod 2 == 0 */ final class DataMask100 extends DataMask { //@Override public function isMasked($i, $j) { return (int)(((int)($i / 2) + (int)($j / 3)) & 0x01) == 0; } } /** * 101: mask bits for which xy mod 2 + xy mod 3 == 0 */ final class DataMask101 extends DataMask { //@Override public function isMasked($i, $j) { $temp = $i * $j; return ($temp & 0x01) + ($temp % 3) == 0; } } /** * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 */ final class DataMask110 extends DataMask { //@Override public function isMasked($i, $j) { $temp = $i * $j; return ((($temp & 0x01) + ($temp % 3)) & 0x01) == 0; } } /** * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 */ final class DataMask111 extends DataMask { //@Override public function isMasked($i, $j) { return (((($i + $j) & 0x01) + (($i * $j) % 3)) & 0x01) == 0; } } PK ATz%% %% &