QREps.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. <?php
  2. /**
  3. * Class QREps
  4. *
  5. * @created 09.05.2022
  6. * @author smiley <smiley@chillerlan.net>
  7. * @copyright 2022 smiley
  8. * @license MIT
  9. */
  10. namespace chillerlan\QRCode\Output;
  11. use function count, date, implode, is_array, is_numeric, max, min, round, sprintf;
  12. /**
  13. * Encapsulated Postscript (EPS) output
  14. *
  15. * @see https://github.com/t0k4rt/phpqrcode/blob/bb29e6eb77e0a2a85bb0eb62725e0adc11ff5a90/qrvect.php#L52-L137
  16. * @see https://web.archive.org/web/20170818010030/http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/postscript/pdfs/5002.EPSF_Spec.pdf
  17. * @see https://web.archive.org/web/20210419003859/https://www.adobe.com/content/dam/acom/en/devnet/actionscript/articles/PLRM.pdf
  18. * @see https://github.com/chillerlan/php-qrcode/discussions/148
  19. */
  20. class QREps extends QROutputAbstract{
  21. /**
  22. * @inheritDoc
  23. */
  24. public static function moduleValueIsValid($value):bool{
  25. if(!is_array($value) || count($value) < 3){
  26. return false;
  27. }
  28. // check the first 3 values of the array
  29. for($i = 0; $i < 3; $i++){
  30. if(!is_numeric($value[$i])){
  31. return false;
  32. }
  33. }
  34. return true;
  35. }
  36. /**
  37. * @inheritDoc
  38. */
  39. protected function getModuleValue($value):array{
  40. $val = [];
  41. for($i = 0; $i < 3; $i++){
  42. // clamp value and convert from 0-255 to 0-1 RGB range
  43. $val[] = round((max(0, min(255, $value[$i])) / 255), 6);
  44. }
  45. return $val;
  46. }
  47. /**
  48. * @inheritDoc
  49. */
  50. protected function getDefaultModuleValue(bool $isDark):array{
  51. return ($isDark) ? [0.0, 0.0, 0.0] : [1.0, 1.0, 1.0];
  52. }
  53. /**
  54. * @inheritDoc
  55. */
  56. public function dump(string $file = null):string{
  57. $eps = [
  58. // main header
  59. '%!PS-Adobe-3.0 EPSF-3.0',
  60. '%%Creator: php-qrcode (https://github.com/chillerlan/php-qrcode)',
  61. '%%Title: QR Code',
  62. sprintf('%%%%CreationDate: %1$s', date('c')),
  63. '%%DocumentData: Clean7Bit',
  64. '%%LanguageLevel: 3',
  65. sprintf('%%%%BoundingBox: 0 0 %1$s %1$s', $this->length),
  66. '%%EndComments',
  67. // function definitions
  68. '%%BeginProlog',
  69. '/F { rectfill } def',
  70. '/S { setrgbcolor } def',
  71. '%%EndProlog',
  72. ];
  73. // create the path elements
  74. $paths = $this->collectModules(fn(int $x, int $y):string => $this->module($x, $y));
  75. foreach($paths as $M_TYPE => $path){
  76. if(empty($path)){
  77. continue;
  78. }
  79. $eps[] = sprintf('%f %f %f S', ...$this->moduleValues[$M_TYPE]);
  80. $eps[] = implode("\n", $path);
  81. }
  82. // end file
  83. $eps[] = '%%EOF';
  84. $data = implode("\n", $eps);
  85. $this->saveToFile($data, $file);
  86. return $data;
  87. }
  88. /**
  89. * returns a path segment for a single module
  90. */
  91. protected function module(int $x, int $y):string{
  92. if(!$this->options->drawLightModules && !$this->matrix->check($x, $y)){
  93. return '';
  94. }
  95. $outputX = ($x * $this->scale);
  96. // Actual size - one block = Topmost y pos.
  97. $top = ($this->length - $this->scale);
  98. // Apparently y-axis is inverted (y0 is at bottom and not top) in EPS, so we have to switch the y-axis here
  99. $outputY = ($top - ($y * $this->scale));
  100. return sprintf('%d %d %d %d F', $outputX, $outputY, $this->scale, $this->scale);
  101. }
  102. }