# Module values

## Basics

The QR Code matrix is a 2-dimensional array of numerical values that hold a bitmask for each QR pixel (“module” as per specification), the so-called “module type” or `$M_TYPE`, which is represented by the `QRMatrix::M_*` constants. The bitmask is 12 bits wide; the first 11 bits stand for the pattern type, the highest bit designates whether the module is dark or light. 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 (values with “_DARK” and “_LIGHT” suffix are for convenience):

    $options->moduleValues = [
    	// light
    	QRMatrix::M_NULL             => false, // special value - always 0
    	QRMatrix::M_DARKMODULE_LIGHT => false, // key equivalent to (QRMatrix::M_DARKMODULE & ~QRMatrix::IS_DARK)
    	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,
    	// dark
    	QRMatrix::M_DARKMODULE       => true,
    	QRMatrix::M_DATA_DARK        => true, // key equivalent to (QRMatrix::M_DATA | QRMatrix::IS_DARK)
    	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,
    ];

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]);
    	}
    }