QROptionsTrait.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
  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 = PNG, GIF, JPG
  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. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  113. * @see \chillerlan\QRCode\QROptions::$outputBase64
  114. */
  115. protected bool $imageBase64 = true;
  116. /**
  117. * Toggle base64 data URI or raw data output (if applicable)
  118. */
  119. protected bool $outputBase64 = true;
  120. /**
  121. * Newline string
  122. */
  123. protected string $eol = PHP_EOL;
  124. /*
  125. * Common visual modifications
  126. */
  127. /**
  128. * Sets the image background color (if applicable)
  129. *
  130. * - QRImagick: defaults to "white"
  131. * - QRGdImage: defaults to [255, 255, 255]
  132. * - QRFpdf: defaults to blank internally (white page)
  133. *
  134. * @var mixed|null
  135. */
  136. protected $bgColor = null;
  137. /**
  138. * Whether to draw the light (false) modules
  139. *
  140. * @var bool
  141. */
  142. protected bool $drawLightModules = true;
  143. /**
  144. * Specify whether to draw the modules as filled circles
  145. *
  146. * a note for GDImage output:
  147. *
  148. * if QROptions::$scale is less than 20, the image will be upscaled internally, then the modules will be drawn
  149. * using imagefilledellipse() and then scaled back to the expected size
  150. *
  151. * No effect in: QREps, QRFpdf, QRMarkupHTML
  152. *
  153. * @see https://github.com/chillerlan/php-qrcode/issues/23
  154. * @see https://github.com/chillerlan/php-qrcode/discussions/122
  155. */
  156. protected bool $drawCircularModules = false;
  157. /**
  158. * Specifies the radius of the modules when $drawCircularModules is set to true
  159. */
  160. protected float $circleRadius = 0.45;
  161. /**
  162. * Specifies which module types to exclude when $drawCircularModules is set to true
  163. */
  164. protected array $keepAsSquare = [];
  165. /**
  166. * Whether to connect the paths for the several module types to avoid weird glitches when using gradients etc.
  167. *
  168. * @see https://github.com/chillerlan/php-qrcode/issues/57
  169. */
  170. protected bool $connectPaths = false;
  171. /**
  172. * Specify which paths/patterns to exclude from connecting if $connectPaths is set to true
  173. */
  174. protected array $excludeFromConnect = [];
  175. /**
  176. * Module values map
  177. *
  178. * - QRImagick, QRMarkupHTML, QRMarkupSVG: #ABCDEF, cssname, rgb(), rgba()...
  179. * - QREps, QRFpdf, QRGdImage: [63, 127, 255] // R, G, B
  180. */
  181. protected ?array $moduleValues = null;
  182. /**
  183. * Toggles logo space creation
  184. */
  185. protected bool $addLogoSpace = false;
  186. /**
  187. * Width of the logo space
  188. *
  189. * if only either $logoSpaceWidth or $logoSpaceHeight is given, the logo space is assumed a square of that size
  190. */
  191. protected ?int $logoSpaceWidth = null;
  192. /**
  193. * Height of the logo space
  194. *
  195. * if only either $logoSpaceWidth or $logoSpaceHeight is given, the logo space is assumed a square of that size
  196. */
  197. protected ?int $logoSpaceHeight = null;
  198. /**
  199. * Optional horizontal start position of the logo space (top left corner)
  200. */
  201. protected ?int $logoSpaceStartX = null;
  202. /**
  203. * Optional vertical start position of the logo space (top left corner)
  204. */
  205. protected ?int $logoSpaceStartY = null;
  206. /*
  207. * Common raster image settings (QRGdImage, QRImagick)
  208. */
  209. /**
  210. * Pixel size of a QR code module
  211. */
  212. protected int $scale = 5;
  213. /**
  214. * Toggle transparency
  215. *
  216. * - QRGdImage and QRImagick: the given {@see \chillerlan\QRCode\QROptions::$transparencyColor $transparencyColor} is set as transparent
  217. *
  218. * @see https://github.com/chillerlan/php-qrcode/discussions/121
  219. */
  220. protected bool $imageTransparent = true;
  221. /**
  222. * Sets a transparency color for when {@see \chillerlan\QRCode\QROptions::$imageTransparent QROptions::$imageTransparent} is set to true.
  223. * Defaults to {@see \chillerlan\QRCode\QROptions::$bgColor QROptions::$bgColor}.
  224. *
  225. * - QRGdImage: [R, G, B], this color is set as transparent in {@see imagecolortransparent()}
  226. * - QRImagick: "color_str", this color is set in {@see Imagick::transparentPaintImage()}
  227. *
  228. * @var mixed|null
  229. */
  230. protected $transparencyColor = null;
  231. /*
  232. * QRGdImage settings
  233. */
  234. /**
  235. * @see imagepng()
  236. */
  237. protected int $pngCompression = -1;
  238. /**
  239. * @see imagejpeg()
  240. */
  241. protected int $jpegQuality = 85;
  242. /*
  243. * QRImagick settings
  244. */
  245. /**
  246. * Imagick output format
  247. *
  248. * @see \Imagick::setImageFormat()
  249. * @see https://www.imagemagick.org/script/formats.php
  250. */
  251. protected string $imagickFormat = 'png32';
  252. /*
  253. * Common markup output settings (QRMarkupSVG, QRMarkupHTML)
  254. */
  255. /**
  256. * A common css class
  257. */
  258. protected string $cssClass = 'qrcode';
  259. /**
  260. * Markup substitute for dark (CSS value)
  261. */
  262. protected string $markupDark = '#000';
  263. /**
  264. * Markup substitute for light (CSS value)
  265. */
  266. protected string $markupLight = '#fff';
  267. /*
  268. * QRMarkupSVG settings
  269. */
  270. /**
  271. * Whether to add an XML header line or not, e.g. to embed the SVG directly in HTML
  272. *
  273. * `<?xml version="1.0" encoding="UTF-8"?>`
  274. */
  275. protected bool $svgAddXmlHeader = true;
  276. /**
  277. * SVG opacity
  278. */
  279. protected float $svgOpacity = 1.0;
  280. /**
  281. * Anything in the <defs> tag
  282. *
  283. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs
  284. */
  285. protected string $svgDefs = '';
  286. /**
  287. * SVG viewBox size. A single integer number which defines width/height of the viewBox attribute.
  288. *
  289. * viewBox="0 0 x x"
  290. *
  291. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox
  292. * @see https://css-tricks.com/scale-svg/#article-header-id-3
  293. */
  294. protected ?int $svgViewBoxSize = null;
  295. /**
  296. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio
  297. */
  298. protected string $svgPreserveAspectRatio = 'xMidYMid';
  299. /**
  300. * Optional "width" attribute with the specified value (note that the value is not checked!)
  301. *
  302. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/width
  303. */
  304. protected ?string $svgWidth = null;
  305. /**
  306. * Optional "height" attribute with the specified value (note that the value is not checked!)
  307. *
  308. * @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/height
  309. */
  310. protected ?string $svgHeight = null;
  311. /*
  312. * QRString settings
  313. */
  314. /**
  315. * String substitute for dark
  316. */
  317. protected string $textDark = '██';
  318. /**
  319. * String substitute for light
  320. */
  321. protected string $textLight = '░░';
  322. /**
  323. * An optional line prefix, e.g. empty space to align the QR Code in a console
  324. */
  325. protected string $textLineStart = '';
  326. /**
  327. * Whether to return matrix values in JSON as booleans or $M_TYPE integers
  328. */
  329. protected bool $jsonAsBooleans = false;
  330. /*
  331. * QRFpdf settings
  332. */
  333. /**
  334. * Measurement unit for FPDF output: pt, mm, cm, in (defaults to "pt")
  335. *
  336. * @see \FPDF::__construct()
  337. */
  338. protected string $fpdfMeasureUnit = 'pt';
  339. /*
  340. * QR Code reader settings
  341. */
  342. /**
  343. * Use Imagick (if available) when reading QR Codes
  344. */
  345. protected bool $readerUseImagickIfAvailable = false;
  346. /**
  347. * Grayscale the image before reading
  348. */
  349. protected bool $readerGrayscale = false;
  350. /**
  351. * Increase the contrast before reading
  352. *
  353. * note that applying contrast works different in GD and Imagick, so mileage may vary
  354. */
  355. protected bool $readerIncreaseContrast = false;
  356. /**
  357. * clamp min/max version number
  358. */
  359. protected function setMinMaxVersion(int $versionMin, int $versionMax):void{
  360. $min = max(1, min(40, $versionMin));
  361. $max = max(1, min(40, $versionMax));
  362. $this->versionMin = min($min, $max);
  363. $this->versionMax = max($min, $max);
  364. }
  365. /**
  366. * sets the minimum version number
  367. */
  368. protected function set_versionMin(int $version):void{
  369. $this->setMinMaxVersion($version, $this->versionMax);
  370. }
  371. /**
  372. * sets the maximum version number
  373. */
  374. protected function set_versionMax(int $version):void{
  375. $this->setMinMaxVersion($this->versionMin, $version);
  376. }
  377. /**
  378. * sets/clamps the version number
  379. */
  380. protected function set_version(int $version):void{
  381. $this->version = ($version !== Version::AUTO) ? max(1, min(40, $version)) : Version::AUTO;
  382. }
  383. /**
  384. * sets/clamps the quiet zone size
  385. */
  386. protected function set_quietzoneSize(int $quietzoneSize):void{
  387. $this->quietzoneSize = max(0, min($quietzoneSize, 75));
  388. }
  389. /**
  390. * sets the FPDF measurement unit
  391. *
  392. * @codeCoverageIgnore
  393. */
  394. protected function set_fpdfMeasureUnit(string $unit):void{
  395. $unit = strtolower($unit);
  396. if(in_array($unit, ['cm', 'in', 'mm', 'pt'], true)){
  397. $this->fpdfMeasureUnit = $unit;
  398. }
  399. // @todo throw or ignore silently?
  400. }
  401. /**
  402. * enables Imagick for the QR Code reader if the extension is available
  403. */
  404. protected function set_readerUseImagickIfAvailable(bool $useImagickIfAvailable):void{
  405. $this->readerUseImagickIfAvailable = ($useImagickIfAvailable && extension_loaded('imagick'));
  406. }
  407. /**
  408. * clamp the logo space values between 0 and maximum length (177 modules at version 40)
  409. */
  410. protected function clampLogoSpaceValue(?int $value):?int{
  411. if($value === null){
  412. return null;
  413. }
  414. return (int)max(0, min(177, $value));
  415. }
  416. /**
  417. * clamp/set logo space width
  418. */
  419. protected function set_logoSpaceWidth(?int $value):void{
  420. $this->logoSpaceWidth = $this->clampLogoSpaceValue($value);
  421. }
  422. /**
  423. * clamp/set logo space height
  424. */
  425. protected function set_logoSpaceHeight(?int $value):void{
  426. $this->logoSpaceHeight = $this->clampLogoSpaceValue($value);
  427. }
  428. /**
  429. * clamp/set horizontal logo space start
  430. */
  431. protected function set_logoSpaceStartX(?int $value):void{
  432. $this->logoSpaceStartX = $this->clampLogoSpaceValue($value);
  433. }
  434. /**
  435. * clamp/set vertical logo space start
  436. */
  437. protected function set_logoSpaceStartY(?int $value):void{
  438. $this->logoSpaceStartY = $this->clampLogoSpaceValue($value);
  439. }
  440. /**
  441. * clamp/set SVG circle radius
  442. */
  443. protected function set_circleRadius(float $circleRadius):void{
  444. $this->circleRadius = max(0.1, min(0.75, $circleRadius));
  445. }
  446. /**
  447. * redirect call to the new variable
  448. *
  449. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  450. * @see \chillerlan\QRCode\QROptions::$outputBase64
  451. */
  452. protected function set_imageBase64(bool $imageBase64):void{
  453. $this->outputBase64 = $imageBase64;
  454. }
  455. /**
  456. * redirect call to the new variable
  457. *
  458. * @deprecated 5.0.0 use QROptions::$outputBase64 instead
  459. * @see \chillerlan\QRCode\QROptions::$outputBase64
  460. */
  461. protected function get_imageBase64():bool{
  462. return $this->outputBase64;
  463. }
  464. }