# Advanced usage

## Configuration via `QROptions`

The `QROptions` class is a container based on chillerlan/php-settings-container that behaves similar to a `\stdClass` object, but with fixed properties. A list with all available `QROptions` can be found under configuration settings.

    $options = new QROptions;

    // set some values
    $options->version = 7;     // property "version" exists
    $options->foo     = 'bar'; // property "foo" does not exist (and will not be created)

    // retrieve values
    var_dump($options->version); // -> 7
    var_dump($options->foo);     // -> null (no error will be thrown)

### Supply an `iterable` of options

The constructor takes an `iterable` of `$key => $value` pairs. For each setting an optional setter will be called if present.

    $myOptions = [
    	'version'    => 5,
    	'outputType' => QROutputInterface::GDIMAGE_PNG,
    	'eccLevel'   => EccLevel::M,
    ];

    $options = new QROptions($myOptions);

You can also set an `iterable` of options on an existing QROptions instance:

    $options->fromIterable($myOptions);

### Load and save options from/to JSON

The settings can be saved to and loaded from JSON, e.g. to store them in a database:

    $json = $options->toJSON(JSON_THROW_ON_ERROR);
    // via JsonSerializable interface
    $json = json_encode($options, JSON_THROW_ON_ERROR);
    // via __toString()
    $json = (string)$options;

    $options = (new QROptions)->fromJSON($json);
    // on an existing instance - properties will be overwriten
    $options->fromJSON($json);

### Extending the `QROptions` class

In case you need additional settings for your output module, just extend `QROptions`…

    class MyCustomOptions extends QROptions{
    	protected string $myParam = 'defaultValue';
    	// ...
    }

…or use the `SettingsContainerInterface`, which is the more flexible approach.

    trait MyCustomOptionsTrait{
    	protected string $myParam = 'defaultValue';
    	// ...

    	// an optional magic setter, named "set_" + property name
    	protected function set_myParam(string $myParam):void{
    		$this->myParam = trim($myParam);
    	}

    	// an optional magic getter, named "get_" + property name
    	protected function get_myParam():string{
    		return strtoupper($this->myParam);
    	}
    }

    class MyCustomOptions extends SettingsContainerAbstract{
    	use QROptionsTrait, MyCustomOptionsTrait;
    }

    // set the options
    $myCustomOptions = new MyCustomOptions;
    $myCustomOptions->myParam = 'whatever value';

Extend the `SettingsContainerInterface` on-the-fly:

    $myOptions = [
    	'myParam' => 'whatever value',
    	// ...
    ];

    $myCustomOptions = new class($myOptions) extends SettingsContainerAbstract{
    	use QROptionsTrait, MyCustomOptionsTrait;
    };

## `QRCode` methods

Aside of invoking a `QRCode` instance with an optional `QROptions` object as parameter, you can also set the options instance after invocation. After invocation of the `QROptions` instance, values can be set without calling `QRCode::setOptions()` again (instance is backreferenced), however, this may create side effects.

    // instance will be invoked with default settings
    $qrcode  = new QRCode;

    // set options after QRCode invocation
    $options = new QROptions;

    $qrcode->setOptions($options);

### Render a `QRMatrix` instance

You can render a `QRMatrix` instance directly:

    // a matrix from the current data segments
    $matrix = $qrcode->getQRMatrix();
    // from the QR Code reader
    $matrix = $readerResult->getQRMatrix();
    // manually invoked
    $matrix = (new QRMatrix(new Version(7), new EccLevel(EccLevel::M)))->initFunctionalPatterns();

    $output = $qrcode->renderMatrix($matrix);
    // save to file
    $qrcode->renderMatrix($matrix, '/path/to/qrcode.svg');

### Mixed mode

Mixed mode QR Codes can be generated by adding several data segments:

    // make sure to set a proper internal encoding character set
    // ideally, this should be set in php.ini internal_encoding,
    // default_charset or mbstring.internal_encoding
    mb_internal_encoding('UTF-8');

    // clear any existing data segments
    $qrcode->clearSegments();

    $qrcode
    	->addNumericSegment($numericData)
    	->addAlphaNumSegment($alphaNumData)
    	->addKanjiSegment($kanjiData)
    	->addHanziSegment($hanziData)
    	->addByteSegment($binaryData)
    	->addEciSegment(ECICharset::GB18030, $encodedEciData)
    ;

    $output = $qrcode->render();
    // render to file
    $qrcode->render(null, '/path/to/qrcode.svg');

The `QRDataModeInterface` offers the `validateString()` method (implemended for `AlphaNum`, `Byte`, `Hanzi`, `Kanji` and `Number`). This method is used internally when a data mode is invoked, but it can come in handy if you need to check input data beforehand.

    if(!Hanzi::validateString($data)){
    	throw new Exception('invalid GB2312 data');
    }

    $qrcode->addHanziSegment($data);

### QR Code reader

In some cases it might be necessary to increase the contrast of a QR Code image:

    $options->readerUseImagickIfAvailable = true;
    $options->readerIncreaseContrast      = true;
    $options->readerGrayscale             = true;

    $qrcode = new QRCode($options);

    $result = $qrcode->readFromFile('path/to/qrcode.png');
    $result = $qrcode->readFromBlob($imagedata);

The `QRMatrix` object from the `DecoderResult` can be reused:

    $matrix = $result->getQRMatrix();

    // ...matrix modification...

    $output = (new QRCode($options))->renderMatrix($matrix);

    // ...output

## Common output options

### Save to file

You can specify an output file path in which the QR Code content is stored:

    $options->outputBase64 = false;
    $options->cachefile    = '/path/to/qrcode.svg';

    $qrcode->render($data);

    printf('<img src="%s" alt="QR Code" />', $options->cachefile);

The file path can also be supplied as second parameter to the render methods (this will override the `QROptions::$cachefile` setting):

    $qrcode->render($data, '/path/to/qrcode.svg');

### Base64 URI output

By default, a Base64 encoded data URI will be returned (where applicable):

    echo $qrcode->render($data); // -> data:image/png;base64,...

Disable Base64 output:

    $options->outputBase64 = false;

    header('Content-type: image/png');

    echo $qrcode->render($data);

### Return the image resource

In some cases you might want to modify the QR image after creation (without crating a custom output class), in which case you want the internal image resource rather than the final output.

    $options->outputType     = QROutputInterface::IMAGICK;
    $options->returnResource = true;

    /** @var Imagick $imagick */
    $imagick = $qrcode->render($data);

    echo $imagick->getImageBlob();

### Add a logo space

    $options->addLogoSpace    = true;
    $options->logoSpaceWidth  = 9;
    $options->logoSpaceHeight = 9;
    $options->logoSpaceStartX = 10;
    $options->logoSpaceStartY = 10;