Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How do I replicate a QR Code with rounded modules and pointy rounded control points with a PNG image overlay? #279

Discussion options

test

How would I replicate this QR code using php-qrcode?

The center Image is a PNG file.

In the generation of the QR code the PNG will be substituted for a PNG image of the avatar of the person who is creating the QR code. Also I would need a High level of error correction.

In the iQR MacOS app they call the control points "centered" and I am using a corner radius of about 80%.

Any help or pointers in how to recreate this QR code is appreciated.

I am using the 5.0.x branch.

I have seen these examples:

  • examples/svgWithLogo.php
  • examples/svgMeltedModules.php

And I have found an ImageMagick Function to convert the PNG image into an SVG.

I am using the Laravel Framework.

protected function pngToSVG() 
{
 // Assuming the logged-in user
 $user = Auth::user();
 $pngBlob = $user->avatar;
 // Create a new Imagick instance from the PNG blob
 $imagick = new Imagick();
 $imagick->readImageBlob($pngBlob);
 // Set the image format to SVG
 $imagick->setImageFormat("svg");
 // Get the SVG content
 $svgContent = $imagick->getImageBlob();
 // Generate a unique ID for the filename
 $uniqueId = Str::uuid()->toString();
 $fileName = $uniqueId . '.svg';
 // Define the path where the file will be stored
 $filePath = 'tmp/' . $fileName;
 // Save the SVG file to the storage/tmp directory
 Storage::disk('local')->put($filePath, $svgContent);
 return $filePath;
}
You must be logged in to vote

I finally got the logo to appear correctly, I set the png image to be 300x300 pixels as a standard size then reduced the size of the png by 13% and then set the height and width on the tag.

 use Intervention\Image\Laravel\Facades\Image;
 $imgScale = 0.13;
 $image = Image::read($logoBlob);
 $pngScaledWidth = $image->width() * $imgScale;
 $pngScaledHeight = $image->height() * $imgScale;
 $embedPng = '<image width="' . $pngScaledWidth . '" height="' . $pngScaledHeight . '" href="data:image/png;base64,' . $logoBlob . '" />';

and this is my getFinderPatterns function

