Skip to content

Commit 0008606

Browse files
committed
✨ EPS support (really!)
1 parent 14779f9 commit 0008606

File tree

3 files changed

+167
-1
lines changed

3 files changed

+167
-1
lines changed

examples/eps.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
/**
3+
* @created 10.05.2022
4+
* @author Smiley <[email protected]>
5+
* @copyright 2022 Smiley
6+
* @license MIT
7+
*/
8+
9+
namespace chillerlan\QRCodeExamples;
10+
11+
use chillerlan\QRCode\{QRCode, QROptions};
12+
use chillerlan\QRCode\Common\EccLevel;
13+
use chillerlan\QRCode\Data\QRMatrix;
14+
15+
require_once __DIR__.'/../vendor/autoload.php';
16+
17+
$data = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ';
18+
19+
$options = new QROptions([
20+
'version' => 7,
21+
'outputType' => QRCode::OUTPUT_EPS,
22+
'eccLevel' => EccLevel::L,
23+
'scale' => 5,
24+
'addQuietzone' => true,
25+
'cachefile' => __DIR__.'/test.eps',
26+
'moduleValues' => [
27+
// finder
28+
QRMatrix::M_FINDER | QRMatrix::IS_DARK => 0xA71111, // dark (true)
29+
QRMatrix::M_FINDER => 0xFFBFBF, // light (false)
30+
QRMatrix::M_FINDER_DOT | QRMatrix::IS_DARK => 0xA71111, // finder dot, dark (true)
31+
// alignment
32+
QRMatrix::M_ALIGNMENT | QRMatrix::IS_DARK => 0xA70364,
33+
QRMatrix::M_ALIGNMENT => 0xFFC9C9,
34+
// timing
35+
QRMatrix::M_TIMING | QRMatrix::IS_DARK => 0x98005D,
36+
QRMatrix::M_TIMING => 0xFFB8E9,
37+
// format
38+
QRMatrix::M_FORMAT | QRMatrix::IS_DARK => 0x003804,
39+
QRMatrix::M_FORMAT => 0x00FB12,
40+
// version
41+
QRMatrix::M_VERSION | QRMatrix::IS_DARK => 0x650098,
42+
QRMatrix::M_VERSION => 0xE0B8FF,
43+
// data
44+
QRMatrix::M_DATA | QRMatrix::IS_DARK => 0x4A6000,
45+
QRMatrix::M_DATA => 0xECF9BE,
46+
// darkmodule
47+
QRMatrix::M_DARKMODULE | QRMatrix::IS_DARK => 0x080063,
48+
// separator
49+
QRMatrix::M_SEPARATOR => 0xAFBFBF,
50+
// quietzone
51+
QRMatrix::M_QUIETZONE => 0xDDDDDD,
52+
],
53+
]);
54+
55+
// if viewed in the browser, we should push it as file download as EPS isn't usually supported
56+
header('Content-type: application/postscript');
57+
header('Content-Disposition: filename="qrcode.eps"');
58+
59+
echo (new QRCode($options))->render($data);
60+
61+
62+

