QROptionsTrait.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. <?php
  2. /**
  3. * Trait QROptionsTrait
  4. *
  5. * @created 10.03.2018
  6. * @author smiley <smiley@chillerlan.net>
  7. * @copyright 2018 smiley
  8. * @license MIT
  9. *
  10. * @noinspection PhpUnused
  11. */
  12. namespace chillerlan\QRCode;
  13. use chillerlan\QRCode\Output\QROutputInterface;
  14. use chillerlan\QRCode\Common\{EccLevel, MaskPattern, Version};
  15. use function extension_loaded, in_array, max, min, strtolower;
  16. /**
  17. * The QRCode plug-in settings & setter functionality
  18. */
  19. trait QROptionsTrait{
  20. /*
  21. * QR Code specific settings
  22. */
  23. /**
  24. * QR Code version number
  25. *
  26. * [1 ... 40] or Version::AUTO
  27. */
  28. protected int $version = Version::AUTO;
  29. /**
  30. * Minimum QR version
  31. *
  32. * if $version = QRCode::VERSION_AUTO
  33. */
  34. protected int $versionMin = 1;
  35. /**
  36. * Maximum QR version
  37. */
  38. protected int $versionMax = 40;
  39. /**
  40. * Error correct level
  41. *
  42. * QRCode::ECC_X where X is:
  43. *
  44. * - L => 7%
  45. * - M => 15%
  46. * - Q => 25%
  47. * - H => 30%
  48. *
  49. * @todo: accept string values (PHP8+)
  50. * @see https://github.com/chillerlan/php-qrcode/discussions/160
  51. */
  52. protected int $eccLevel = EccLevel::L;
  53. /**
  54. * Mask Pattern to use (no value in using, mostly for unit testing purposes)
  55. *
  56. * [0...7] or MaskPattern::PATTERN_AUTO
  57. */
  58. protected int $maskPattern = MaskPattern::AUTO;
  59. /**
  60. * Add a "quiet zone" (margin) according to the QR code spec
  61. *
  62. * @see https://www.qrcode.com/en/howto/code.html
  63. */
  64. protected bool $addQuietzone = true;
  65. /**
  66. * Size of the quiet zone
  67. *
  68. * internally clamped to [0 ... $moduleCount / 2], defaults to 4 modules
  69. */
  70. protected int $quietzoneSize = 4;
  71. /*
  72. * General output settings
  73. */
  74. /**
  75. * The built-in output type
  76. *
  77. * - QROutputInterface::MARKUP_XXXX where XXXX = HTML, SVG
  78. * - QROutputInterface::GDIMAGE_XXX where XXX = BMP, GIF, JPG, PNG, WEBP
  79. * - QROutputInterface::STRING_XXXX where XXXX = TEXT, JSON
  80. * - QROutputInterface::IMAGICK
  81. * - QROutputInterface::EPS
  82. * - QROutputInterface::FPDF
  83. * - QROutputInterface::CUSTOM
  84. */
  85. protected string $outputType = QROutputInterface::MARKUP_SVG;
  86. /**
  87. * The FQCN of the custom QROutputInterface if $outputType is set to QRCode::OUTPUT_CUSTOM
  88. */
  89. protected ?string $outputInterface = null;
  90. /**
  91. * Return the image resource instead of a render if applicable.
  92. * This option overrides/ignores other output options, such as $cachefile and $outputBase64.
  93. *
  94. * Supported by the following modules:
  95. *
  96. * - QRGdImage: resource (PHP < 8), GdImage
  97. * - QRImagick: Imagick
  98. * - QRFpdf: FPDF
  99. *
  100. * @see \chillerlan\QRCode\Output\QROutputInterface::dump()
  101. *
  102. * @var bool
  103. */
  104. protected bool $returnResource = false;
  105. /**
  106. * Optional cache file path `/path/to/cache.file`
  107. *
  108. * please note that the $file parameter in QRCode::render*() takes precedence over the $cachefile value
  109. */
  110. protected ?string $cachefile = null;
  111. /**
  112. * Toggle base64 data URI or raw data output (if applicable)
  113. */
  114. protected bool $outputBase64 = true;
  115. /**
  116. * Newline string
  117. */
  118. protected string $eol = PHP_EOL;
  119. /*
  120. * Common visual modifications
  121. */
  122. /**
  123. * Sets the image background color (if applicable)
  124. *
  125. * - QRImagick: defaults to "white"
  126. * - QRGdImage: defaults to [255, 255, 255]
  127. * - QRFpdf: defaults to blank internally (white page)
  128. *
  129. * @var mixed|null
  130. */
  131. protected $bgColor = null;
  132. /**
  133. * Whether to invert the matrix (reflectance reversal)
  134. */
  135. protected bool $invertMatrix = false;
  136. /**
  137. * Whether to draw the light (false) modules
  138. */
  139. protected bool $drawLightModules = true;
  140. /**
  141. * Specify whether to draw the modules as filled circles
  142. *
  143. * a note for GDImage output:
  144. *
  145. * if QROptions::$scale is less than 20, the image will be upscaled internally, then the modules will be drawn
  146. * using imagefilledellipse() and then scaled back to the expected size
  147. *
  148. * No effect in: QREps, QRFpdf, QRMarkupHTML
  149. *
  150. * @see https://github.com/chillerlan/php-qrcode/issues/23
  151. * @see https://github.com/chillerlan/php-qrcode/discussions/122
  152. */
  153. protected bool $drawCircularModules = false;
  154. /**
  155. * Specifies the radius of the modules when $drawCircularModules is set to true
  156. */
  157. protected float $circleRadius = 0.45;
  158. /**
  159. * Specifies which module types to exclude when $drawCircularModules is set to true
  160. */
  161. protected array $keepAsSquare = [];
  162. /**
  163. * Whether to connect the paths for the several module types to avoid weird glitches when using gradients etc.
  164. *
  165. * @see https://github.com/chillerlan/php-qrcode/issues/57
  166. */
  167. protected bool $connectPaths = false;
  168. /**
  169. * Specify which paths/patterns to exclude from connecting if $connectPaths is set to true
  170. */
  171. protected array $excludeFromConnect = [];
  172. /**
  173. * Module values map
  174. *
  175. * - QRImagick, QRMarkupHTML, QRMarkupSVG: #ABCDEF, cssname, rgb(), rgba()...
  176. * - QREps, QRFpdf, QRGdImage: [R, G, B] // 0-255
  177. * - QREps: [C, M, Y, K] // 0-255
  178. */
  179. protected ?array $moduleValues = null;
  180. /**
  181. * Toggles logo space creation
  182. */
  183. protected bool $addLogoSpace = false;
  184. /**
  185. * Width of the logo space
  186. *
  187. * if only either $logoSpaceWidth or $logoSpaceHeight is given, the logo space is assumed a square of that size
  188. */
  189. protected ?int $logoSpaceWidth = null;
  190. /**
  191. * Height of the logo space
  192. *
  193. * if only either $logoSpaceWidth or $logoSpaceHeight is given, the logo space is assumed a square of that size
  194. */
  195. protected ?int $logoSpaceHeight = null;
  196. /**
  197. * Optional horizontal start position of the logo space (top left corner)
  198. */
  199. protected ?int $logoSpaceStartX = null;
  200. /**
  201. * Optional vertical start position of the logo space (top left corner)
  202. */
  203. protected ?int $logoSpaceStartY = null;
  204. /*
  205. * Common raster image settings (QRGdImage, QRImagick)
  206. */
  207. /**
  208. * Pixel size of a QR code module
  209. */
  210. protected int $scale = 5;
  211. /**
  212. * Toggle transparency
  213. *
  214. * - QRGdImage and QRImagick: the given {@see \chillerlan\QRCode\QROptions::$transparencyColor $transparencyColor} is set as transparent
  215. *
  216. * @see https://github.com/chillerlan/php-qrcode/discussions/121
  217. */
  218. protected bool $imageTransparent = false;
  219. /**
  220. * Sets a transparency color for when {@see \chillerlan\QRCode\QROptions::$imageTransparent QROptions::$imageTransparent} is set to true.
  221. * Defaults to {@see \chillerlan\QRCode\QROptions::$bgColor QROptions::$bgColor}.
  222. *
  223. * - QRGdImage: [R, G, B], this color is set as transparent in {@see imagecolortransparent()}
  224. * - QRImagick: "color_str", this color is set in {@see Imagick::transparentPaintImage()}
  225. *
  226. * @var mixed|null
  227. */
  228. protected $transparencyColor = null;
  229. /**
  230. * Compression quality
  231. *
  232. * The given value depends on the used output type:
  233. *
  234. * - GDIMAGE_BMP {@see \imagebmp()} [0-1]
  235. * - GDIMAGE_JPG {@see \imagejpeg()} [0-100]
  236. * - GDIMAGE_WEBP {@see \imagepng()} [0-9]
  237. * - GDIMAGE_PNG {@see \imagewebp()} [0-100]
  238. * - IMAGICK {@see \Imagick::setImageCompressionQuality()} [0-100]
  239. */
  240. protected int $quality = -1;
  241. /*
  242. * QRImagick settings
  243. */
  244. /**
  245. * Imagick output format
  246. *
  247. * @see \Imagick::setImageFormat()
  248. * @see https://www.imagemagick.org/script/formats.php
  249. */
  250. protected string $imagickFormat = 'png32';
  251. /*
  252. * Common markup output settings (QRMarkupSVG, QRMarkupHTML)
  253. */
  254. /**
  255. * A common css class
  256. */
  257. protected string $cssClass = 'qrcode';
  258. /**
  259. * Markup substitute for dark (CSS value)
  260. */
  261. protected string $markupDark = '#000';
  262. /**
  263. * Markup substitute for light (CSS value)
  264. */
  265. protected string $markupLight = '#fff';
  266. /*
  267. * QRMarkupSVG settings
  268. */
  269. /**
  270. * Whether to add an XML header line or not, e.g. to embed the SVG directly in HTML
  271. *
  272. * `<?xml version="1.0" encoding="UTF-8"?>`
  273. */
  274. protected bool $svgAddXmlHeader = true;
  275. /**
  276. * SVG opacity
  277. */
  278. protected float $svgOpacity = 1.0;
  279. /**
  280. * Anything in the <defs> tag
  281. *
  282. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
  283. */
  284. protected string $svgDefs = '';
  285. /**
  286. * SVG viewBox size. A single integer number which defines width/height of the viewBox attribute.
  287. *
  288. * viewBox="0 0 x x"
  289. *
  290. * @deprecated 5.0.0 use QRMarkupSVG::getViewBox() instead
  291. * @see \chillerlan\QRCode\Output\QRMarkupSVG::getViewBox()
  292. *
  293. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
  294. * @see https://css-tricks.com/scale-svg/#article-header-id-3
  295. */
  296. protected ?int $svgViewBoxSize = null;
  297. /**
  298. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
  299. */
  300. protected string $svgPreserveAspectRatio = 'xMidYMid';
  301. /*
  302. * QRString settings
  303. */
  304. /**
  305. * String substitute for dark
  306. */
  307. protected string $textDark = '██';
  308. /**
  309. * String substitute for light
  310. */
  311. protected string $textLight = '░░';
  312. /**
  313. * An optional line prefix, e.g. empty space to align the QR Code in a console
  314. */
  315. protected string $textLineStart = '';
  316. /**
  317. * Whether to return matrix values in JSON as booleans or $M_TYPE integers
  318. */
  319. protected bool $jsonAsBooleans = false;
  320. /*
  321. * QRFpdf settings
  322. */
  323. /**
  324. * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
  325. *
  326. * @see \FPDF::__construct()
  327. */
  328. protected string $fpdfMeasureUnit = 'pt';
  329. /*
  330. * QR Code reader settings
  331. */
  332. /**
  333. * Use Imagick (if available) when reading QR Codes
  334. */
  335. protected bool $readerUseImagickIfAvailable = false;
  336. /**
  337. * Grayscale the image before reading
  338. */
  339. protected bool $readerGrayscale = false;
  340. /**
  341. * Increase the contrast before reading
  342. *
  343. * note that applying contrast works different in GD and Imagick, so mileage may vary
  344. */
  345. protected bool $readerIncreaseContrast = false;
  346. /**
  347. * clamp min/max version number
  348. */
  349. protected function setMinMaxVersion(int $versionMin, int $versionMax):void{
  350. $min = max(1, min(40, $versionMin));
  351. $max = max(1, min(40, $versionMax));
  352. $this->versionMin = min($min, $max);
  353. $this->versionMax = max($min, $max);
  354. }
  355. /**
  356. * sets the minimum version number
  357. */
  358. protected function set_versionMin(int $version):void{
  359. $this->setMinMaxVersion($version, $this->versionMax);
  360. }
  361. /**
  362. * sets the maximum version number
  363. */
  364. protected function set_versionMax(int $version):void{
  365. $this->setMinMaxVersion($this->versionMin, $version);
  366. }
  367. /**
  368. * sets/clamps the version number
  369. */
  370. protected function set_version(int $version):void{
  371. $this->version = ($version !== Version::AUTO) ? max(1, min(40, $version)) : Version::AUTO;
  372. }
  373. /**
  374. * sets/clamps the quiet zone size
  375. */
  376. protected function set_quietzoneSize(int $quietzoneSize):void{
  377. $this->quietzoneSize = max(0, min($quietzoneSize, 75));
  378. }
  379. /**
  380. * sets the FPDF measurement unit
  381. *
  382. * @codeCoverageIgnore
  383. */
  384. protected function set_fpdfMeasureUnit(string $unit):void{
  385. $unit = strtolower($unit);
  386. if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
  387. $this->fpdfMeasureUnit = $unit;
  388. }
  389. // @todo throw or ignore silently?
  390. }
  391. /**
  392. * enables Imagick for the QR Code reader if the extension is available
  393. */
  394. protected function set_readerUseImagickIfAvailable(bool $useImagickIfAvailable):void{
  395. $this->readerUseImagickIfAvailable = ($useImagickIfAvailable && extension_loaded('imagick'));
  396. }
  397. /**
  398. * clamp the logo space values between 0 and maximum length (177 modules at version 40)
  399. */
  400. protected function clampLogoSpaceValue(?int $value):?int{
  401. if($value === null){
  402. return null;
  403. }
  404. return (int)max(0, min(177, $value));
  405. }
  406. /**
  407. * clamp/set logo space width
  408. */
  409. protected function set_logoSpaceWidth(?int $value):void{
  410. $this->logoSpaceWidth = $this->clampLogoSpaceValue($value);
  411. }
  412. /**
  413. * clamp/set logo space height
  414. */
  415. protected function set_logoSpaceHeight(?int $value):void{
  416. $this->logoSpaceHeight = $this->clampLogoSpaceValue($value);
  417. }
  418. /**
  419. * clamp/set horizontal logo space start
  420. */
  421. protected function set_logoSpaceStartX(?int $value):void{
  422. $this->logoSpaceStartX = $this->clampLogoSpaceValue($value);
  423. }
  424. /**
  425. * clamp/set vertical logo space start
  426. */
  427. protected function set_logoSpaceStartY(?int $value):void{
  428. $this->logoSpaceStartY = $this->clampLogoSpaceValue($value);
  429. }
  430. /**
  431. * clamp/set SVG circle radius
  432. */
  433. protected function set_circleRadius(float $circleRadius):void{
  434. $this->circleRadius = max(0.1, min(0.75, $circleRadius));
  435. }
  436. /*
  437. * redirect calls of deprecated variables to new/renamed property
  438. */
  439. /**
  440. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  441. * @see \chillerlan\QRCode\QROptions::$outputBase64
  442. */
  443. protected bool $imageBase64;
  444. /**
  445. * redirect call to the new variable
  446. *
  447. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  448. * @see \chillerlan\QRCode\QROptions::$outputBase64
  449. * @codeCoverageIgnore
  450. */
  451. protected function set_imageBase64(bool $imageBase64):void{
  452. $this->outputBase64 = $imageBase64;
  453. }
  454. /**
  455. * redirect call to the new variable
  456. *
  457. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  458. * @see \chillerlan\QRCode\QROptions::$outputBase64
  459. * @codeCoverageIgnore
  460. */
  461. protected function get_imageBase64():bool{
  462. return $this->outputBase64;
  463. }
  464. /**
  465. * @deprecated 5.0.0 use QROptions::$quality instead
  466. * @see \chillerlan\QRCode\QROptions::$quality
  467. */
  468. protected int $jpegQuality;
  469. /**
  470. * @deprecated 5.0.0 use QROptions::$quality instead
  471. * @see \chillerlan\QRCode\QROptions::$quality
  472. * @codeCoverageIgnore
  473. */
  474. protected function set_jpegQuality(int $jpegQuality):void{
  475. $this->quality = $jpegQuality;
  476. }
  477. /**
  478. * @deprecated 5.0.0 use QROptions::$quality instead
  479. * @see \chillerlan\QRCode\QROptions::$quality
  480. * @codeCoverageIgnore
  481. */
  482. protected function get_jpegQuality():int{
  483. return $this->quality;
  484. }
  485. /**
  486. * @deprecated 5.0.0 use QROptions::$quality instead
  487. * @see \chillerlan\QRCode\QROptions::$quality
  488. */
  489. protected int $pngCompression;
  490. /**
  491. * @deprecated 5.0.0 use QROptions::$quality instead
  492. * @see \chillerlan\QRCode\QROptions::$quality
  493. * @codeCoverageIgnore
  494. */
  495. protected function set_pngCompression(int $pngCompression):void{
  496. $this->quality = $pngCompression;
  497. }
  498. /**
  499. * @deprecated 5.0.0 use QROptions::$quality instead
  500. * @see \chillerlan\QRCode\QROptions::$quality
  501. * @codeCoverageIgnore
  502. */
  503. protected function get_pngCompression():int{
  504. return $this->quality;
  505. }
  506. /**
  507. * @deprecated 5.0.0 use QROptions::$transparencyColor instead
  508. * @see \chillerlan\QRCode\QROptions::$transparencyColor
  509. */
  510. protected array $imageTransparencyBG;
  511. /**
  512. * @deprecated 5.0.0 use QROptions::$transparencyColor instead
  513. * @see \chillerlan\QRCode\QROptions::$transparencyColor
  514. * @codeCoverageIgnore
  515. */
  516. protected function set_imageTransparencyBG(?array $imageTransparencyBG):void{
  517. $this->transparencyColor = $imageTransparencyBG;
  518. }
  519. /**
  520. * @deprecated 5.0.0 use QROptions::$transparencyColor instead
  521. * @see \chillerlan\QRCode\QROptions::$transparencyColor
  522. * @codeCoverageIgnore
  523. */
  524. protected function get_imageTransparencyBG():?array{
  525. return $this->transparencyColor;
  526. }
  527. /**
  528. * @deprecated 5.0.0 use QROptions::$bgColor instead
  529. * @see \chillerlan\QRCode\QROptions::$bgColor
  530. */
  531. protected string $imagickBG;
  532. /**
  533. * @deprecated 5.0.0 use QROptions::$bgColor instead
  534. * @see \chillerlan\QRCode\QROptions::$bgColor
  535. * @codeCoverageIgnore
  536. */
  537. protected function set_imagickBG(?string $imagickBG):void{
  538. $this->bgColor = $imagickBG;
  539. }
  540. /**
  541. * @deprecated 5.0.0 use QROptions::$bgColor instead
  542. * @see \chillerlan\QRCode\QROptions::$bgColor
  543. * @codeCoverageIgnore
  544. */
  545. protected function get_imagickBG():?string{
  546. return $this->bgColor;
  547. }
  548. }