Skip to content

Commit 164116f

Browse files
committed
🛀 output (+test) simplification & cleanup
1 parent dc73f89 commit 164116f

30 files changed

+353
-473
lines changed

src/Output/QRImage.php renamed to src/Output/QRGdImage.php

Lines changed: 21 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22
/**
3-
* Class QRImage
3+
* Class QRGdImage
44
*
55
* @created 05.12.2015
66
* @author Smiley <[email protected]>
@@ -15,31 +15,18 @@
1515
use chillerlan\QRCode\Data\QRMatrix;
1616
use chillerlan\QRCode\QRCode;
1717
use chillerlan\Settings\SettingsContainerInterface;
18-
use ErrorException, Exception;
19-
18+
use ErrorException, Throwable;
2019
use function array_values, count, extension_loaded, imagecolorallocate, imagecolortransparent, imagecreatetruecolor,
21-
imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, in_array,
22-
is_array, ob_end_clean, ob_get_contents, ob_start, range, restore_error_handler, set_error_handler;
20+
imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, is_array,
21+
max, min, ob_end_clean, ob_get_contents, ob_start, restore_error_handler, set_error_handler;
2322
use const IMG_BICUBIC;
2423

2524
/**
2625
* Converts the matrix into GD images, raw or base64 output (requires ext-gd)
2726
*
2827
* @see http://php.net/manual/book.image.php
2928
*/
30-
class QRImage extends QROutputAbstract{
31-
32-
/**
33-
* GD image types that support transparency
34-
*
35-
* @var string[]
36-
*/
37-
protected const TRANSPARENCY_TYPES = [
38-
QRCode::OUTPUT_IMAGE_PNG,
39-
QRCode::OUTPUT_IMAGE_GIF,
40-
];
41-
42-
protected string $defaultMode = QRCode::OUTPUT_IMAGE_PNG;
29+
class QRGdImage extends QROutputAbstract{
4330

4431
/**
4532
* The GD image resource
@@ -115,7 +102,7 @@ public function dump(string $file = null){
115102
/** @phan-suppress-next-line PhanParamTooFewInternalUnpack */
116103
$background = imagecolorallocate($this->image, ...$tbg);
117104

118-
if($this->options->imageTransparent && in_array($this->options->outputType, $this::TRANSPARENCY_TYPES, true)){
105+
if($this->options->imageTransparent && $this->options->outputType !== QRCode::OUTPUT_IMAGE_JPG){
119106
imagecolortransparent($this->image, $background);
120107
}
121108

@@ -188,11 +175,24 @@ protected function dumpImage():string{
188175
ob_start();
189176

190177
try{
191-
$this->{$this->outputMode ?? $this->defaultMode}();
178+
179+
switch($this->options->outputType){
180+
case QRCode::OUTPUT_IMAGE_GIF:
181+
imagegif($this->image);
182+
break;
183+
case QRCode::OUTPUT_IMAGE_JPG:
184+
imagejpeg($this->image, null, max(0, min(100, $this->options->jpegQuality)));
185+
break;
186+
// silently default to png output
187+
case QRCode::OUTPUT_IMAGE_PNG:
188+
default:
189+
imagepng($this->image, null, max(-1, min(9, $this->options->pngCompression)));
190+
}
191+
192192
}
193193
// not going to cover edge cases
194194
// @codeCoverageIgnoreStart
195-
catch(Exception $e){
195+
catch(Throwable $e){
196196
throw new QRCodeOutputException($e->getMessage());
197197
}
198198
// @codeCoverageIgnoreEnd
@@ -205,43 +205,4 @@ protected function dumpImage():string{
205205
return $imageData;
206206
}
207207

208-
/**
209-
* PNG output
210-
*
211-
* @return void
212-
*/
213-
protected function png():void{
214-
imagepng(
215-
$this->image,
216-
null,
217-
in_array($this->options->pngCompression, range(-1, 9), true)
218-
? $this->options->pngCompression
219-
: -1
220-
);
221-
}
222-
223-
/**
224-
* Jiff - like... JitHub!
225-
*
226-
* @return void
227-
*/
228-
protected function gif():void{
229-
imagegif($this->image);
230-
}
231-
232-
/**
233-
* JPG output
234-
*
235-
* @return void
236-
*/
237-
protected function jpg():void{
238-
imagejpeg(
239-
$this->image,
240-
null,
241-
in_array($this->options->jpegQuality, range(0, 100), true)
242-
? $this->options->jpegQuality
243-
: 85
244-
);
245-
}
246-
247208
}

src/Output/QRImagick.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ public function dump(string $file = null){
8080
$this->options->imagickFormat
8181
);
8282

83+
$this->imagick->setImageType(Imagick::IMGTYPE_TRUECOLOR);
84+
8385
$this->drawImage();
8486

8587
if($this->options->returnResource){

src/Output/QRMarkup.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,33 @@ protected function getDefaultModuleValue(bool $isDark):string{
4343
return $isDark ? $this->options->markupDark : $this->options->markupLight;
4444
}
4545

46+
/**
47+
* @inheritDoc
48+
*/
49+
public function dump(string $file = null){
50+
$file ??= $this->options->cachefile;
51+
$saveToFile = $file !== null;
52+
53+
switch($this->options->outputType){
54+
case QRCode::OUTPUT_MARKUP_HTML:
55+
$data = $this->html($saveToFile);
56+
break;
57+
case QRCode::OUTPUT_MARKUP_SVG:
58+
default:
59+
$data = $this->svg($saveToFile);
60+
}
61+
62+
if($saveToFile){
63+
$this->saveToFile($data, $file);
64+
}
65+
66+
return $data;
67+
}
68+
4669
/**
4770
* HTML output
4871
*/
49-
protected function html(string $file = null):string{
72+
protected function html(bool $saveToFile):string{
5073

5174
$html = empty($this->options->cssClass)
5275
? '<div>'
@@ -66,7 +89,7 @@ protected function html(string $file = null):string{
6689

6790
$html .= '</div>'.$this->options->eol;
6891

69-
if($file !== null){
92+
if($saveToFile){
7093
return sprintf(
7194
'<!DOCTYPE html><head><meta charset="UTF-8"><title>QR Code</title></head><body>%s</body>',
7295
$this->options->eol.$html
@@ -83,7 +106,7 @@ protected function html(string $file = null):string{
83106
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
84107
* @see https://www.sarasoueidan.com/demos/interactive-svg-coordinate-system/
85108
*/
86-
protected function svg(string $file = null):string{
109+
protected function svg(bool $saveToFile):string{
87110
$svg = $this->svgHeader();
88111

89112
if(!empty($this->options->svgDefs)){
@@ -96,7 +119,7 @@ protected function svg(string $file = null):string{
96119
$svg .= sprintf('%1$s</svg>%1$s', $this->options->eol);
97120

98121
// transform to data URI only when not saving to file
99-
if($file === null && $this->options->imageBase64){
122+
if(!$saveToFile && $this->options->imageBase64){
100123
$svg = $this->base64encode($svg, 'image/svg+xml');
101124
}
102125

src/Output/QROutputAbstract.php

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
namespace chillerlan\QRCode\Output;
1212

13-
use chillerlan\QRCode\{Data\QRMatrix, QRCode};
13+
use chillerlan\QRCode\Data\QRMatrix;
1414
use chillerlan\Settings\SettingsContainerInterface;
15-
use function base64_encode, dirname, file_put_contents, get_called_class, in_array, is_writable, sprintf;
15+
use function base64_encode, dirname, file_put_contents, is_writable, sprintf;
1616

1717
/**
1818
* common output abstract
@@ -26,18 +26,6 @@ abstract class QROutputAbstract implements QROutputInterface{
2626
*/
2727
protected int $moduleCount;
2828

29-
/**
30-
* the current output mode
31-
*
32-
* @see \chillerlan\QRCode\QROptions::$outputType
33-
*/
34-
protected string $outputMode;
35-
36-
/**
37-
* the default output mode of the current output module
38-
*/
39-
protected string $defaultMode;
40-
4129
/**
4230
* the current scaling for a QR pixel
4331
*
@@ -74,11 +62,6 @@ public function __construct(SettingsContainerInterface $options, QRMatrix $matri
7462
$this->moduleCount = $this->matrix->size();
7563
$this->scale = $this->options->scale;
7664
$this->length = $this->moduleCount * $this->scale;
77-
$class = get_called_class();
78-
79-
if(isset(QRCode::OUTPUT_MODES[$class]) && in_array($this->options->outputType, QRCode::OUTPUT_MODES[$class])){
80-
$this->outputMode = $this->options->outputType;
81-
}
8265

8366
$this->setModuleValues();
8467
}
@@ -136,30 +119,15 @@ protected function base64encode(string $data, string $mime):string{
136119
*
137120
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
138121
*/
139-
protected function saveToFile(string $data, string $file):bool{
122+
protected function saveToFile(string $data, string $file):void{
140123

141124
if(!is_writable(dirname($file))){
142125
throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s', $file));
143126
}
144127

145-
return (bool)file_put_contents($file, $data);
146-
}
147-
148-
/**
149-
* @inheritDoc
150-
*/
151-
public function dump(string $file = null){
152-
$file ??= $this->options->cachefile;
153-
154-
// call the built-in output method with the optional file path as parameter
155-
// to make the called method aware if a cache file was given
156-
$data = $this->{$this->outputMode ?? $this->defaultMode}($file);
157-
158-
if($file !== null){
159-
$this->saveToFile($data, $file);
128+
if(file_put_contents($file, $data) === false){
129+
throw new QRCodeOutputException(sprintf('Cannot write data to cache file: %s (file_put_contents error)', $file));
160130
}
161-
162-
return $data;
163131
}
164132

165133
}

src/Output/QRString.php

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,32 @@ protected function getDefaultModuleValue(bool $isDark):string{
4545
return $isDark ? $this->options->textDark : $this->options->textLight;
4646
}
4747

48+
/**
49+
* @inheritDoc
50+
*/
51+
public function dump(string $file = null):string{
52+
$file ??= $this->options->cachefile;
53+
54+
switch($this->options->outputType){
55+
case QRCode::OUTPUT_STRING_TEXT:
56+
$data = $this->text();
57+
break;
58+
case QRCode::OUTPUT_STRING_JSON:
59+
default:
60+
$data = $this->json();
61+
}
62+
63+
if($file !== null){
64+
$this->saveToFile($data, $file);
65+
}
66+
67+
return $data;
68+
}
69+
4870
/**
4971
* string output
5072
*/
51-
protected function text(string $file = null):string{
73+
protected function text():string{
5274
$str = [];
5375

5476
foreach($this->matrix->matrix() as $row){
@@ -67,7 +89,7 @@ protected function text(string $file = null):string{
6789
/**
6890
* JSON output
6991
*/
70-
protected function json(string $file = null):string{
92+
protected function json():string{
7193
return json_encode($this->matrix->matrix());
7294
}
7395

src/QRCode.php

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
namespace chillerlan\QRCode;
1212

1313
use chillerlan\QRCode\Common\{EccLevel, ECICharset, MaskPattern, Mode};
14-
use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number, QRData, QRCodeDataException, QRDataModeInterface, QRMatrix};
14+
use chillerlan\QRCode\Data\{AlphaNum, Byte, ECI, Kanji, Number, QRCodeDataException, QRData, QRDataModeInterface, QRMatrix};
1515
use chillerlan\QRCode\Decoder\{Decoder, DecoderResult, LuminanceSourceInterface};
16-
use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRImage, QRImagick, QRMarkup, QROutputInterface, QRString};
16+
use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRGdImage, QRImagick, QRMarkup, QROutputInterface, QRString};
1717
use chillerlan\Settings\SettingsContainerInterface;
1818
use function class_exists, class_implements, in_array, mb_convert_encoding, mb_detect_encoding;
1919

@@ -68,30 +68,20 @@ class QRCode{
6868
public const OUTPUT_CUSTOM = 'custom';
6969

7070
/**
71-
* Map of built-in output modules => capabilities
71+
* Map of built-in output modes => modules
7272
*
73-
* @var string[][]
73+
* @var string[]
7474
*/
7575
public const OUTPUT_MODES = [
76-
QRMarkup::class => [
77-
self::OUTPUT_MARKUP_SVG,
78-
self::OUTPUT_MARKUP_HTML,
79-
],
80-
QRImage::class => [
81-
self::OUTPUT_IMAGE_PNG,
82-
self::OUTPUT_IMAGE_GIF,
83-
self::OUTPUT_IMAGE_JPG,
84-
],
85-
QRString::class => [
86-
self::OUTPUT_STRING_JSON,
87-
self::OUTPUT_STRING_TEXT,
88-
],
89-
QRImagick::class => [
90-
self::OUTPUT_IMAGICK,
91-
],
92-
QRFpdf::class => [
93-
self::OUTPUT_FPDF,
94-
],
76+
self::OUTPUT_MARKUP_SVG => QRMarkup::class,
77+
self::OUTPUT_MARKUP_HTML => QRMarkup::class,
78+
self::OUTPUT_IMAGE_PNG => QRGdImage::class,
79+
self::OUTPUT_IMAGE_GIF => QRGdImage::class,
80+
self::OUTPUT_IMAGE_JPG => QRGdImage::class,
81+
self::OUTPUT_STRING_JSON => QRString::class,
82+
self::OUTPUT_STRING_TEXT => QRString::class,
83+
self::OUTPUT_IMAGICK => QRImagick::class,
84+
self::OUTPUT_FPDF => QRFpdf::class,
9585
];
9686

9787
/**
@@ -135,9 +125,7 @@ public function render(string $data = null, string $file = null){
135125

136126
break;
137127
}
138-
139128
}
140-
141129
}
142130

143131
return $this->initOutputInterface()->dump($file);
@@ -189,12 +177,10 @@ protected function initOutputInterface():QROutputInterface{
189177
return $this->initCustomOutputInterface();
190178
}
191179

192-
foreach($this::OUTPUT_MODES as $outputInterface => $modes){
193-
194-
if(in_array($this->options->outputType, $modes)){
195-
return new $outputInterface($this->options, $this->getMatrix());
196-
}
180+
$outputInterface = $this::OUTPUT_MODES[$this->options->outputType] ?? false;
197181

182+
if($outputInterface){
183+
return new $outputInterface($this->options, $this->getMatrix());
198184
}
199185

200186
throw new QRCodeOutputException('invalid output type');

0 commit comments

Comments
 (0)