SproutCMS

This is the code documentation for the SproutCMS project

source of /sprout/Helpers/phpqrcode/qrencode.php

  1. <?php
  2. /*
  3.  * PHP QR Code encoder
  4.  *
  5.  * Main encoder classes.
  6.  *
  7.  * Based on libqrencode C library distributed under LGPL 2.1
  8.  * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
  9.  *
  10.  * PHP QR Code is distributed under LGPL 3
  11.  * Copyright (C) 2010 Dominik Dzienia <deltalab at poczta dot fm>
  12.  *
  13.  * This library is free software; you can redistribute it and/or
  14.  * modify it under the terms of the GNU Lesser General Public
  15.  * License as published by the Free Software Foundation; either
  16.  * version 3 of the License, or any later version.
  17.  *
  18.  * This library is distributed in the hope that it will be useful,
  19.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21.  * Lesser General Public License for more details.
  22.  *
  23.  * You should have received a copy of the GNU Lesser General Public
  24.  * License along with this library; if not, write to the Free Software
  25.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  26.  */
  27.  
  28. class QRrsblock {
  29. public $dataLength;
  30. public $data = array();
  31. public $eccLength;
  32. public $ecc = array();
  33.  
  34. public function __construct($dl, $data, $el, &$ecc, QRrsItem $rs)
  35. {
  36. $rs->encode_rs_char($data, $ecc);
  37.  
  38. $this->dataLength = $dl;
  39. $this->data = $data;
  40. $this->eccLength = $el;
  41. $this->ecc = $ecc;
  42. }
  43. };
  44.  
  45. //##########################################################################
  46.  
  47. class QRrawcode {
  48. public $version;
  49. public $datacode = array();
  50. public $ecccode = array();
  51. public $blocks;
  52. public $rsblocks = array(); //of RSblock
  53. public $count;
  54. public $dataLength;
  55. public $eccLength;
  56. public $b1;
  57.  
  58. //----------------------------------------------------------------------
  59. public function __construct(QRinput $input)
  60. {
  61. $spec = array(0,0,0,0,0);
  62.  
  63. $this->datacode = $input->getByteStream();
  64. if(is_null($this->datacode)) {
  65. throw new Exception('null imput string');
  66. }
  67.  
  68. QRspec::getEccSpec($input->getVersion(), $input->getErrorCorrectionLevel(), $spec);
  69.  
  70. $this->version = $input->getVersion();
  71. $this->b1 = QRspec::rsBlockNum1($spec);
  72. $this->dataLength = QRspec::rsDataLength($spec);
  73. $this->eccLength = QRspec::rsEccLength($spec);
  74. $this->ecccode = array_fill(0, $this->eccLength, 0);
  75. $this->blocks = QRspec::rsBlockNum($spec);
  76.  
  77. $ret = $this->init($spec);
  78. if($ret < 0) {
  79. throw new Exception('block alloc error');
  80. return null;
  81. }
  82.  
  83. $this->count = 0;
  84. }
  85.  
  86. //----------------------------------------------------------------------
  87. public function init(array $spec)
  88. {
  89. $dl = QRspec::rsDataCodes1($spec);
  90. $el = QRspec::rsEccCodes1($spec);
  91. $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
  92.  
  93.  
  94. $blockNo = 0;
  95. $dataPos = 0;
  96. $eccPos = 0;
  97. for($i=0; $i<QRspec::rsBlockNum1($spec); $i++) {
  98. $ecc = array_slice($this->ecccode,$eccPos);
  99. $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
  100. $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
  101.  
  102. $dataPos += $dl;
  103. $eccPos += $el;
  104. $blockNo++;
  105. }
  106.  
  107. if(QRspec::rsBlockNum2($spec) == 0)
  108. return 0;
  109.  
  110. $dl = QRspec::rsDataCodes2($spec);
  111. $el = QRspec::rsEccCodes2($spec);
  112. $rs = QRrs::init_rs(8, 0x11d, 0, 1, $el, 255 - $dl - $el);
  113.  
  114. if($rs == NULL) return -1;
  115.  
  116. for($i=0; $i<QRspec::rsBlockNum2($spec); $i++) {
  117. $ecc = array_slice($this->ecccode,$eccPos);
  118. $this->rsblocks[$blockNo] = new QRrsblock($dl, array_slice($this->datacode, $dataPos), $el, $ecc, $rs);
  119. $this->ecccode = array_merge(array_slice($this->ecccode,0, $eccPos), $ecc);
  120.  
  121. $dataPos += $dl;
  122. $eccPos += $el;
  123. $blockNo++;
  124. }
  125.  
  126. return 0;
  127. }
  128.  
  129. //----------------------------------------------------------------------
  130. public function getCode()
  131. {
  132. $ret = NULL;
  133.  
  134. if($this->count < $this->dataLength) {
  135. $row = $this->count % $this->blocks;
  136. $col = $this->count / $this->blocks;
  137. if($col >= $this->rsblocks[0]->dataLength) {
  138. $row += $this->b1;
  139. }
  140. $ret = $this->rsblocks[$row]->data[$col];
  141. } else if($this->count < $this->dataLength + $this->eccLength) {
  142. $row = ($this->count - $this->dataLength) % $this->blocks;
  143. $col = ($this->count - $this->dataLength) / $this->blocks;
  144. $ret = $this->rsblocks[$row]->ecc[$col];
  145. } else {
  146. return 0;
  147. }
  148. $this->count++;
  149.  
  150. return $ret;
  151. }
  152. }
  153.  
  154. //##########################################################################
  155.  
  156. class QRcode {
  157.  
  158. public $version;
  159. public $width;
  160. public $data;
  161.  
  162. //----------------------------------------------------------------------
  163. public function encodeMask(QRinput $input, $mask)
  164. {
  165. if($input->getVersion() < 0 || $input->getVersion() > QRSPEC_VERSION_MAX) {
  166. throw new Exception('wrong version');
  167. }
  168. if($input->getErrorCorrectionLevel() > QR_ECLEVEL_H) {
  169. throw new Exception('wrong level');
  170. }
  171.  
  172. $raw = new QRrawcode($input);
  173.  
  174. QRtools::markTime('after_raw');
  175.  
  176. $version = $raw->version;
  177. $width = QRspec::getWidth($version);
  178. $frame = QRspec::newFrame($version);
  179.  
  180. $filler = new FrameFiller($width, $frame);
  181. if(is_null($filler)) {
  182. return NULL;
  183. }
  184.  
  185. // inteleaved data and ecc codes
  186. for($i=0; $i<$raw->dataLength + $raw->eccLength; $i++) {
  187. $code = $raw->getCode();
  188. $bit = 0x80;
  189. for($j=0; $j<8; $j++) {
  190. $addr = $filler->next();
  191. $filler->setFrameAt($addr, 0x02 | (($bit & $code) != 0));
  192. $bit = $bit >> 1;
  193. }
  194. }
  195.  
  196. QRtools::markTime('after_filler');
  197.  
  198. unset($raw);
  199.  
  200. // remainder bits
  201. $j = QRspec::getRemainder($version);
  202. for($i=0; $i<$j; $i++) {
  203. $addr = $filler->next();
  204. $filler->setFrameAt($addr, 0x02);
  205. }
  206.  
  207. $frame = $filler->frame;
  208. unset($filler);
  209.  
  210.  
  211. // masking
  212. $maskObj = new QRmask();
  213. if($mask < 0) {
  214.  
  215. if (QR_FIND_BEST_MASK) {
  216. $masked = $maskObj->mask($width, $frame, $input->getErrorCorrectionLevel());
  217. } else {
  218. $masked = $maskObj->makeMask($width, $frame, (intval(QR_DEFAULT_MASK) % 8), $input->getErrorCorrectionLevel());
  219. }
  220. } else {
  221. $masked = $maskObj->makeMask($width, $frame, $mask, $input->getErrorCorrectionLevel());
  222. }
  223.  
  224. if($masked == NULL) {
  225. return NULL;
  226. }
  227.  
  228. QRtools::markTime('after_mask');
  229.  
  230. $this->version = $version;
  231. $this->width = $width;
  232. $this->data = $masked;
  233.  
  234. return $this;
  235. }
  236.  
  237. //----------------------------------------------------------------------
  238. public function encodeInput(QRinput $input)
  239. {
  240. return $this->encodeMask($input, -1);
  241. }
  242.  
  243. //----------------------------------------------------------------------
  244. public function encodeString8bit($string, $version, $level)
  245. {
  246. if($string == NULL) {
  247. throw new Exception('empty string!');
  248. return NULL;
  249. }
  250.  
  251. $input = new QRinput($version, $level);
  252. if($input == NULL) return NULL;
  253.  
  254. $ret = $input->append($input, QR_MODE_8, strlen($string), str_split($string));
  255. if($ret < 0) {
  256. unset($input);
  257. return NULL;
  258. }
  259. return $this->encodeInput($input);
  260. }
  261.  
  262. //----------------------------------------------------------------------
  263. public function encodeString($string, $version, $level, $hint, $casesensitive)
  264. {
  265.  
  266. if($hint != QR_MODE_8 && $hint != QR_MODE_KANJI) {
  267. throw new Exception('bad hint');
  268. return NULL;
  269. }
  270.  
  271. $input = new QRinput($version, $level);
  272. if($input == NULL) return NULL;
  273.  
  274. $ret = QRsplit::splitStringToQRinput($string, $input, $hint, $casesensitive);
  275. if($ret < 0) {
  276. return NULL;
  277. }
  278.  
  279. return $this->encodeInput($input);
  280. }
  281.  
  282. //----------------------------------------------------------------------
  283. public static function png($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000)
  284. {
  285. $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color);
  286. return $enc->encodePNG($text, $outfile, $saveandprint=false);
  287. }
  288.  
  289. //----------------------------------------------------------------------
  290. public static function text($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
  291. {
  292. $enc = QRencode::factory($level, $size, $margin);
  293. return $enc->encode($text, $outfile);
  294. }
  295.  
  296. //----------------------------------------------------------------------
  297. public static function eps($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false)
  298. {
  299. $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color, $cmyk);
  300. return $enc->encodeEPS($text, $outfile, $saveandprint=false);
  301. }
  302.  
  303. //----------------------------------------------------------------------
  304. public static function svg($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4, $saveandprint=false, $back_color = 0xFFFFFF, $fore_color = 0x000000)
  305. {
  306. $enc = QRencode::factory($level, $size, $margin, $back_color, $fore_color);
  307. return $enc->encodeSVG($text, $outfile, $saveandprint=false);
  308. }
  309.  
  310. //----------------------------------------------------------------------
  311. public static function raw($text, $outfile = false, $level = QR_ECLEVEL_L, $size = 3, $margin = 4)
  312. {
  313. $enc = QRencode::factory($level, $size, $margin);
  314. return $enc->encodeRAW($text, $outfile);
  315. }
  316. }
  317.  
  318. //##########################################################################
  319.  
  320. class FrameFiller {
  321.  
  322. public $width;
  323. public $frame;
  324. public $x;
  325. public $y;
  326. public $dir;
  327. public $bit;
  328.  
  329. //----------------------------------------------------------------------
  330. public function __construct($width, &$frame)
  331. {
  332. $this->width = $width;
  333. $this->frame = $frame;
  334. $this->x = $width - 1;
  335. $this->y = $width - 1;
  336. $this->dir = -1;
  337. $this->bit = -1;
  338. }
  339.  
  340. //----------------------------------------------------------------------
  341. public function setFrameAt($at, $val)
  342. {
  343. $this->frame[$at['y']][$at['x']] = chr($val);
  344. }
  345.  
  346. //----------------------------------------------------------------------
  347. public function getFrameAt($at)
  348. {
  349. return ord($this->frame[$at['y']][$at['x']]);
  350. }
  351.  
  352. //----------------------------------------------------------------------
  353. public function next()
  354. {
  355. do {
  356.  
  357. if($this->bit == -1) {
  358. $this->bit = 0;
  359. return array('x'=>$this->x, 'y'=>$this->y);
  360. }
  361.  
  362. $x = $this->x;
  363. $y = $this->y;
  364. $w = $this->width;
  365.  
  366. if($this->bit == 0) {
  367. $x--;
  368. $this->bit++;
  369. } else {
  370. $x++;
  371. $y += $this->dir;
  372. $this->bit--;
  373. }
  374.  
  375. if($this->dir < 0) {
  376. if($y < 0) {
  377. $y = 0;
  378. $x -= 2;
  379. $this->dir = 1;
  380. if($x == 6) {
  381. $x--;
  382. $y = 9;
  383. }
  384. }
  385. } else {
  386. if($y == $w) {
  387. $y = $w - 1;
  388. $x -= 2;
  389. $this->dir = -1;
  390. if($x == 6) {
  391. $x--;
  392. $y -= 8;
  393. }
  394. }
  395. }
  396. if($x < 0 || $y < 0) return null;
  397.  
  398. $this->x = $x;
  399. $this->y = $y;
  400.  
  401. } while(ord($this->frame[$y][$x]) & 0x80);
  402.  
  403. return array('x'=>$x, 'y'=>$y);
  404. }
  405.  
  406. } ;
  407.  
  408. //##########################################################################
  409.  
  410. class QRencode {
  411.  
  412. public $casesensitive = true;
  413. public $eightbit = false;
  414.  
  415. public $version = 0;
  416. public $size = 3;
  417. public $margin = 4;
  418. public $back_color = 0xFFFFFF;
  419. public $fore_color = 0x000000;
  420.  
  421. public $structured = 0; // not supported yet
  422.  
  423. public $level = QR_ECLEVEL_L;
  424. public $hint = QR_MODE_8;
  425.  
  426. //----------------------------------------------------------------------
  427. public static function factory($level = QR_ECLEVEL_L, $size = 3, $margin = 4, $back_color = 0xFFFFFF, $fore_color = 0x000000, $cmyk = false)
  428. {
  429. $enc = new QRencode();
  430. $enc->size = $size;
  431. $enc->margin = $margin;
  432. $enc->fore_color = $fore_color;
  433. $enc->back_color = $back_color;
  434. $enc->cmyk = $cmyk;
  435.  
  436. switch ($level.'') {
  437. case '0':
  438. case '1':
  439. case '2':
  440. case '3':
  441. $enc->level = $level;
  442. break;
  443. case 'l':
  444. case 'L':
  445. $enc->level = QR_ECLEVEL_L;
  446. break;
  447. case 'm':
  448. case 'M':
  449. $enc->level = QR_ECLEVEL_M;
  450. break;
  451. case 'q':
  452. case 'Q':
  453. $enc->level = QR_ECLEVEL_Q;
  454. break;
  455. case 'h':
  456. case 'H':
  457. $enc->level = QR_ECLEVEL_H;
  458. break;
  459. }
  460.  
  461. return $enc;
  462. }
  463.  
  464. //----------------------------------------------------------------------
  465. public function encodeRAW($intext, $outfile = false)
  466. {
  467. $code = new QRcode();
  468.  
  469. if($this->eightbit) {
  470. $code->encodeString8bit($intext, $this->version, $this->level);
  471. } else {
  472. $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
  473. }
  474.  
  475. return $code->data;
  476. }
  477.  
  478. //----------------------------------------------------------------------
  479. public function encode($intext, $outfile = false)
  480. {
  481. $code = new QRcode();
  482.  
  483. if($this->eightbit) {
  484. $code->encodeString8bit($intext, $this->version, $this->level);
  485. } else {
  486. $code->encodeString($intext, $this->version, $this->level, $this->hint, $this->casesensitive);
  487. }
  488.  
  489. QRtools::markTime('after_encode');
  490.  
  491. if ($outfile!== false) {
  492. file_put_contents($outfile, join("\n", QRtools::binarize($code->data)));
  493. } else {
  494. return QRtools::binarize($code->data);
  495. }
  496. }
  497.  
  498. //----------------------------------------------------------------------
  499. public function encodePNG($intext, $outfile = false,$saveandprint=false)
  500. {
  501. try {
  502.  
  503. $tab = $this->encode($intext);
  504. $err = ob_get_contents();
  505.  
  506. if ($err != '')
  507. QRtools::log($outfile, $err);
  508.  
  509. $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
  510.  
  511. QRimage::png($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color);
  512.  
  513. } catch (Exception $e) {
  514.  
  515. QRtools::log($outfile, $e->getMessage());
  516.  
  517. }
  518. }
  519.  
  520. //----------------------------------------------------------------------
  521. public function encodeEPS($intext, $outfile = false,$saveandprint=false)
  522. {
  523. try {
  524.  
  525. $tab = $this->encode($intext);
  526. $err = ob_get_contents();
  527.  
  528. if ($err != '')
  529. QRtools::log($outfile, $err);
  530.  
  531. $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
  532.  
  533. QRvect::eps($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color, $this->cmyk);
  534.  
  535. } catch (Exception $e) {
  536.  
  537. QRtools::log($outfile, $e->getMessage());
  538.  
  539. }
  540. }
  541.  
  542. //----------------------------------------------------------------------
  543. public function encodeSVG($intext, $outfile = false,$saveandprint=false)
  544. {
  545. try {
  546.  
  547. $tab = $this->encode($intext);
  548. $err = ob_get_contents();
  549.  
  550. if ($err != '')
  551. QRtools::log($outfile, $err);
  552.  
  553. $maxSize = (int)(QR_PNG_MAXIMUM_SIZE / (count($tab)+2*$this->margin));
  554.  
  555. QRvect::svg($tab, $outfile, min(max(1, $this->size), $maxSize), $this->margin,$saveandprint, $this->back_color, $this->fore_color);
  556.  
  557. } catch (Exception $e) {
  558.  
  559. QRtools::log($outfile, $e->getMessage());
  560.  
  561. }
  562. }
  563. }
  564.