protected function getFinderPatterns():string{
 $qz = ($this->options->ad...

Replies: 1 comment 7 replies

Comment options

Hey, I assume the desired output format is SVG? You can simply embed an image into an SVG document via the <image> element (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image) - similar to the svgWithLogo example, where you'd replace the whole logo SVG string with the <image> tag over here:

file_get_contents($this->options->svgLogo),

Alternatively, you can append the <g ...><image ... /></g> after rendering the SVG (replace the closing </svg> with your image embed and close the SVG again).

You must be logged in to vote
7 replies
Comment options

The relative coordinates of the finder patterns look very large, they should be around 0...7 (absolute size) each.

Comment options

I was able to get the Finder patterns to position correctly. Now I am having issues with the SVG Logo. It is not scaling and positioning properly. is it possible to fill the quietzone area? The SVG Logo is an embedded png in base64. Here is my code so far

namespace App\Services;
use Closure;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use chillerlan\QRCode\Common\EccLevel;
use chillerlan\QRCode\Data\QRMatrix;
use chillerlan\QRCode\Output\QRMarkupSVG;
use chillerlan\QRCode\Output\QROutputInterface;
class QRSvgMeltedWithCustomFinder extends QRMarkupSVG{
 protected function paths():string{
 // make sure connect paths is enabled
 $this->options->connectPaths = true;
 // we're calling QRMatrix::setLogoSpace() manually, so QROptions::$addLogoSpace has no effect here
 $this->matrix->setLogoSpace((int)ceil($this->moduleCount * $this->options->svgLogoScale));
 // generate the path element(s) - in this case it's just one element as we've "disabled" several options
 $svg = parent::paths();
 // add the custom shapes for the finder patterns
 $svg .= $this->getFinderPatterns();
 // and add the custom logo
 $svg .= $this->getLogo();
 return $svg;
 }
 protected function path(string $path, int $M_TYPE):string{
 // omit the "fill" and "opacity" attributes on the path element
 return sprintf('<path class="%s" d="%s"/>', $this->getCssClass($M_TYPE), $path);
 }
 protected function collectModules(Closure $transform):array{
 $paths = [];
 $melt = $this->options->melt; // avoid magic getter in long loops
 // collect the modules for each type
 foreach($this->matrix->getMatrix() as $y => $row){
 foreach($row as $x => $M_TYPE){
 $M_TYPE_LAYER = $M_TYPE;
 if($this->connectPaths && !$this->matrix->checkTypeIn($x, $y, $this->excludeFromConnect)){
 // to connect paths we'll redeclare the $M_TYPE_LAYER to data only
 $M_TYPE_LAYER = QRMatrix::M_DATA;
 if($this->matrix->isDark($M_TYPE)){
 $M_TYPE_LAYER = QRMatrix::M_DATA_DARK;
 }
 }
 // if we're going to "melt" the matrix, we'll declare *all* modules as dark,
 // so that light modules with dark parts are rendered in the same path
 if($melt){
 $M_TYPE_LAYER |= QRMatrix::IS_DARK;
 }
 // collect the modules per $M_TYPE
 $module = $transform($x, $y, $M_TYPE, $M_TYPE_LAYER);
 if(!empty($module)){
 $paths[$M_TYPE_LAYER][] = $module;
 }
 }
 }
 // beautify output
 ksort($paths);
 return $paths;
 }
 protected function module(int $x, int $y, int $M_TYPE):string{
 $bits = $this->matrix->checkNeighbours($x, $y, null);
 $check = fn(int $all, int $any = 0):bool => ($bits & ($all | (~$any & 0xff))) === $all;
 $template = ($M_TYPE & QRMatrix::IS_DARK) === QRMatrix::IS_DARK
 ? $this->darkModule($check, $this->options->inverseMelt)
 : $this->lightModule($check, $this->options->inverseMelt);
 $r = $this->options->meltRadius;
 if(
 !$this->matrix->isDark($M_TYPE)
 // we're skipping the finder patterns here
 || $this->matrix->checkType($x, $y, QRMatrix::M_FINDER)
 || $this->matrix->checkType($x, $y, QRMatrix::M_FINDER_DOT)
 ){
 return '';
 }
 return sprintf($template, $x, $y, $r, (1 - $r), (1 - 2 * $r));
 }
 protected function darkModule(Closure $check, bool $invert):string{
 switch(true){
 // 4 rounded
 case !$invert && $check(0b00000000, 0b01010101):
 case $invert && $check(0b00000000, 0b00000000):
 return 'M%1$s,%2$s m0,%3$s v%5$s q0,%3$s %3$s,%3$s h%5$s q%3$s,0 %3$s,-%3$s v-%5$s q0,-%3$s -%3$s,-%3$s h-%5$s q-%3$s,0 -%3$s,%3$sZ';
 // 3 rounded
 case $invert && $check(0b01000000, 0b00000000): // 135
 return 'M%1$s,%2$s m0,1 h%4$s q%3$s,0 %3$s,-%3$s v-%5$s q0,-%3$s -%3$s,-%3$s h-%5$s q-%3$s,0 -%3$s,%3$sZ';
 case $invert && $check(0b00000001, 0b00000000): // 357
 return 'M%1$s,%2$s v%4$s q0,%3$s %3$s,%3$s h%5$s q%3$s,0 %3$s,-%3$s v-%5$s q0,-%3$s -%3$s,-%3$sZ';
 case $invert && $check(0b00000100, 0b00000000): // 571
 return 'M%1$s,%2$s m1,0 v%4$s q0,%3$s -%3$s,%3$s h-%5$s q-%3$s,0 -%3$s,-%3$s v-%5$s q0,-%3$s %3$s,-%3$sZ';
 case $invert && $check(0b00010000, 0b00000000): // 713
 return 'M%1$s,%2$s m1,1 h-%4$s q-%3$s,0 -%3$s,-%3$s v-%5$s q0,-%3$s %3$s,-%3$s h%5$s q%3$s,0 %3$s,%3$sZ';
 // 2 rounded
 case !$invert && $check(0b00100000, 0b01010101): // 13
 case $invert && $check(0b00000000, 0b01110000):
 return 'M%1$s,%2$s m0,1 h1 v-%4$s q0,-%3$s -%3$s,-%3$s h-%5$s q-%3$s,0 -%3$s,%3$sZ';
 case !$invert && $check(0b10000000, 0b01010101): // 35
 case $invert && $check(0b00000000, 0b11000001):
 return 'M%1$s,%2$s v1 h%4$s q%3$s,0 %3$s,-%3$s v-%5$s q0,-%3$s -%3$s,-%3$sZ';
 case !$invert && $check(0b00000010, 0b01010101): // 57
 case $invert && $check(0b00000000, 0b00000111):
 return 'M%1$s,%2$s v%4$s q0,%3$s %3$s,%3$s h%5$s q%3$s,0 %3$s,-%3$s v-%4$sZ';
 case !$invert && $check(0b00001000, 0b01010101): // 71
 case $invert && $check(0b00000000, 0b00011100):
 return 'M%1$s,%2$s m1,1 v-1 h-%4$s q-%3$s,0 -%3$s,%3$s v%5$s q0,%3$s %3$s,%3$sZ';
 // diagonal
 case $invert && $check(0b01000100, 0b00000000): // 15
 return 'M%1$s,%2$s m0,1 h%4$s q%3$s,0 %3$s,-%3$s v-%4$s h-%4$s q-%3$s,0 -%3$s,%3$sZ';
 case $invert && $check(0b00010001, 0b00000000): // 37
 return 'M%1$s,%2$s h%4$s q%3$s,0 %3$s,%3$s v%4$s h-%4$s q-%3$s,0 -%3$s,-%3$sZ';
 // 1 rounded
 case !$invert && $check(0b00101000, 0b01010101): // 1
 case $invert && $check(0b00000000, 0b01111100):
 return 'M%1$s,%2$s m0,1 h1 v-1 h-%4$s q-%3$s,0 -%3$s,%3$sZ';
 case !$invert && $check(0b10100000, 0b01010101): // 3
 case $invert && $check(0b00000000, 0b11110001):
 return 'M%1$s,%2$s h%4$s q%3$s,0 %3$s,%3$s v%4$s h-1Z';
 case !$invert && $check(0b10000010, 0b01010101): // 5
 case $invert && $check(0b00000000, 0b11000111):
 return 'M%1$s,%2$s h1 v%4$s q0,%3$s -%3$s,%3$s h-%4$sZ';
 case !$invert && $check(0b00001010, 0b01010101): // 7
 case $invert && $check(0b00000000, 0b00011111):
 return 'M%1$s,%2$s v%4$s q0,%3$s %3$s,%3$s h%4$s v-1Z';
 default:
 // full square
 return 'M%1$s,%2$s h1 v1 h-1Z';
 }
 }
 protected function lightModule(Closure $check, bool $invert):string{
 switch(true){
 // 4 rounded
 case !$invert && $check(0b11111111, 0b01010101):
 case $invert && $check(0b10101010, 0b01010101):
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m1,0 v%3$s q0,-%3$s -%3$s,-%3$sz m0,1 h-%3$s q%3$s,0 %3$s,-%3$sz m-1,0 v-%3$s q0,%3$s %3$s,%3$sZ';
 // 3 rounded
 case !$invert && $check(0b10111111, 0b00000000): // 135
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m1,0 v%3$s q0,-%3$s -%3$s,-%3$sz m0,1 h-%3$s q%3$s,0 %3$s,-%3$sZ';
 case !$invert && $check(0b11111110, 0b00000000): // 357
 return 'M%1$s,%2$s m1,0 v%3$s q0,-%3$s -%3$s,-%3$sz m0,1 h-%3$s q%3$s,0 %3$s,-%3$sz m-1,0 v-%3$s q0,%3$s %3$s,%3$sZ';
 case !$invert && $check(0b11111011, 0b00000000): // 571
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m0,1 v-%3$s q0,%3$s %3$s,%3$sz m1,0 h-%3$s q%3$s,0 %3$s,-%3$sZ';
 case !$invert && $check(0b11101111, 0b00000000): // 713
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m0,1 v-%3$s q0,%3$s %3$s,%3$sz m1,-1 v%3$s q0,-%3$s -%3$s,-%3$sZ';
 // 2 rounded
 case !$invert && $check(0b10001111, 0b01110000): // 13
 case $invert && $check(0b10001010, 0b01010101):
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m1,0 v%3$s q0,-%3$s -%3$s,-%3$sZ';
 case !$invert && $check(0b00111110, 0b11000001): // 35
 case $invert && $check(0b00101010, 0b01010101):
 return 'M%1$s,%2$s m1,0 v%3$s q0,-%3$s -%3$s,-%3$sz m0,1 h-%3$s q%3$s,0 %3$s,-%3$sZ';
 case !$invert && $check(0b11111000, 0b00000111): // 57
 case $invert && $check(0b10101000, 0b01010101):
 return 'M%1$s,%2$s m1,1 h-%3$s q%3$s,0 %3$s,-%3$sz m-1,0 v-%3$s q0,%3$s %3$s,%3$sZ';
 case !$invert && $check(0b11100011, 0b00011100): // 71
 case $invert && $check(0b10100010, 0b01010101):
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m0,1 v-%3$s q0,%3$s %3$s,%3$sZ';
 // diagonal
 case !$invert && $check(0b10111011, 0b00000000): // 15
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sz m1,1 h-%3$s q%3$s,0 %3$s,-%3$sZ';
 case !$invert && $check(0b11101110, 0b00000000): // 37
 return 'M%1$s,%2$s m1,0 v%3$s q0,-%3$s -%3$s,-%3$sz m-1,1 v-%3$s q0,%3$s %3$s,%3$sZ';
 // 1 rounded
 case !$invert && $check(0b10000011, 0b01111100): // 1
 case $invert && $check(0b10000010, 0b01010101):
 return 'M%1$s,%2$s h%3$s q-%3$s,0 -%3$s,%3$sZ';
 case !$invert && $check(0b00001110, 0b11110001): // 3
 case $invert && $check(0b00001010, 0b01010101):
 return 'M%1$s,%2$s m1,0 v%3$s q0,-%3$s -%3$s,-%3$sZ';
 case !$invert && $check(0b00111000, 0b11000111): // 5
 case $invert && $check(0b00101000, 0b01010101):
 return 'M%1$s,%2$s m1,1 h-%3$s q%3$s,0 %3$s,-%3$sZ';
 case !$invert && $check(0b11100000, 0b00011111): // 7
 case $invert && $check(0b10100000, 0b01010101):
 return 'M%1$s,%2$s m0,1 v-%3$s q0,%3$s %3$s,%3$sZ';
 default:
 // empty block
 return '';
 }
 }
 protected function getFinderPatterns():string{
 $qz = ($this->options->addQuietzone) ? $this->options->quietzoneSize : 0;
 // the positions for the finder patterns (top left corner)
 // $this->moduleCount includes 2* the quiet zone size already, so we need to take this into account
 $pos = [
 [(0 + $qz), (0 + $qz)],
 [(0 + $qz), ($this->moduleCount - $qz - 7)],
 [($this->moduleCount - $qz - 7), (0 + $qz)],
 ];
 // the custom paths for the finder pattern - the first move (M) is parametrized, the rest are relative coordinates. This is in order of top left, top right, bottom left.
 // Bottom Left
 $path[1] = 'M%1$s,%2$s m2,0 c-0.96,0,-1.73,0.77,-1.73,1.73v3.54c0,0.96,0.77,1.73,1.73,1.73h5.27v-5.27c0,-0.96,-0.77,-1.73,-1.73,-1.73zm4.27,1.73v4.27h-4.27c-0.4,0,-0.73,-0.33,-0.73,-0.73v-3.54c0,-0.4,0.33,-0.73,0.73,-0.73h3.54c0.4,0,0.73,0.33,0.73,0.73zm-3.4,0.27c-0.33,0,-0.6,0.27,-0.6,0.6v1.8c0,0.33,0.27,0.6,0.6,0.6h2.4v-2.4c0,-0.33,-0.27,-0.6,-0.6,-0.6z';
 // Top Left
 $path[2] = 'M%1$s,%2$s m2,7 c-0.96,0,-1.73,-0.77,-1.73,-1.73v-3.54c0,-0.96,0.77,-1.73,1.73,-1.73h5.27v5.27c0,0.96,-0.77,1.73,-1.73,1.73zm4.27,-1.73v-4.27h-4.27c-0.4,0,-0.73,0.33,-0.73,0.73v3.54c0,0.4,0.33,0.73,0.73,0.73h3.54c0.4,0,0.73,-0.33,0.73,-0.73zm-3.4,-0.27c-0.33,0,-0.6,-0.27,-0.6,-0.6v-1.8c0,-0.33,0.27,-0.6,0.6,-0.6h2.4v2.4c0,0.33,-0.27,0.6,-0.6,0.6z';
 
 // Top Right
 $path[3] = 'M%1$s,%2$s m5,0 c0.96,0,1.73,0.77,1.73,1.73v3.54c0,0.96,-0.77,1.73,-1.73,1.73h-5.27v-5.27c0,-0.96,0.77,-1.73,1.73,-1.73zm-4.27,1.73v4.27h4.27c0.4,0,0.73,-0.33,0.73,-0.73v-3.54c0,-0.4,-0.33,-0.73,-0.73,-0.73h-3.54c-0.4,0,-0.73,0.33,-0.73,0.73zm3.4,0.27c0.33,0,0.6,0.27,0.6,0.6v1.8c0,0.33,-0.27,0.6,-0.6,0.6h-2.4v-2.4c0,-0.33,0.27,-0.6,0.6,-0.6z';
 $finder = [];
 $z = 1;
 foreach($pos as [$ix, $iy]){
 $finder[] = sprintf($path[$z], $ix, $iy);
 $z += 1;
 }
 return sprintf(
 '%s<path class="%s" d="%s"/>',
 $this->options->eol,
 $this->getCssClass(QRMatrix::M_FINDER_DARK),
 implode('', $finder)
 );
 }
 protected function getLogo():string{
 // @todo: customize the <g> element to your liking (css class, style...)
 return sprintf(
 '%5$s<g transform="translate(%1$s %1$s) scale(%2$s)" class="%3$s">%5$s %4$s%5$s</g>',
 (($this->moduleCount - ($this->moduleCount * $this->options->svgLogoScale)) / 2),
 $this->options->svgLogoScale,
 $this->options->svgLogoCssClass,
 $this->options->svgLogo,
 $this->options->eol
 );
 }
}
class QRSvgMeltedWithCustomFinderOptions extends QROptions{
 // path to svg logo
 protected string $svgLogo;
 // logo scale in % of QR Code size, clamped to 10%-30%
 protected float $svgLogoScale = 0.20;
 // css class for the logo (defined in $svgDefs)
 protected string $svgLogoCssClass = ''; 
 // enable the melt effect
 protected bool $melt = false;
 // whether to let the melt effect flow along the dark or light modules
 protected bool $inverseMelt = false;
 // the corner radius for melted modules
 protected float $meltRadius = 0.15;
 // clamp/set melt corner radius
 protected function set_meltRadius(float $meltRadius):void{
 $this->meltRadius = max(0.01, min(0.5, $meltRadius));
 }
 // check logo
 protected function set_svgLogo(string $svgLogo):void{
 #if(!file_exists($svgLogo) || !is_readable($svgLogo)){
 # throw new QRCodeException('invalid svg logo');
 #}
 // @todo: validate svg
 $this->svgLogo = $svgLogo;
 }
 // clamp logo scale
 protected function set_svgLogoScale(float $svgLogoScale):void{
 $this->svgLogoScale = max(0.05, min(0.3, $svgLogoScale));
 }
}
class QRCodeService
{
 public function generateQRCode(string $data, string $logoBlob = null): string
 {
 $options = new QRSvgMeltedWithCustomFinderOptions;
 // SVG Logo Options
 $options->svgLogo = '<image href="data:image/png;base64,'.$logoBlob.'" />';
 $options->svgLogoScale = 0.3;
 $options->svgLogoCssClass = 'qr-logo dark';
 // settings from the custom options class
 $options->version = 5;
 $options->quietzoneSize = 4; 
 $options->melt = true;
 $options->inverseMelt = false;
 $options->meltRadius = 0.4;
 $options->outputType = QROutputInterface::CUSTOM;
 $options->outputInterface = QRSvgMeltedWithCustomFinder::class;
 $options->outputBase64 = false;
 $options->eccLevel = EccLevel::H;
 $options->addQuietzone = true;
 $options->svgDefs = '
 <linearGradient id="rainbow" x1="100%" y2="100%">
 <stop stop-color="#e2453c" offset="2.5%"/>
 <stop stop-color="#e07e39" offset="21.5%"/>
 <stop stop-color="#e5d667" offset="40.5%"/>
 <stop stop-color="#51b95b" offset="59.5%"/>
 <stop stop-color="#1e72b7" offset="78.5%"/>
 <stop stop-color="#6f5ba7" offset="97.5%"/>
 </linearGradient>
 <style><![CDATA[
 .light, .dark{fill: url(#rainbow);}
 ]]></style>';
 $svg = (new QRCode($options))->render($data);
 return $svg;
 }
}

Here is my latest QR code SVG:

print

Comment options

I think the <image> element needs the width and height attributes (I'm not an SVG expert though, you might need to experiment a bit with these attributes and translate/scale).

Comment options

I finally got the logo to appear correctly, I set the png image to be 300x300 pixels as a standard size then reduced the size of the png by 13% and then set the height and width on the tag.

 use Intervention\Image\Laravel\Facades\Image;
 $imgScale = 0.13;
 $image = Image::read($logoBlob);
 $pngScaledWidth = $image->width() * $imgScale;
 $pngScaledHeight = $image->height() * $imgScale;
 $embedPng = '<image width="' . $pngScaledWidth . '" height="' . $pngScaledHeight . '" href="data:image/png;base64,' . $logoBlob . '" />';

and this is my getFinderPatterns function

protected function getFinderPatterns():string{
 $qz = ($this->options->addQuietzone) ? $this->options->quietzoneSize : 0;
 // the positions for the finder patterns (top left corner)
 // $this->moduleCount includes 2* the quiet zone size already, so we need to take this into account
 $pos = [
 [(0 + $qz), (0 + $qz)],
 [(0 + $qz), ($this->moduleCount - $qz - 7)],
 [($this->moduleCount - $qz - 7), (0 + $qz)],
 ];
 // the custom paths for the finder pattern - the first move (M) is parametrized, the rest are relative coordinates. This is in order of top left, top right, bottom left.
 // Bottom Left
 $path[1] = 'M%1$s,%2$s m2,0 c-0.96,0,-1.73,0.77,-1.73,1.73v3.54c0,0.96,0.77,1.73,1.73,1.73h5.27v-5.27c0,-0.96,-0.77,-1.73,-1.73,-1.73zm4.27,1.73v4.27h-4.27c-0.4,0,-0.73,-0.33,-0.73,-0.73v-3.54c0,-0.4,0.33,-0.73,0.73,-0.73h3.54c0.4,0,0.73,0.33,0.73,0.73zm-3.4,0.27c-0.33,0,-0.6,0.27,-0.6,0.6v1.8c0,0.33,0.27,0.6,0.6,0.6h2.4v-2.4c0,-0.33,-0.27,-0.6,-0.6,-0.6z';
 // Top Left
 $path[2] = 'M%1$s,%2$s m2,7 c-0.96,0,-1.73,-0.77,-1.73,-1.73v-3.54c0,-0.96,0.77,-1.73,1.73,-1.73h5.27v5.27c0,0.96,-0.77,1.73,-1.73,1.73zm4.27,-1.73v-4.27h-4.27c-0.4,0,-0.73,0.33,-0.73,0.73v3.54c0,0.4,0.33,0.73,0.73,0.73h3.54c0.4,0,0.73,-0.33,0.73,-0.73zm-3.4,-0.27c-0.33,0,-0.6,-0.27,-0.6,-0.6v-1.8c0,-0.33,0.27,-0.6,0.6,-0.6h2.4v2.4c0,0.33,-0.27,0.6,-0.6,0.6z';
 // Top Right
 $path[3] = 'M%1$s,%2$s m5,0 c0.96,0,1.73,0.77,1.73,1.73v3.54c0,0.96,-0.77,1.73,-1.73,1.73h-5.27v-5.27c0,-0.96,0.77,-1.73,1.73,-1.73zm-4.27,1.73v4.27h4.27c0.4,0,0.73,-0.33,0.73,-0.73v-3.54c0,-0.4,-0.33,-0.73,-0.73,-0.73h-3.54c-0.4,0,-0.73,0.33,-0.73,0.73zm3.4,0.27c0.33,0,0.6,0.27,0.6,0.6v1.8c0,0.33,-0.27,0.6,-0.6,0.6h-2.4v-2.4c0,-0.33,0.27,-0.6,0.6,-0.6z';
 $finder = [];
 $z = 1;
 foreach($pos as [$ix, $iy]){
 $finder[] = sprintf($path[$z], $ix, $iy);
 $z += 1;
 }
 return sprintf(
 '%s<path class="%s" d="%s"/>',
 $this->options->eol,
 $this->getCssClass(QRMatrix::M_FINDER_DARK),
 implode(' ', $finder)
 );
 }
Answer selected by spacemunkey77
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet

AltStyle によって変換されたページ (->オリジナル) /