You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 lines
7.1KB

  1. <?php
  2. class bmp
  3. {
  4. var $mpdf = null;
  5. public function __construct(mPDF $mpdf)
  6. {
  7. $this->mpdf = $mpdf;
  8. }
  9. function _getBMPimage($data, $file)
  10. {
  11. $info = array();
  12. // Adapted from script by Valentin Schmidt
  13. // http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/
  14. $bfOffBits = $this->_fourbytes2int_le(substr($data, 10, 4));
  15. $width = $this->_fourbytes2int_le(substr($data, 18, 4));
  16. $height = $this->_fourbytes2int_le(substr($data, 22, 4));
  17. $flip = ($height < 0);
  18. if ($flip)
  19. $height = -$height;
  20. $biBitCount = $this->_twobytes2int_le(substr($data, 28, 2));
  21. $biCompression = $this->_fourbytes2int_le(substr($data, 30, 4));
  22. $info = array('w' => $width, 'h' => $height);
  23. if ($biBitCount < 16) {
  24. $info['cs'] = 'Indexed';
  25. $info['bpc'] = $biBitCount;
  26. $palStr = substr($data, 54, ($bfOffBits - 54));
  27. $pal = '';
  28. $cnt = strlen($palStr) / 4;
  29. for ($i = 0; $i < $cnt; $i++) {
  30. $n = 4 * $i;
  31. $pal .= $palStr[$n + 2] . $palStr[$n + 1] . $palStr[$n];
  32. }
  33. $info['pal'] = $pal;
  34. } else {
  35. $info['cs'] = 'DeviceRGB';
  36. $info['bpc'] = 8;
  37. }
  38. if ($this->mpdf->restrictColorSpace == 1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace == 3) {
  39. if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
  40. $this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - " . $file . " - (Image replaced by 'no-image'.)";
  41. }
  42. return array('error' => "BMP Image cannot be converted to suitable colour space - " . $file . " - (Image replaced by 'no-image'.)");
  43. }
  44. $biXPelsPerMeter = $this->_fourbytes2int_le(substr($data, 38, 4)); // horizontal pixels per meter, usually set to zero
  45. //$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero
  46. $biXPelsPerMeter = round($biXPelsPerMeter / 1000 * 25.4);
  47. //$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4);
  48. $info['set-dpi'] = $biXPelsPerMeter;
  49. switch ($biCompression) {
  50. case 0:
  51. $str = substr($data, $bfOffBits);
  52. break;
  53. case 1: # BI_RLE8
  54. $str = $this->rle8_decode(substr($data, $bfOffBits), $width);
  55. break;
  56. case 2: # BI_RLE4
  57. $str = $this->rle4_decode(substr($data, $bfOffBits), $width);
  58. break;
  59. }
  60. $bmpdata = '';
  61. $padCnt = (4 - ceil(($width / (8 / $biBitCount))) % 4) % 4;
  62. switch ($biBitCount) {
  63. case 1:
  64. case 4:
  65. case 8:
  66. $w = floor($width / (8 / $biBitCount)) + ($width % (8 / $biBitCount) ? 1 : 0);
  67. $w_row = $w + $padCnt;
  68. if ($flip) {
  69. for ($y = 0; $y < $height; $y++) {
  70. $y0 = $y * $w_row;
  71. for ($x = 0; $x < $w; $x++)
  72. $bmpdata .= $str[$y0 + $x];
  73. }
  74. } else {
  75. for ($y = $height - 1; $y >= 0; $y--) {
  76. $y0 = $y * $w_row;
  77. for ($x = 0; $x < $w; $x++)
  78. $bmpdata .= $str[$y0 + $x];
  79. }
  80. }
  81. break;
  82. case 16:
  83. $w_row = $width * 2 + $padCnt;
  84. if ($flip) {
  85. for ($y = 0; $y < $height; $y++) {
  86. $y0 = $y * $w_row;
  87. for ($x = 0; $x < $width; $x++) {
  88. $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
  89. $b = ($n & 31) << 3;
  90. $g = ($n & 992) >> 2;
  91. $r = ($n & 31744) >> 7128;
  92. $bmpdata .= chr($r) . chr($g) . chr($b);
  93. }
  94. }
  95. } else {
  96. for ($y = $height - 1; $y >= 0; $y--) {
  97. $y0 = $y * $w_row;
  98. for ($x = 0; $x < $width; $x++) {
  99. $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
  100. $b = ($n & 31) << 3;
  101. $g = ($n & 992) >> 2;
  102. $r = ($n & 31744) >> 7;
  103. $bmpdata .= chr($r) . chr($g) . chr($b);
  104. }
  105. }
  106. }
  107. break;
  108. case 24:
  109. case 32:
  110. $byteCnt = $biBitCount / 8;
  111. $w_row = $width * $byteCnt + $padCnt;
  112. if ($flip) {
  113. for ($y = 0; $y < $height; $y++) {
  114. $y0 = $y * $w_row;
  115. for ($x = 0; $x < $width; $x++) {
  116. $i = $y0 + $x * $byteCnt; # + 1
  117. $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
  118. }
  119. }
  120. } else {
  121. for ($y = $height - 1; $y >= 0; $y--) {
  122. $y0 = $y * $w_row;
  123. for ($x = 0; $x < $width; $x++) {
  124. $i = $y0 + $x * $byteCnt; # + 1
  125. $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
  126. }
  127. }
  128. }
  129. break;
  130. default:
  131. return array('error' => 'Error parsing BMP image - Unsupported image biBitCount');
  132. }
  133. if ($this->mpdf->compress) {
  134. $bmpdata = gzcompress($bmpdata);
  135. $info['f'] = 'FlateDecode';
  136. }
  137. $info['data'] = $bmpdata;
  138. $info['type'] = 'bmp';
  139. return $info;
  140. }
  141. function _fourbytes2int_le($s)
  142. {
  143. //Read a 4-byte integer from string
  144. return (ord($s[3]) << 24) + (ord($s[2]) << 16) + (ord($s[1]) << 8) + ord($s[0]);
  145. }
  146. function _twobytes2int_le($s)
  147. {
  148. //Read a 2-byte integer from string
  149. return (ord(substr($s, 1, 1)) << 8) + ord(substr($s, 0, 1));
  150. }
  151. # Decoder for RLE8 compression in windows bitmaps
  152. # see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
  153. function rle8_decode($str, $width)
  154. {
  155. $lineWidth = $width + (3 - ($width - 1) % 4);
  156. $out = '';
  157. $cnt = strlen($str);
  158. for ($i = 0; $i < $cnt; $i++) {
  159. $o = ord($str[$i]);
  160. switch ($o) {
  161. case 0: # ESCAPE
  162. $i++;
  163. switch (ord($str[$i])) {
  164. case 0: # NEW LINE
  165. $padCnt = $lineWidth - strlen($out) % $lineWidth;
  166. if ($padCnt < $lineWidth)
  167. $out .= str_repeat(chr(0), $padCnt);# pad line
  168. break;
  169. case 1: # END OF FILE
  170. $padCnt = $lineWidth - strlen($out) % $lineWidth;
  171. if ($padCnt < $lineWidth)
  172. $out .= str_repeat(chr(0), $padCnt);# pad line
  173. break 3;
  174. case 2: # DELTA
  175. $i += 2;
  176. break;
  177. default: # ABSOLUTE MODE
  178. $num = ord($str[$i]);
  179. for ($j = 0; $j < $num; $j++)
  180. $out .= $str[++$i];
  181. if ($num % 2)
  182. $i++;
  183. }
  184. break;
  185. default:
  186. $out .= str_repeat($str[++$i], $o);
  187. }
  188. }
  189. return $out;
  190. }
  191. # Decoder for RLE4 compression in windows bitmaps
  192. # see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
  193. function rle4_decode($str, $width)
  194. {
  195. $w = floor($width / 2) + ($width % 2);
  196. $lineWidth = $w + (3 - ( ($width - 1) / 2) % 4);
  197. $pixels = array();
  198. $cnt = strlen($str);
  199. for ($i = 0; $i < $cnt; $i++) {
  200. $o = ord($str[$i]);
  201. switch ($o) {
  202. case 0: # ESCAPE
  203. $i++;
  204. switch (ord($str[$i])) {
  205. case 0: # NEW LINE
  206. while (count($pixels) % $lineWidth != 0)
  207. $pixels[] = 0;
  208. break;
  209. case 1: # END OF FILE
  210. while (count($pixels) % $lineWidth != 0)
  211. $pixels[] = 0;
  212. break 3;
  213. case 2: # DELTA
  214. $i += 2;
  215. break;
  216. default: # ABSOLUTE MODE
  217. $num = ord($str[$i]);
  218. for ($j = 0; $j < $num; $j++) {
  219. if ($j % 2 == 0) {
  220. $c = ord($str[++$i]);
  221. $pixels[] = ($c & 240) >> 4;
  222. } else
  223. $pixels[] = $c & 15;
  224. }
  225. if ($num % 2)
  226. $i++;
  227. }
  228. break;
  229. default:
  230. $c = ord($str[++$i]);
  231. for ($j = 0; $j < $o; $j++)
  232. $pixels[] = ($j % 2 == 0 ? ($c & 240) >> 4 : $c & 15);
  233. }
  234. }
  235. $out = '';
  236. if (count($pixels) % 2)
  237. $pixels[] = 0;
  238. $cnt = count($pixels) / 2;
  239. for ($i = 0; $i < $cnt; $i++)
  240. $out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]);
  241. return $out;
  242. }
  243. }