RGBLuminanceSource.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <?php
  2. /*
  3. * Copyright 2009 ZXing authors
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. namespace Zxing;
  18. /**
  19. * This class is used to help decode images from files which arrive as RGB data from
  20. * an ARGB pixel array. It does not support rotation.
  21. *
  22. * @author dswitkin@google.com (Daniel Switkin)
  23. * @author Betaminos
  24. */
  25. final class RGBLuminanceSource extends LuminanceSource {
  26. public $luminances;
  27. private $dataWidth;
  28. private $dataHeight;
  29. private $left;
  30. private $top;
  31. private $pixels;
  32. public function __construct($pixels,
  33. $dataWidth,
  34. $dataHeight,
  35. $left=null,
  36. $top=null,
  37. $width=null,
  38. $height=null) {
  39. if(!$left&&!$top&&!$width&&!$height){
  40. $this->RGBLuminanceSource_($pixels,$dataWidth,$dataHeight);
  41. return;
  42. }
  43. parent::__construct($width, $height);
  44. if ($left + $width > $dataWidth || $top + $height > $dataHeight) {
  45. throw new \InvalidArgumentException("Crop rectangle does not fit within image data.");
  46. }
  47. $this->luminances = $pixels;
  48. $this->dataWidth = $dataWidth;
  49. $this->dataHeight = $dataHeight;
  50. $this->left = $left;
  51. $this->top = $top;
  52. }
  53. public function RGBLuminanceSource_($width, $height, $pixels)
  54. {
  55. parent::__construct($width, $height);
  56. $this->dataWidth = $width;
  57. $this->dataHeight = $height;
  58. $this->left = 0;
  59. $this->top = 0;
  60. $this->pixels = $pixels;
  61. // In order to measure pure decoding speed, we convert the entire image to a greyscale array
  62. // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app.
  63. $this->luminances = array();
  64. //$this->luminances = $this->grayScaleToBitmap($this->grayscale());
  65. foreach ($pixels as $key => $pixel) {
  66. $r = $pixel['red'];
  67. $g = $pixel['green'];
  68. $b = $pixel['blue'];
  69. /* if (($pixel & 0xFF000000) == 0) {
  70. $pixel = 0xFFFFFFFF; // = white
  71. }
  72. // .229R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC)
  73. $this->luminances[$key] =
  74. (306 * (($pixel >> 16) & 0xFF) +
  75. 601 * (($pixel >> 8) & 0xFF) +
  76. 117 * ($pixel & 0xFF) +
  77. 0x200) >> 10;
  78. */
  79. //$r = ($pixel >> 16) & 0xff;
  80. //$g = ($pixel >> 8) & 0xff;
  81. //$b = $pixel & 0xff;
  82. if ($r == $g && $g == $b) {
  83. // Image is already greyscale, so pick any channel.
  84. $this->luminances[$key] = $r;//(($r + 128) % 256) - 128;
  85. } else {
  86. // Calculate luminance cheaply, favoring green.
  87. $this->luminances[$key] = ($r+2*$g+$b)/4;//(((($r + 2 * $g + $b) / 4) + 128) % 256) - 128;
  88. }
  89. }
  90. /*
  91. for ($y = 0; $y < $height; $y++) {
  92. $offset = $y * $width;
  93. for ($x = 0; $x < $width; $x++) {
  94. $pixel = $pixels[$offset + $x];
  95. $r = ($pixel >> 16) & 0xff;
  96. $g = ($pixel >> 8) & 0xff;
  97. $b = $pixel & 0xff;
  98. if ($r == $g && $g == $b) {
  99. // Image is already greyscale, so pick any channel.
  100. $this->luminances[intval($offset + $x)] = (($r+128) % 256) - 128;
  101. } else {
  102. // Calculate luminance cheaply, favoring green.
  103. $this->luminances[intval($offset + $x)] = (((($r + 2 * $g + $b) / 4)+128)%256) - 128;
  104. }
  105. }
  106. */
  107. //}
  108. // $this->luminances = $this->grayScaleToBitmap($this->luminances);
  109. }
  110. function grayscale(){
  111. $width = $this->dataWidth;
  112. $height = $this->dataHeight;
  113. $ret = fill_array(0, $width*$height,0);
  114. for ($y = 0; $y < $height; $y++)
  115. {
  116. for ($x = 0; $x < $width; $x++)
  117. {
  118. $gray = $this->getPixel($x, $y,$width,$height);
  119. $ret[$x+$y*$width] = $gray;
  120. }
  121. }
  122. return $ret;
  123. }
  124. function getPixel($x,$y,$width,$height){
  125. $image = $this->pixels;
  126. if ($width < $x) {
  127. die('error');
  128. }
  129. if ($height < $y) {
  130. die('error');
  131. }
  132. $point = ($x) + ($y * $width);
  133. $r = $image[$point]['red'];//($image[$point] >> 16) & 0xff;
  134. $g = $image[$point]['green'];//($image[$point] >> 8) & 0xff;
  135. $b = $image[$point]['blue'];//$image[$point] & 0xff;
  136. $p = intval(($r*33 +$g*34 + $b*33)/100);
  137. return $p;
  138. }
  139. function getMiddleBrightnessPerArea($image)
  140. {
  141. $numSqrtArea = 4;
  142. //obtain middle brightness((min + max) / 2) per area
  143. $areaWidth = floor($this->dataWidth / $numSqrtArea);
  144. $areaHeight = floor($this->dataHeight / $numSqrtArea);
  145. $minmax = fill_array(0,$numSqrtArea,0);
  146. for ($i = 0; $i < $numSqrtArea; $i++)
  147. {
  148. $minmax[$i] = fill_array(0,$numSqrtArea,0);
  149. for ($i2 = 0; $i2 < $numSqrtArea; $i2++)
  150. {
  151. $minmax[$i][$i2] = array(0,0);
  152. }
  153. }
  154. for ($ay = 0; $ay < $numSqrtArea; $ay++)
  155. {
  156. for ($ax = 0; $ax < $numSqrtArea; $ax++)
  157. {
  158. $minmax[$ax][$ay][0] = 0xFF;
  159. for ($dy = 0; $dy < $areaHeight; $dy++)
  160. {
  161. for ($dx = 0; $dx < $areaWidth; $dx++)
  162. {
  163. $target = $image[intval($areaWidth * $ax + $dx+($areaHeight * $ay + $dy)*$this->dataWidth)];
  164. if ($target < $minmax[$ax][$ay][0])
  165. $minmax[$ax][$ay][0] = $target;
  166. if ($target > $minmax[$ax][$ay][1])
  167. $minmax[$ax][$ay][1] = $target;
  168. }
  169. }
  170. //minmax[ax][ay][0] = (minmax[ax][ay][0] + minmax[ax][ay][1]) / 2;
  171. }
  172. }
  173. $middle = array();
  174. for ($i3 = 0; $i3 < $numSqrtArea; $i3++)
  175. {
  176. $middle[$i3] = array();
  177. }
  178. for ($ay = 0; $ay < $numSqrtArea; $ay++)
  179. {
  180. for ($ax = 0; $ax < $numSqrtArea; $ax++)
  181. {
  182. $middle[$ax][$ay] = floor(($minmax[$ax][$ay][0] + $minmax[$ax][$ay][1]) / 2);
  183. //Console.out.print(middle[ax][ay] + ",");
  184. }
  185. //Console.out.println("");
  186. }
  187. //Console.out.println("");
  188. return $middle;
  189. }
  190. function grayScaleToBitmap ($grayScale)
  191. {
  192. $middle = $this->getMiddleBrightnessPerArea($grayScale);
  193. $sqrtNumArea = count($middle);
  194. $areaWidth = floor($this->dataWidth/ $sqrtNumArea);
  195. $areaHeight = floor($this->dataHeight / $sqrtNumArea);
  196. $bitmap = fill_array(0,$this->dataWidth*$this->dataHeight,0);
  197. for ($ay = 0; $ay < $sqrtNumArea; $ay++)
  198. {
  199. for ($ax = 0; $ax < $sqrtNumArea; $ax++)
  200. {
  201. for ($dy = 0; $dy < $areaHeight; $dy++)
  202. {
  203. for ($dx = 0; $dx < $areaWidth; $dx++)
  204. {
  205. $bitmap[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] = ($grayScale[intval($areaWidth * $ax + $dx+ ($areaHeight * $ay + $dy)*$this->dataWidth)] < $middle[$ax][$ay])?0:255;
  206. }
  207. }
  208. }
  209. }
  210. return $bitmap;
  211. }
  212. //@Override
  213. public function getRow($y, $row=null) {
  214. if ($y < 0 || $y >= $this->getHeight()) {
  215. throw new \InvalidArgumentException("Requested row is outside the image: " + y);
  216. }
  217. $width = $this->getWidth();
  218. if ($row == null || count($row) < $width) {
  219. $row = array();
  220. }
  221. $offset = ($y + $this->top) * $this->dataWidth + $this->left;
  222. $row = arraycopy($this->luminances,$offset, $row, 0, $width);
  223. return $row;
  224. }
  225. //@Override
  226. public function getMatrix() {
  227. $width = $this->getWidth();
  228. $height = $this->getHeight();
  229. // If the caller asks for the entire underlying image, save the copy and give them the
  230. // original data. The docs specifically warn that result.length must be ignored.
  231. if ($width == $this->dataWidth && $height == $this->dataHeight) {
  232. return $this->luminances;
  233. }
  234. $area = $width * $height;
  235. $matrix = array();
  236. $inputOffset = $this->top * $this->dataWidth + $this->left;
  237. // If the width matches the full width of the underlying data, perform a single copy.
  238. if ($width == $this->dataWidth) {
  239. $matrix = arraycopy($this->luminances, $inputOffset, $matrix, 0, $area);
  240. return $matrix;
  241. }
  242. // Otherwise copy one cropped row at a time.
  243. $rgb = $this->luminances;
  244. for ($y = 0; $y < $height; $y++) {
  245. $outputOffset = $y * $width;
  246. $matrix = arraycopy($rgb, $inputOffset, $matrix, $outputOffset, $width);
  247. $inputOffset += $this->dataWidth;
  248. }
  249. return $matrix;
  250. }
  251. //@Override
  252. public function isCropSupported() {
  253. return true;
  254. }
  255. //@Override
  256. public function crop($left, $top, $width, $height) {
  257. return new RGBLuminanceSource($this->luminances,
  258. $this->dataWidth,
  259. $this->dataHeight,
  260. $this->left + $left,
  261. $this->top + $top,
  262. $width,
  263. $height);
  264. }
  265. }