:octocat: circular modules in GD output

This commit is contained in:
codemasher
2021-12-10 00:00:36 +01:00
parent e5948ade90
commit 9b54d1d565
5 changed files with 75 additions and 38 deletions
+30 -18
View File
@@ -11,51 +11,63 @@ namespace chillerlan\QRCodeExamples;
use chillerlan\QRCode\{QRCode, QROptions};
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\Common\EccLevel;
use Throwable;
require_once __DIR__.'/../vendor/autoload.php';
$data = 'https://www.youtube.com/watch?v=DLzxrzFCyOs&t=43s';
$options = new QROptions([
'version' => 5,
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
'eccLevel' => EccLevel::L,
'scale' => 5,
'imageBase64' => false,
'moduleValues' => [
'version' => 7,
'outputType' => QRCode::OUTPUT_IMAGE_PNG,
'eccLevel' => EccLevel::L,
'scale' => 10,
'imageBase64' => false,
'imageTransparent' => false,
'drawCircularModules' => true,
'circleRadius' => 0.4,
'keepAsSquare' => [QRMatrix::M_FINDER|QRMatrix::IS_DARK, QRMatrix::M_FINDER_DOT, QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK],
'moduleValues' => [
// finder
QRMatrix::M_FINDER | QRMatrix::IS_DARK => [0, 63, 255], // dark (true)
QRMatrix::M_FINDER => [255, 255, 255], // light (false), white is the transparency color and is enabled by default
QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => [241, 28, 163], // finder dot, dark (true)
QRMatrix::M_FINDER => [233, 233, 233], // light (false), white is the transparency color and is enabled by default
QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => [0, 63, 255], // finder dot, dark (true)
// alignment
QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => [255, 0, 255],
QRMatrix::M_ALIGNMENT => [255, 255, 255],
QRMatrix::M_ALIGNMENT => [233, 233, 233],
// timing
QRMatrix::M_TIMING | QRMatrix::IS_DARK => [255, 0, 0],
QRMatrix::M_TIMING => [255, 255, 255],
QRMatrix::M_TIMING => [233, 233, 233],
// format
QRMatrix::M_FORMAT | QRMatrix::IS_DARK => [67, 99, 84],
QRMatrix::M_FORMAT => [255, 255, 255],
QRMatrix::M_FORMAT | QRMatrix::IS_DARK => [67, 159, 84],
QRMatrix::M_FORMAT => [233, 233, 233],
// version
QRMatrix::M_VERSION | QRMatrix::IS_DARK => [62, 174, 190],
QRMatrix::M_VERSION => [255, 255, 255],
QRMatrix::M_VERSION => [233, 233, 233],
// data
QRMatrix::M_DATA | QRMatrix::IS_DARK => [0, 0, 0],
QRMatrix::M_DATA => [255, 255, 255],
QRMatrix::M_DATA => [233, 233, 233],
// darkmodule
QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => [0, 0, 0],
// separator
QRMatrix::M_SEPARATOR => [255, 255, 255],
QRMatrix::M_SEPARATOR => [233, 233, 233],
// quietzone
QRMatrix::M_QUIETZONE => [255, 255, 255],
QRMatrix::M_QUIETZONE => [233, 233, 233],
// logo (requires a call to QRMatrix::setLogoSpace()), see QRImageWithLogo
QRMatrix::M_LOGO => [255, 255, 255],
QRMatrix::M_LOGO => [233, 233, 233],
],
]);
try{
$im = (new QRCode($options))->render($data);
}
catch(Throwable $e){
exit($e->getMessage());
}
header('Content-type: image/png');
echo (new QRCode($options))->render($data);
echo $im;
+3 -3
View File
@@ -29,10 +29,10 @@ $options = new QROptions([
'markupDark' => '',
'markupLight' => '',
// draw the modules as circles isntead of squares
'svgDrawCircularModules' => true,
'svgCircleRadius' => 0.3,
'drawCircularModules' => true,
'circleRadius' => 0.4,
// keep modules of thhese types as square
'svgKeepAsSquare' => [QRMatrix::M_FINDER|QRMatrix::IS_DARK, QRMatrix::M_FINDER_DOT, QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK],
'keepAsSquare' => [QRMatrix::M_FINDER|QRMatrix::IS_DARK, QRMatrix::M_FINDER_DOT, QRMatrix::M_ALIGNMENT|QRMatrix::IS_DARK],
// connect
'svgConnectPaths' => true,
// https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient
+35 -12
View File
@@ -17,9 +17,10 @@ use chillerlan\QRCode\QRCode;
use chillerlan\Settings\SettingsContainerInterface;
use Exception;
use function array_values, call_user_func, count, extension_loaded, imagecolorallocate, imagecolortransparent,
imagecreatetruecolor, imagedestroy, imagefilledrectangle, imagegif, imagejpeg, imagepng, in_array,
use function array_values, count, extension_loaded, imagecolorallocate, imagecolortransparent, imagecreatetruecolor,
imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, in_array,
is_array, ob_end_clean, ob_get_contents, ob_start, range;
use const IMG_BICUBIC;
/**
* Converts the matrix into GD images, raw or base64 output (requires ext-gd)
@@ -93,6 +94,12 @@ class QRImage extends QROutputAbstract{
public function dump(string $file = null){
$file ??= $this->options->cachefile;
// we're scaling the image up in order to draw crisp round circles, otherwise they appear square-y on small scales
if($this->options->drawCircularModules && $this->options->scale <= 20){
$this->length = ($this->length + 2) * 10;
$this->scale *= 10;
}
$this->image = imagecreatetruecolor($this->length, $this->length);
// avoid: "Indirect modification of overloaded property $imageTransparencyBG has no effect"
@@ -113,6 +120,11 @@ class QRImage extends QROutputAbstract{
}
}
// scale down to the expected size
if($this->options->drawCircularModules && $this->options->scale <= 20){
$this->image = imagescale($this->image, $this->length/10, $this->length/10, IMG_BICUBIC);
}
if($this->options->returnResource){
return $this->image;
}
@@ -134,15 +146,26 @@ class QRImage extends QROutputAbstract{
* Creates a single QR pixel with the given settings
*/
protected function setPixel(int $x, int $y, int $M_TYPE):void{
imagefilledrectangle(
$this->image,
$x * $this->scale,
$y * $this->scale,
($x + 1) * $this->scale,
($y + 1) * $this->scale,
/** @phan-suppress-next-line PhanParamTooFewInternalUnpack */
imagecolorallocate($this->image, ...$this->moduleValues[$M_TYPE])
);
/** @phan-suppress-next-line PhanParamTooFewInternalUnpack */
$color = imagecolorallocate($this->image, ...$this->moduleValues[$M_TYPE]);
$this->options->drawCircularModules && !$this->matrix->checkTypes($x, $y, $this->options->keepAsSquare)
? imagefilledellipse(
$this->image,
($x * $this->scale) + ($this->scale / 2),
($y * $this->scale) + ($this->scale / 2),
2 * $this->options->circleRadius * $this->scale,
2 * $this->options->circleRadius * $this->scale,
$color
)
: imagefilledrectangle(
$this->image,
$x * $this->scale,
$y * $this->scale,
($x + 1) * $this->scale,
($y + 1) * $this->scale,
$color
);
}
/**
@@ -154,7 +177,7 @@ class QRImage extends QROutputAbstract{
ob_start();
try{
call_user_func([$this, $this->outputMode ?? $this->defaultMode]);
$this->{$this->outputMode ?? $this->defaultMode}();
}
// not going to cover edge cases
// @codeCoverageIgnoreStart
+2 -2
View File
@@ -189,8 +189,8 @@ class QRMarkup extends QROutputAbstract{
return '';
}
if($this->options->svgDrawCircularModules && !$this->matrix->checkTypes($x, $y, $this->options->svgKeepAsSquare)){
$r = $this->options->svgCircleRadius;
if($this->options->drawCircularModules && !$this->matrix->checkTypes($x, $y, $this->options->keepAsSquare)){
$r = $this->options->circleRadius;
return sprintf(
'M%1$s %2$s a%3$s %3$s 0 1 0 %4$s 0 a%3$s,%3$s 0 1 0 -%4$s 0Z',
+5 -3
View File
@@ -162,18 +162,20 @@ trait QROptionsTrait{
/**
* specify whether to draw the modules as filled circles
*
* @see https://github.com/chillerlan/php-qrcode/issues/23
*/
protected bool $svgDrawCircularModules = false;
protected bool $drawCircularModules = false;
/**
* specifies the radius of the modules when $svgDrawCircularModules is set to true
*/
protected float $svgCircleRadius = 0.45;
protected float $circleRadius = 0.45;
/**
* specifies which module types to exclude when $svgDrawCircularModules is set to true
*/
protected array $svgKeepAsSquare = [];
protected array $keepAsSquare = [];
/**
* string substitute for dark