src/Output/QREps.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
/**
3+
* Class QREps
4+
*
5+
* @created 09.05.2022
6+
* @author smiley <[email protected]>
7+
* @copyright 2022 smiley
8+
* @license MIT
9+
*/
10+
11+
namespace chillerlan\QRCode\Output;
12+
13+
use function date, implode, is_int, sprintf;
14+
15+
/**
16+
* Encapsulated Postscript (EPS) output
17+
*
18+
* @see https://github.com/t0k4rt/phpqrcode/blob/bb29e6eb77e0a2a85bb0eb62725e0adc11ff5a90/qrvect.php#L52-L137
19+
* @see https://web.archive.org/web/20170818010030/http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/postscript/pdfs/5002.EPSF_Spec.pdf
20+
* @see https://web.archive.org/web/20210419003859/https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
21+
*/
22+
class QREps extends QROutputAbstract{
23+
24+
/**
25+
* @inheritDoc
26+
*/
27+
protected function moduleValueIsValid($value):bool{
28+
return is_int($value) && $value >= 0 && $value <= 0xffffff;
29+
}
30+
31+
/**
32+
* @inheritDoc
33+
*/
34+
protected function getModuleValue($value):array{
35+
return [
36+
round((($value & 0xff0000) >> 16) / 255, 5),
37+
round((($value & 0x00ff00) >> 8) / 255, 5),
38+
round(($value & 0x0000ff) / 255, 5)
39+
];
40+
}
41+
42+
/**
43+
* @inheritDoc
44+
*/
45+
protected function getDefaultModuleValue(bool $isDark):array{
46+
return $isDark ? [0.0, 0.0, 0.0] : [1.0, 1.0, 1.0];
47+
}
48+
49+
/**
50+
* @inheritDoc
51+
*/
52+
public function dump(string $file = null):string{
53+
$file ??= $this->options->cachefile;
54+
$saveToFile = $file !== null;
55+
56+
$eps = [
57+
// main header
58+
'%!PS-Adobe-3.0 EPSF-3.0',
59+
'%%Creator: php-qrcode (https://github.com/chillerlan/php-qrcode)',
60+
'%%Title: QR Code',
61+
sprintf('%%%%CreationDate: %1$s', date('c')),
62+
'%%DocumentData: Clean7Bit',
63+
'%%LanguageLevel: 3',
64+
sprintf('%%%%BoundingBox: 0 -%1$s %1$s 0', $this->length),
65+
'%%EndComments',
66+
// function definitions
67+
'%%BeginProlog',
68+
'/F { rectfill } def',
69+
'/S { setrgbcolor } def',
70+
'%%EndProlog',
71+
// rotate into the proper orientation and scale to fit
72+
'-90 rotate',
73+
sprintf('%1$s %1$s scale', $this->scale),
74+
];
75+
76+
// create the path elements
77+
$paths = $this->collectModules(fn(int $x, int $y):string => sprintf('%s %s 1 1 F', $x, $y));
78+
79+
foreach($paths as $M_TYPE => $path){
80+
81+
if(empty($path)){
82+
continue;
83+
}
84+
85+
$eps[] = sprintf('%f %f %f S', ...$this->moduleValues[$M_TYPE]);
86+
$eps[] = implode("\n", $path);
87+
}
88+
89+
// end file
90+
$eps[] = '%%EOF';
91+
92+
$data = implode("\n", $eps);
93+
94+
if($saveToFile){
95+
$this->saveToFile($data, $file);
96+
}
97+
98+
return $data;
99+
}
100+
101+
}

src/QRCode.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use chillerlan\QRCode\Common\{EccLevel, ECICharset, MaskPattern, Mode};
1414
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, QRGdImage, QRImagick, QRMarkup, QROutputInterface, QRString};
16+
use chillerlan\QRCode\Output\{QRCodeOutputException, QRFpdf, QRGdImage, QRImagick, QRMarkup, QREps, QROutputInterface, QRString};
1717
use chillerlan\Settings\SettingsContainerInterface;
1818
use function class_exists, class_implements, in_array, mb_convert_encoding, mb_detect_encoding;
1919

@@ -80,6 +80,8 @@ class QRCode{
8080
/** @var string */
8181
public const OUTPUT_FPDF = 'fpdf';
8282
/** @var string */
83+
public const OUTPUT_EPS = 'eps';
84+
/** @var string */
8385
public const OUTPUT_CUSTOM = 'custom';
8486

8587
/**
@@ -97,6 +99,7 @@ class QRCode{
9799
self::OUTPUT_STRING_TEXT => QRString::class,
98100
self::OUTPUT_IMAGICK => QRImagick::class,
99101
self::OUTPUT_FPDF => QRFpdf::class,
102+
self::OUTPUT_EPS => QREps::class,
100103
];
101104

102105
/**

0 commit comments

Comments
 (0)