From 92a0ba2da93e4c613408ba687f4b6eb8ce756e0e Mon Sep 17 00:00:00 2001 From: smiley Date: Thu, 8 Jun 2023 23:21:32 +0200 Subject: [PATCH] :octocat: M_TYPE bitmask rework --- examples/image.php | 6 +- examples/imageWithLogo.php | 2 +- examples/imagick.php | 6 +- examples/imagickWithLogo.php | 6 +- examples/svg.php | 7 +-- examples/svgMeltedModules.php | 9 +-- examples/svgRandomColoredDots.php | 35 ++++-------- examples/svgRoundQuietzone.php | 23 +++----- examples/svgWithLogo.php | 6 +- examples/svgWithLogoAndCustomShapes.php | 8 +-- src/Data/QRMatrix.php | 74 +++++++++++++++---------- src/Output/QROutputInterface.php | 2 + src/QROptionsTrait.php | 4 +- tests/Data/QRMatrixTest.php | 8 +-- 14 files changed, 83 insertions(+), 113 deletions(-) diff --git a/examples/image.php b/examples/image.php index 3da0b887f..e6723b0e5 100644 --- a/examples/image.php +++ b/examples/image.php @@ -25,11 +25,7 @@ 'drawCircularModules' => true, 'drawLightModules' => true, 'circleRadius' => 0.4, - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => ((QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT) << 12), 'moduleValues' => [ // finder QRMatrix::M_FINDER_DARK => [0, 63, 255], // dark (true) diff --git a/examples/imageWithLogo.php b/examples/imageWithLogo.php index 67428ff86..70fbf5e32 100644 --- a/examples/imageWithLogo.php +++ b/examples/imageWithLogo.php @@ -85,7 +85,7 @@ public function dump(string $file = null, string $logo = null):string{ 'imageTransparent' => false, 'drawCircularModules' => true, 'circleRadius' => 0.45, - 'keepAsSquare' => [QRMatrix::M_FINDER, QRMatrix::M_FINDER_DOT], + 'keepAsSquare' => (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT), ]); $qrcode = new QRCode($options); diff --git a/examples/imagick.php b/examples/imagick.php index 4f494f841..384d652f3 100644 --- a/examples/imagick.php +++ b/examples/imagick.php @@ -25,11 +25,7 @@ 'drawLightModules' => true, 'drawCircularModules' => true, 'circleRadius' => 0.4, - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => ((QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT) << 12), 'moduleValues' => [ // finder QRMatrix::M_FINDER_DARK => '#A71111', // dark (true) diff --git a/examples/imagickWithLogo.php b/examples/imagickWithLogo.php index 4f120ea16..964fa003c 100644 --- a/examples/imagickWithLogo.php +++ b/examples/imagickWithLogo.php @@ -108,11 +108,7 @@ protected function set_pngLogo(string $pngLogo):void{ 'drawLightModules' => false, 'drawCircularModules' => true, 'circleRadius' => 0.4, - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => ((QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT) << 12), ]); diff --git a/examples/svg.php b/examples/svg.php index c43f0db84..da36cbca7 100644 --- a/examples/svg.php +++ b/examples/svg.php @@ -33,11 +33,8 @@ // connect paths 'connectPaths' => true, // keep modules of these types as square - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => ((QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT) << 12), +# 'keepAsSquare' => 0b110000010100010000000000, // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient 'svgDefs' => ' diff --git a/examples/svgMeltedModules.php b/examples/svgMeltedModules.php index 4a0808f7e..92dba6e8e 100644 --- a/examples/svgMeltedModules.php +++ b/examples/svgMeltedModules.php @@ -48,7 +48,7 @@ protected function collectModules(Closure $transform):array{ $M_TYPE_LAYER = QRMatrix::M_DATA; if($this->matrix->check($x, $y)){ - $M_TYPE_LAYER |= QRMatrix::IS_DARK; + $M_TYPE_LAYER = QRMatrix::M_DATA_DARK; } } @@ -251,19 +251,16 @@ protected function set_meltRadius(float $meltRadius):void{ 'version' => 7, 'eccLevel' => EccLevel::H, + 'imageBase64' => false, 'addQuietzone' => true, 'addLogoSpace' => true, 'logoSpaceWidth' => 13, 'logoSpaceHeight' => 13, 'connectPaths' => true, - 'imageBase64' => false, + 'excludeFromConnect' => (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT), 'outputType' => QROutputInterface::CUSTOM, 'outputInterface' => MeltedSVGQRCodeOutput::class, - 'excludeFromConnect' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - ], 'svgDefs' => ' diff --git a/examples/svgRandomColoredDots.php b/examples/svgRandomColoredDots.php index 772afe41a..1c4692ef4 100644 --- a/examples/svgRandomColoredDots.php +++ b/examples/svgRandomColoredDots.php @@ -46,21 +46,19 @@ protected function collectModules(Closure $transform):array{ $M_TYPE = $this->matrix->get($x, $y); $M_TYPE_LAYER = $M_TYPE; - if($this->options->connectPaths - && !$this->matrix->checkTypeIn($x, $y, $this->options->excludeFromConnect) - ){ + if($this->options->connectPaths && !$this->matrix->checkTypeIn($x, $y, $this->options->excludeFromConnect)){ // to connect paths we'll redeclare the $M_TYPE_LAYER to data only $M_TYPE_LAYER = QRMatrix::M_DATA; if($this->matrix->check($x, $y)){ - $M_TYPE_LAYER |= QRMatrix::IS_DARK; + $M_TYPE_LAYER = QRMatrix::M_DATA_DARK; } } // randomly assign another $M_TYPE_LAYER for the given types - // note that the layer id has to be an integer value, - // ideally outside the several bitmask values if($M_TYPE_LAYER === QRMatrix::M_DATA_DARK){ + // note that the layer id has to be an integer value, + // ideally outside the several bitmask values $M_TYPE_LAYER = array_rand($this->options->dotColors); } @@ -100,12 +98,12 @@ class RandomDotsOptions extends QROptions{ // our custom dot colors $dotColors = [ - 111 => '#e2453c', - 222 => '#e07e39', - 333 => '#e5d667', - 444 => '#51b95b', - 555 => '#1e72b7', - 666 => '#6f5ba7', + (111 | QRMatrix::IS_DARK) => '#e2453c', + (222 | QRMatrix::IS_DARK) => '#e07e39', + (333 | QRMatrix::IS_DARK) => '#e5d667', + (444 | QRMatrix::IS_DARK) => '#51b95b', + (555 | QRMatrix::IS_DARK) => '#1e72b7', + (666 | QRMatrix::IS_DARK) => '#6f5ba7', ]; // generate the CSS for the several colored layers @@ -134,20 +132,11 @@ class RandomDotsOptions extends QROptions{ 'drawLightModules' => false, 'connectPaths' => true, - 'excludeFromConnect' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'excludeFromConnect' => (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT), 'drawCircularModules' => true, 'circleRadius' => 0.4, - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], - + 'keepAsSquare' => (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT), ]); // dump the output diff --git a/examples/svgRoundQuietzone.php b/examples/svgRoundQuietzone.php index a0a1312a4..a549eb84e 100644 --- a/examples/svgRoundQuietzone.php +++ b/examples/svgRoundQuietzone.php @@ -185,14 +185,14 @@ protected function collectModules(Closure $transform):array{ $M_TYPE_LAYER = QRMatrix::M_DATA; if($this->matrix->check($x, $y)){ - $M_TYPE_LAYER |= QRMatrix::IS_DARK; + $M_TYPE_LAYER = QRMatrix::M_DATA_DARK; } } // randomly assign another $M_TYPE_LAYER for the given types - // note that the layer id has to be an integer value, - // ideally outside the several bitmask values - if($M_TYPE_LAYER === QRMatrix::M_DATA_DARK){ + if($this->matrix->checkType($x, $y, QRMatrix::M_QUIETZONE_DARK)){ + // note that the layer id has to be an integer value, + // ideally outside the several bitmask values $M_TYPE_LAYER = array_rand($this->options->dotColors); } @@ -330,20 +330,11 @@ protected function set_svgLogoScale(float $svgLogoScale):void{ // common SVG options 'svgDefs' => $svgDefs, -// 'connectPaths' => true, // this has been set to "always on" internally - 'excludeFromConnect' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - (QRMatrix::M_QUIETZONE | QRMatrix::IS_DARK), - ], +# 'connectPaths' => true, // this has been set to "always on" internally +# 'excludeFromConnect' => (QRMatrix::M_TIMING_DARK | QRMatrix::M_FORMAT_DARK), 'drawCircularModules' => true, 'circleRadius' => 0.4, - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT), ]); $qrcode = (new QRCode($options))->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ'); diff --git a/examples/svgWithLogo.php b/examples/svgWithLogo.php index 271acb4e2..bce69e5cf 100644 --- a/examples/svgWithLogo.php +++ b/examples/svgWithLogo.php @@ -124,11 +124,7 @@ protected function set_svgLogoScale(float $svgLogoScale):void{ // connect paths 'connectPaths' => true, // keep modules of thhese types as square - 'keepAsSquare' => [ - QRMatrix::M_FINDER_DARK, - QRMatrix::M_FINDER_DOT, - QRMatrix::M_ALIGNMENT_DARK, - ], + 'keepAsSquare' => ((QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT | QRMatrix::M_ALIGNMENT) << 12), // https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient 'svgDefs' => ' diff --git a/examples/svgWithLogoAndCustomShapes.php b/examples/svgWithLogoAndCustomShapes.php index 2f063c190..10ee72462 100644 --- a/examples/svgWithLogoAndCustomShapes.php +++ b/examples/svgWithLogoAndCustomShapes.php @@ -61,12 +61,8 @@ protected function path(string $path, int $M_TYPE):string{ */ protected function module(int $x, int $y, int $M_TYPE):string{ - if( - !$this->matrix->check($x, $y) - // we're skipping the finder patterns here - || $this->matrix->checkType($x, $y, QRMatrix::M_FINDER) - || $this->matrix->checkType($x, $y, QRMatrix::M_FINDER_DOT) - ){ + // we're skipping the finder patterns here + if(!$this->matrix->check($x, $y) || $this->matrix->checkTypeIn($x, $y, (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT))){ return ''; } diff --git a/src/Data/QRMatrix.php b/src/Data/QRMatrix.php index 77fb42675..3bc606f31 100755 --- a/src/Data/QRMatrix.php +++ b/src/Data/QRMatrix.php @@ -22,47 +22,51 @@ class QRMatrix{ /** @var int */ - public const IS_DARK = 0b100000000000; + public const IS_DARK = 0b100000000000000000000000; /** @var int */ - public const M_NULL = 0b000000000000; + public const M_NULL = 0b000000000000000000000000; /** @var int */ - public const M_DARKMODULE = 0b100000000001; + public const M_DARKMODULE = 0b100000000001000000000001; /** @var int */ - public const M_DATA = 0b000000000010; + public const M_DATA = 0b000000000000000000000010; /** @var int */ - public const M_DATA_DARK = 0b100000000010; + public const M_DATA_DARK = 0b100000000010000000000010; /** @var int */ - public const M_FINDER = 0b000000000100; + public const M_FINDER = 0b000000000000000000000100; /** @var int */ - public const M_FINDER_DARK = 0b100000000100; + public const M_FINDER_DARK = 0b100000000100000000000100; /** @var int */ - public const M_SEPARATOR = 0b000000001000; + public const M_SEPARATOR = 0b000000000000000000001000; /** @var int */ - public const M_ALIGNMENT = 0b000000010000; + public const M_ALIGNMENT = 0b000000000000000000010000; /** @var int */ - public const M_ALIGNMENT_DARK = 0b100000010000; + public const M_ALIGNMENT_DARK = 0b100000010000000000010000; /** @var int */ - public const M_TIMING = 0b000000100000; + public const M_TIMING = 0b000000000000000000100000; /** @var int */ - public const M_TIMING_DARK = 0b100000100000; + public const M_TIMING_DARK = 0b100000100000000000100000; /** @var int */ - public const M_FORMAT = 0b000001000000; + public const M_FORMAT = 0b000000000000000001000000; /** @var int */ - public const M_FORMAT_DARK = 0b100001000000; + public const M_FORMAT_DARK = 0b100001000000000001000000; /** @var int */ - public const M_VERSION = 0b000010000000; + public const M_VERSION = 0b000000000000000010000000; /** @var int */ - public const M_VERSION_DARK = 0b100010000000; + public const M_VERSION_DARK = 0b100010000000000010000000; /** @var int */ - public const M_QUIETZONE = 0b000100000000; + public const M_QUIETZONE = 0b000000000000000100000000; /** @var int */ - public const M_LOGO = 0b001000000000; + public const M_QUIETZONE_DARK = 0b100100000000000100000000; /** @var int */ - public const M_FINDER_DOT = 0b110000000000; + public const M_LOGO = 0b000000000000001000000000; /** @var int */ - public const M_TEST = 0b011111111111; + public const M_LOGO_DARK = 0b101000000000001000000000; /** @var int */ - public const M_TEST_DARK = 0b111111111111; + public const M_FINDER_DOT = 0b110000000000010000000000; + /** @var int */ + public const M_TEST = 0b000000000000011111111111; + /** @var int */ + public const M_TEST_DARK = 0b111111111111011111111111; /** * Map of flag => coord @@ -256,15 +260,24 @@ public function get(int $x, int $y):int{ /** * Sets the $M_TYPE value for the module at position [$x, $y] * - * true => $M_TYPE | 0x800 + * true => (self::IS_DARK | ($M_TYPE << 12) | $M_TYPE) * false => $M_TYPE */ public function set(int $x, int $y, bool $value, int $M_TYPE):self{ - if(isset($this->matrix[$y][$x])){ - $this->matrix[$y][$x] = (($M_TYPE & ~$this::IS_DARK) | (($value) ? $this::IS_DARK : 0)); + if(!isset($this->matrix[$y][$x])){ + return $this; + } + + // we'll convert to the basic light value (lowest 11 bits), in case we get passed a dark $M_TYPE value + $val = ($M_TYPE & 0x7ff); + + if($value === true){ + $val = ($this::IS_DARK | ($val << 12) | $val); } + $this->matrix[$y][$x] = $val; + return $this; } @@ -301,15 +314,16 @@ public function checkType(int $x, int $y, int $M_TYPE):bool{ * checks whether the module at ($x, $y) is in the given array of $M_TYPES, * returns true if a match is found, otherwise false. */ - public function checkTypeIn(int $x, int $y, array $M_TYPES):bool{ + public function checkTypeIn(int $x, int $y, int $M_TYPES):bool{ + $val = $this->get($x, $y); - foreach($M_TYPES as $type){ - if($this->checkType($x, $y, $type)){ - return true; - } + if($val === -1){ + return false; } - return false; +# printf("%024b\n%024b\n%024b\n\n", $M_TYPES, $val, (($val & $M_TYPES))); + + return ($val & $M_TYPES & 0x7fffff) > 0; } /** diff --git a/src/Output/QROutputInterface.php b/src/Output/QROutputInterface.php index ee8af95c9..04a931e54 100644 --- a/src/Output/QROutputInterface.php +++ b/src/Output/QROutputInterface.php @@ -82,6 +82,8 @@ interface QROutputInterface{ QRMatrix::M_TIMING_DARK => true, QRMatrix::M_FORMAT_DARK => true, QRMatrix::M_VERSION_DARK => true, + QRMatrix::M_QUIETZONE_DARK => true, + QRMatrix::M_LOGO_DARK => true, QRMatrix::M_FINDER_DOT => true, QRMatrix::M_TEST_DARK => true, ]; diff --git a/src/QROptionsTrait.php b/src/QROptionsTrait.php index 2f596e5f8..38886c42e 100644 --- a/src/QROptionsTrait.php +++ b/src/QROptionsTrait.php @@ -181,7 +181,7 @@ trait QROptionsTrait{ /** * specifies which module types to exclude when $drawCircularModules is set to true */ - protected array $keepAsSquare = []; + protected int $keepAsSquare = 0; /** * whether to connect the paths for the several module types to avoid weird glitches when using gradients etc. @@ -193,7 +193,7 @@ trait QROptionsTrait{ /** * specify which paths/patterns to exclude from connecting if $connectPaths is set to true */ - protected array $excludeFromConnect = []; + protected int $excludeFromConnect = 0; /** * Module values map diff --git a/tests/Data/QRMatrixTest.php b/tests/Data/QRMatrixTest.php index 37385dc3d..f4f3f37fd 100755 --- a/tests/Data/QRMatrixTest.php +++ b/tests/Data/QRMatrixTest.php @@ -250,7 +250,7 @@ public function testSetAlignmentPattern(QRMatrix $matrix):void{ foreach($alignmentPattern as $py){ foreach($alignmentPattern as $px){ // skip finder pattern - if(!$matrix->checkTypeIn($px, $py, [QRMatrix::M_FINDER, QRMatrix::M_FINDER_DOT])){ + if(!$matrix->checkTypeIn($px, $py, (QRMatrix::M_FINDER | QRMatrix::M_FINDER_DOT))){ $this::assertSame(QRMatrix::M_ALIGNMENT_DARK, $matrix->get($px, $py)); } } @@ -278,7 +278,7 @@ public function testSetTimingPattern(QRMatrix $matrix):void{ for($i = 7; $i < ($size - 7); $i++){ if(($i % 2) === 0){ // skip alignment pattern - if(!$matrix->checkTypeIn(6, $i, [QRMatrix::M_ALIGNMENT])){ + if(!$matrix->checkTypeIn(6, $i, (QRMatrix::M_ALIGNMENT))){ $this::assertSame(QRMatrix::M_TIMING_DARK, $matrix->get(6, $i)); $this::assertSame(QRMatrix::M_TIMING_DARK, $matrix->get($i, 6)); } @@ -490,8 +490,8 @@ public function testSetLogoSpaceMaxSizeException():void{ public function testCheckTypeIn():void{ $this->matrix->set(10, 10, true, QRMatrix::M_QUIETZONE); - $this::assertFalse($this->matrix->checkTypeIn(10, 10, [QRMatrix::M_DATA, QRMatrix::M_FINDER])); - $this::assertTrue($this->matrix->checkTypeIn(10, 10, [QRMatrix::M_QUIETZONE, QRMatrix::M_FINDER])); + $this::assertFalse($this->matrix->checkTypeIn(10, 10, (QRMatrix::M_DATA | QRMatrix::M_FINDER))); + $this::assertTrue($this->matrix->checkTypeIn(10, 10, (QRMatrix::M_QUIETZONE | QRMatrix::M_FINDER))); } /**