Skip to content

Commit f88b53a

Browse files
authored
Added an example with png rounded modules using gd (#215)
* added example with png rounded modules * code formatting and removing of example image
1 parent 017b163 commit f88b53a

File tree

2 files changed

+223
-0
lines changed

2 files changed

+223
-0
lines changed

examples/Readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- [Custom output](./custom_output.php): a simple example that demonstrates the usage of custom output classes
2020
- [GD Image with logo](./imageWithLogo.php): a logo on top of the QR Code
2121
- [GD image with text](./imageWithText.php): description text under the QR Code ([#35](https://github.com/chillerlan/php-qrcode/issues/35))
22+
- [GD Image with rounded modules](./pngWithRoundedShapes.php): Similar to "melted" modules, but more rounded ([#127](https://github.com/chillerlan/php-qrcode/issues/127))
2223
- [ImageMagick with logo](./imagickWithLogo.php): a logo on top of the QR Code
2324
- [ImageMagick with image as background](./imagickImageAsBackground.php): an image as full size background of the QR Code
2425
- [SVG with logo](./svgWithLogo.php): an SVG QR Code with embedded logo (that is also SVG)

examples/pngWithRoundedShapes.php

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<?php
2+
3+
/**
4+
* php-gd realization of QR code with rounded modules
5+
*
6+
* @see https://github.com/chillerlan/php-qrcode/pull/215
7+
* @see https://github.com/chillerlan/php-qrcode/issues/127
8+
*
9+
* @created 17.09.2023
10+
* @author livingroot
11+
* @copyright 2023 livingroot
12+
* @license MIT
13+
*/
14+
15+
use chillerlan\QRCode\Common\EccLevel;
16+
use chillerlan\QRCode\Data\QRMatrix;
17+
use chillerlan\QRCode\Output\QRGdImage;
18+
use chillerlan\QRCode\Output\QROutputInterface;
19+
use chillerlan\QRCode\QRCode;
20+
use chillerlan\QRCode\QROptions;
21+
22+
require_once __DIR__ . '/../vendor/autoload.php';
23+
24+
// --------------------
25+
// Class definition
26+
// --------------------
27+
28+
class QRGdRounded extends QRGdImage {
29+
30+
protected function module(int $x, int $y, int $M_TYPE): void {
31+
32+
$x1 = ($x * $this->scale);
33+
$y1 = ($y * $this->scale);
34+
$x2 = (($x + 1) * $this->scale);
35+
$y2 = (($y + 1) * $this->scale);
36+
37+
$rectsize = ($this->scale / 2);
38+
39+
/**
40+
* @var int $neighbours
41+
* The right bit order (starting from 0):
42+
* 0 1 2
43+
* 7 # 3
44+
* 6 5 4
45+
*/
46+
$neighbours = $this->matrix->checkNeighbours($x, $y);
47+
48+
// ------------------
49+
// Outer rounding
50+
// ------------------
51+
52+
if ($neighbours & (1 << 7)) { // neighbour left
53+
// top left
54+
imagefilledrectangle(
55+
$this->image,
56+
$x1,
57+
$y1,
58+
($x1 + $rectsize),
59+
($y1 + $rectsize),
60+
$this->moduleValues[$M_TYPE]
61+
);
62+
// bottom left
63+
imagefilledrectangle(
64+
$this->image,
65+
$x1,
66+
($y2 - $rectsize),
67+
($x1 + $rectsize),
68+
$y2,
69+
$this->moduleValues[$M_TYPE]
70+
);
71+
}
72+
73+
if ($neighbours & (1 << 3)) { // neighbour right
74+
// top right
75+
imagefilledrectangle(
76+
$this->image,
77+
($x2 - $rectsize),
78+
$y1,
79+
$x2,
80+
($y1 + $rectsize),
81+
$this->moduleValues[$M_TYPE]
82+
);
83+
// bottom right
84+
imagefilledrectangle(
85+
$this->image,
86+
($x2 - $rectsize),
87+
($y2 - $rectsize),
88+
$x2,
89+
$y2,
90+
$this->moduleValues[$M_TYPE]
91+
);
92+
}
93+
94+
if ($neighbours & (1 << 1)) { // neighbour top
95+
// top left
96+
imagefilledrectangle(
97+
$this->image,
98+
$x1,
99+
$y1,
100+
($x1 + $rectsize),
101+
($y1 + $rectsize),
102+
$this->moduleValues[$M_TYPE]
103+
);
104+
// top right
105+
imagefilledrectangle(
106+
$this->image,
107+
($x2 - $rectsize),
108+
$y1,
109+
$x2,
110+
($y1 + $rectsize),
111+
$this->moduleValues[$M_TYPE]
112+
);
113+
}
114+
115+
if ($neighbours & (1 << 5)) { // neighbour bottom
116+
// bottom left
117+
imagefilledrectangle(
118+
$this->image,
119+
$x1,
120+
($y2 - $rectsize),
121+
($x1 + $rectsize),
122+
$y2,
123+
$this->moduleValues[$M_TYPE]
124+
);
125+
// bottom right
126+
imagefilledrectangle(
127+
$this->image,
128+
($x2 - $rectsize),
129+
($y2 - $rectsize),
130+
$x2,
131+
$y2,
132+
$this->moduleValues[$M_TYPE]
133+
);
134+
}
135+
136+
// ---------------------
137+
// inner rounding
138+
// ---------------------
139+
140+
if (!$this->matrix->check($x, $y)) {
141+
142+
if (($neighbours & 1) && ($neighbours & (1 << 7)) && ($neighbours & (1 << 1))) {
143+
// top left
144+
imagefilledrectangle(
145+
$this->image,
146+
$x1,
147+
$y1,
148+
($x1 + $rectsize),
149+
($y1 + $rectsize),
150+
$this->moduleValues[($M_TYPE | QRMatrix::IS_DARK)]
151+
);
152+
}
153+
154+
if (($neighbours & (1 << 1)) && ($neighbours & (1 << 2)) && ($neighbours & (1 << 3))) {
155+
// top right
156+
imagefilledrectangle(
157+
$this->image,
158+
($x2 - $rectsize),
159+
$y1,
160+
$x2,
161+
($y1 + $rectsize),
162+
$this->moduleValues[($M_TYPE | QRMatrix::IS_DARK)]
163+
);
164+
}
165+
166+
if (($neighbours & (1 << 7)) && ($neighbours & (1 << 6)) && ($neighbours & (1 << 5))) {
167+
// bottom left
168+
imagefilledrectangle(
169+
$this->image,
170+
$x1,
171+
($y2 - $rectsize),
172+
($x1 + $rectsize),
173+
$y2,
174+
$this->moduleValues[($M_TYPE | QRMatrix::IS_DARK)]
175+
);
176+
}
177+
178+
if (($neighbours & (1 << 3)) && ($neighbours & (1 << 4)) && ($neighbours & (1 << 5))) {
179+
// bottom right
180+
imagefilledrectangle(
181+
$this->image,
182+
($x2 - $rectsize),
183+
($y2 - $rectsize),
184+
$x2,
185+
$y2,
186+
$this->moduleValues[($M_TYPE | QRMatrix::IS_DARK)]
187+
);
188+
}
189+
}
190+
191+
imagefilledellipse(
192+
$this->image,
193+
(int)(($x * $this->scale) + ($this->scale / 2)),
194+
(int)(($y * $this->scale) + ($this->scale / 2)),
195+
(int)($this->scale - 1),
196+
(int)($this->scale - 1),
197+
$this->moduleValues[$M_TYPE]
198+
);
199+
}
200+
}
201+
202+
203+
// --------------------
204+
// Example
205+
// --------------------
206+
207+
$options = new QROptions([
208+
'outputType' => QROutputInterface::CUSTOM,
209+
'outputInterface' => QRGdRounded::class,
210+
'eccLevel' => EccLevel::M,
211+
'imageTransparent' => false,
212+
'imageBase64' => false,
213+
'scale' => 30
214+
]);
215+
216+
$qrcode = new QRCode($options);
217+
218+
$img = $qrcode->render('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
219+
220+
header('Content-type: image/png');
221+
222+
echo $img;

0 commit comments

Comments
 (0)