Module values
+Basics
+The QR Code matrix is a 2-dimensional array of numerical values that hold a bit mask for
+each QR pixel (“module” as per specification), the so-called “module type” or $M_TYPE, which is represented by
+the QRMatrix::M_* constants.
+You can assign different values for the several function patterns to colorize them or even draw pixel-art.
Assigning values
+To map the values and properly render the modules for the given QROutputInterface, it may be necessary to overwrite the
+default values,
+that are replaced by the user defined values in QROptions::$moduleValues during the render process.
The map of QRMatrix::M_* constants => default values looks similar to the following:
$options->moduleValues = [
+ // light
+ QRMatrix::M_NULL => false,
+ QRMatrix::M_DARKMODULE_LIGHT => false,
+ QRMatrix::M_DATA => false,
+ QRMatrix::M_FINDER => false,
+ QRMatrix::M_SEPARATOR => false,
+ QRMatrix::M_ALIGNMENT => false,
+ QRMatrix::M_TIMING => false,
+ QRMatrix::M_FORMAT => false,
+ QRMatrix::M_VERSION => false,
+ QRMatrix::M_QUIETZONE => false,
+ QRMatrix::M_LOGO => false,
+ QRMatrix::M_FINDER_DOT_LIGHT => false,
+ QRMatrix::M_TEST => false,
+ // dark
+ QRMatrix::M_DARKMODULE => true,
+ QRMatrix::M_DATA_DARK => true,
+ QRMatrix::M_FINDER_DARK => true,
+ QRMatrix::M_SEPARATOR_DARK => true,
+ QRMatrix::M_ALIGNMENT_DARK => true,
+ 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,
+];
+Not all the module values need to be specified - missing values will be filled with the internal default values
+for true (dark) and false (light) respectively. The QROutputInterface inheritors implement a moduleValueIsValid()
+method that checks if the given value is valid for that particular class:
// set an initial value that acts as default
+$dark = 'rgba(0, 0, 0, 0.5)';
+
+// try to receive user input
+if(QRMarkupSVG::moduleValueIsValid($_GET['qr_dark'])){
+ // module values for HTML, SVG and other markup may need special treatment,
+ // e.g. only accept hexadecimal values from user input
+ // as moduleValueIsValid() just checks for the general syntax
+ $dark = sanitize_user_input($_GET['qr_dark']);
+}
+
+$options->moduleValues = [
+ QRMatrix::M_DATA_DARK => $dark,
+ QRMatrix::M_FINDER_DARK => $dark,
+ QRMatrix::M_ALIGNMENT_DARK => $dark,
+ QRMatrix::M_FINDER_DOT => $dark,
+];
+The several output classes may need different substitute values (you can find examples in the test moduleValueProvider() for each output class):
// for HTML, SVG and ImageMagick
+$options->moduleValues = [
+ QRMatrix::M_DATA => '#ffffff',
+ QRMatrix::M_DATA_DARK => '#000000',
+ // ...
+];
+
+// for the GdImage, EPS and FPDF output types
+$options->moduleValues = [
+ QRMatrix::M_DATA => [255, 255, 255],
+ QRMatrix::M_DATA_DARK => [0, 0, 0],
+ // ...
+];
+
+// for string/text output
+$options->moduleValues = [
+ QRMatrix::M_DATA => '░░',
+ QRMatrix::M_DATA_DARK => '██',
+ // ...
+];
+Handling in your own QROutputInterface
+Setting module values
+QROutputAbstract::setModuleValues()
+calls the 3 abstract methods moduleValueIsValid(), getModuleValue() and getDefaultModuleValue() to fill the internal
+module value map with the values given via QROptions::$moduleValues:
protected function setModuleValues():void{
+
+ foreach($this::DEFAULT_MODULE_VALUES as $M_TYPE => $defaultValue){
+ $value = ($this->options->moduleValues[$M_TYPE] ?? null);
+
+ $this->moduleValues[$M_TYPE] = $this->moduleValueIsValid($value)
+ ? $this->getModuleValue($value)
+ : $this->getDefaultModuleValue($defaultValue);
+ }
+
+}
+In the following example we’ll create these methods for the GdImage output.
+Since imagecolorallocate() and other GD functions accept 3 values
+for RGB color (or 4 in case of RGBA), we’ll supply these as a array where each value is an integer between 0 and 255 ([RRR, GGG, BBB, (, AAA)]).
First we need to validate the input:
+protected function moduleValueIsValid($value):bool{
+
+ // nowhere near valid
+ if(!is_array($value) || count($value) !== 3){
+ return false;
+ }
+
+ // now iterate over the values
+ foreach($value as $color){
+
+ // non-integers won't work
+ if(!is_int($color)){
+ return false;
+ }
+
+ // a strict check - we could also just ignore outliers and clamp the values instead
+ if($color < 0 || $color > 255){
+ return false;
+ }
+ }
+
+ return true; // yay!
+}
+Now we can prepare the value:
+protected function getModuleValue($value):array{
+ // we call array_values() so we don't run into string-key related issues
+ return array_map(fn(int $val):int => max(0, min(255, $val)), array_values($value));
+}
+And finally we need to provide default values:
+protected function getDefaultModuleValue(bool $isDark):array{
+ return $isDark ? [0, 0, 0] : [255, 255, 255];
+}
+Now that everything is ready and set, we can use the values in our GD functions:
+$color = imagecolorallocate($this->image, ...$this->moduleValues[$M_TYPE]);
+Using the module values
+The state of the $M_TYPE is set with the QRMatrix::IS_DARK constant:
// set to dark (true) with bitwise OR:
+$M_TYPE = ($M_TYPE | QRMatrix::IS_DARK);
+
+// set to light (false) with bitwise AND NOT
+$M_TYPE = ($M_TYPE & ~QRMatrix::IS_DARK);
+
+// toggle the opposite state with bitwise XOR
+$M_TYPE = ($M_TYPE ^ QRMatrix::IS_DARK);
+You can manually check whether the module is dark:
+($value & QRMatrix::IS_DARK) === QRMatrix::IS_DARK;
+However it is much more convenient to use the QRMatrix methods for that:
for($y = 0; $y < $this->moduleCount; $y++){ // rows
+ for($x = 0; $x < $this->moduleCount; $x++){ // columns
+ // sets current module as dark (true) with the M_DATA type
+ $this->matrix->set($x, $y, true, QRMatrix::M_DATA);
+
+ // -> true (shortcut for checkType($x, $y, QRMatrix::IS_DARK))
+ $this->matrix->check($x, $y);
+
+ // -> true (current module is of type M_DATA)
+ $this->matrix->checkType($x, $y, QRMatrix::M_DATA);
+
+ // -> true (current module is of type IS_DARK)
+ $this->matrix->checkType($x, $y, QRMatrix::IS_DARK);
+
+ // -> false, type is M_DATA
+ $this->matrix->checkTypeIn($x, $y, [QRMatrix::M_FINDER_DARK, QRMatrix::M_ALIGNMENT]);
+ }
+}
+