From a992372489c933b74f357ba9d83b9ae1be1f2f24 Mon Sep 17 00:00:00 2001 From: Leonardo Zenzen Date: Sat, 7 Jun 2025 16:03:43 -0300 Subject: [PATCH] Added a new hint `BINARY_MODE` to allow working with binary QRCodes, created a test and fixed nullable parameters. --- lib/Qrcode/Decoder/DecodedBitStreamParser.php | 37 ++++++++++-------- lib/Qrcode/Decoder/Decoder.php | 2 +- lib/Qrcode/Detector/Detector.php | 2 +- tests/QrReaderTest.php | 30 ++++++++++++++ tests/qrcodes/binary-test.png | Bin 0 -> 1026 bytes 5 files changed, 52 insertions(+), 19 deletions(-) create mode 100644 tests/qrcodes/binary-test.png diff --git a/lib/Qrcode/Decoder/DecodedBitStreamParser.php b/lib/Qrcode/Decoder/DecodedBitStreamParser.php index 147361b..ae211cd 100644 --- a/lib/Qrcode/Decoder/DecodedBitStreamParser.php +++ b/lib/Qrcode/Decoder/DecodedBitStreamParser.php @@ -309,24 +309,27 @@ private static function decodeByteSegment( $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. + if ($hints !== null && array_key_exists('BINARY_MODE', $hints) && $hints['BINARY_MODE']) { + $result .= $text; + } else { + $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. - try { - $encoding = mb_detect_encoding($text, $hints); - } catch (ValueError $e) { - $encoding = mb_detect_encoding($text, mb_detect_order(), false); - } - } else { - $encoding = $currentCharacterSetECI->name(); - } - $result .= mb_convert_encoding($text, $encoding); //(new String(readBytes, encoding)); - // $result .= $text; //(new String(readBytes, encoding)); + try { + $encoding = mb_detect_encoding($text, $hints); + } catch (ValueError $e) { + $encoding = mb_detect_encoding($text, mb_detect_order(), false); + } + } else { + $encoding = $currentCharacterSetECI->name(); + } + $result .= mb_convert_encoding($text, $encoding); //(new String(readBytes, encoding)); + } $byteSegments = array_merge($byteSegments, $readBytes); } diff --git a/lib/Qrcode/Decoder/Decoder.php b/lib/Qrcode/Decoder/Decoder.php index c88279e..c6b0f89 100644 --- a/lib/Qrcode/Decoder/Decoder.php +++ b/lib/Qrcode/Decoder/Decoder.php @@ -147,7 +147,7 @@ public function decodeBits(\Zxing\Common\BitMatrix $bits, $hints = null): string } } - private function decodeParser(\Zxing\Qrcode\Decoder\BitMatrixParser $parser, array $hints = null): DecoderResult + private function decodeParser(\Zxing\Qrcode\Decoder\BitMatrixParser $parser, ?array $hints = null): DecoderResult { $version = $parser->readVersion(); $ecLevel = $parser->readFormatInformation()->getErrorCorrectionLevel(); diff --git a/lib/Qrcode/Detector/Detector.php b/lib/Qrcode/Detector/Detector.php index f3dac17..9bd4734 100644 --- a/lib/Qrcode/Detector/Detector.php +++ b/lib/Qrcode/Detector/Detector.php @@ -52,7 +52,7 @@ public function __construct(private BitMatrix $image) * @throws NotFoundException if QR Code cannot be found * @throws FormatException if a QR Code cannot be decoded */ - final public function detect(array $hints = null): DetectorResult + final public function detect(?array $hints = null): DetectorResult {/*Map*/ $resultPointCallback = ($hints !== null && array_key_exists('NEED_RESULT_POINT_CALLBACK', $hints)) ? diff --git a/tests/QrReaderTest.php b/tests/QrReaderTest.php index 68dd7b7..4368a86 100644 --- a/tests/QrReaderTest.php +++ b/tests/QrReaderTest.php @@ -55,6 +55,36 @@ public function testText3() $this->assertSame("https://www.gosuslugi.ru/covid-cert/verify/9770000014233333?lang=ru&ck=733a9d218d312fe134f1c2cc06e1a800", $qrcode->text()); } + /** + * The following test is meant to check if it works with QRCodes containing raw binary data. + * The test qrcode image was generated with `qrencode -8 -r 'binary-test.bin' -o 'test-binary-test.png'`. + * + * @return void + */ + public function testBinary() { + $image = __DIR__ . "/qrcodes/binary-test.png"; + $expected = hex2bin( + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f'. + '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f'. + '404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f'. + '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f'. + '808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f'. + 'a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf'. + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf'. + 'e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff' + ); + + $qrcode = new QrReader($image); + $qrcode->decode([ + 'BINARY_MODE' => true + ]); + $this->assertSame(null, $qrcode->getError()); + $result = $qrcode->getResult(); + $this->assertInstanceOf(Result::class, $result); + $text = $result->getText(); + $this->assertEquals($expected, $text); + } + // TODO: fix this test // public function testText4() // { diff --git a/tests/qrcodes/binary-test.png b/tests/qrcodes/binary-test.png new file mode 100644 index 0000000000000000000000000000000000000000..b2fc3b6121c589e39ec93374128bd61dcda147d9 GIT binary patch literal 1026 zcmV+d1pWJoP)!8~;Jc6H$PP!sAGIX9(GMG&Bef|G zC$&D&^a&x?)iyCLl{YTOXJla_FR$Lm!aRIL7@I9ua*OP`Ai&E{blxVoos#?O=O=S- z6MXJ~OF3=psySlof2!(jat4}-Z|@L;rM8aqRCA{$RBoTUl$Sc}cqC94o0?#S*)u0> zG|%2m6`3!amYe~_f&lPVksSB%xEj_HX17F|1MheQnXh?DZPAj8%@*5~hLz04xkID) z+-b>eQP*y^h-jmLx<=ucOG_>;oXScAD(H$dN!tyZmfYwzmi!#mT-Ei`e{RweEOI4L zz6rt*8j(3K< zo&;nDm6#s^GE=sS%)k0aLAc`8%^3_5^$5s}6g8^}qwNf82eaa-Rpk(!R+39(pg{@x z3YjS@g6dnRB^VKB;0;=Z8_O$_lk^0yPGQ*na6lEjBf@a|(fF?CVY zMo*q|n^S&R_Xy<#N$5N+!8%Be9afn?C?Bjtot9uWqL3fZW4S3@GtqEq$yG(GwnU2z za0Dawl|LX571t%+trYkk2F4>=a$6{h2#Uj@B`4O2 zZ2^z%sZ}WIFZZM&SIm&)g$+u36;*&2cy*(KaD?CF4Ym&RKVpuxrGD4-`$Rll#l+y< zmpzE5Kn*Q=f^Nga$fG4_m2m&nB^rXcJ*7McNfAdh9ICQ)T7nPO>0(}B{Ly?NPwdnL zA$;JsM57(x%gAEOSxvYimXHKD{OR-?Rny}Cq4W^XWQ;e{7@1nYcxF)gteI5<{907*qoM6N<$f|EGaUjP6A literal 0 HcmV?d00001