composer package updates
[openemr.git] / vendor / mpdf / mpdf / src / Image / Bmp.php
blob8df9c342ea8ff9f5a4cef2b68131cd8546358032
1 <?php
3 namespace Mpdf\Image;
5 use Mpdf\Mpdf;
7 class Bmp
10 /**
11 * @var Mpdf
13 private $mpdf;
15 public function __construct(Mpdf $mpdf)
17 $this->mpdf = $mpdf;
20 public function _getBMPimage($data, $file)
22 // Adapted from script by Valentin Schmidt
23 // http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/
24 $bfOffBits = $this->_fourbytes2int_le(substr($data, 10, 4));
25 $width = $this->_fourbytes2int_le(substr($data, 18, 4));
26 $height = $this->_fourbytes2int_le(substr($data, 22, 4));
27 $flip = ($height < 0);
28 if ($flip) {
29 $height = -$height;
31 $biBitCount = $this->_twobytes2int_le(substr($data, 28, 2));
32 $biCompression = $this->_fourbytes2int_le(substr($data, 30, 4));
33 $info = ['w' => $width, 'h' => $height];
34 if ($biBitCount < 16) {
35 $info['cs'] = 'Indexed';
36 $info['bpc'] = $biBitCount;
37 $palStr = substr($data, 54, $bfOffBits - 54);
38 $pal = '';
39 $cnt = strlen($palStr) / 4;
40 for ($i = 0; $i < $cnt; $i++) {
41 $n = 4 * $i;
42 $pal .= $palStr[$n + 2] . $palStr[$n + 1] . $palStr[$n];
44 $info['pal'] = $pal;
45 } else {
46 $info['cs'] = 'DeviceRGB';
47 $info['bpc'] = 8;
50 if ($this->mpdf->restrictColorSpace == 1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace == 3) {
51 if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) {
52 $this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - $file - (Image replaced by 'no-image'.)";
54 return ['error' => "BMP Image cannot be converted to suitable colour space - $file - (Image replaced by 'no-image'.)"];
57 $biXPelsPerMeter = $this->_fourbytes2int_le(substr($data, 38, 4)); // horizontal pixels per meter, usually set to zero
58 //$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero
59 $biXPelsPerMeter = round($biXPelsPerMeter / 1000 * 25.4);
60 //$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4);
61 $info['set-dpi'] = $biXPelsPerMeter;
63 switch ($biCompression) {
64 case 0:
65 $str = substr($data, $bfOffBits);
66 break;
67 case 1: # BI_RLE8
68 $str = $this->rle8_decode(substr($data, $bfOffBits), $width);
69 break;
70 case 2: # BI_RLE4
71 $str = $this->rle4_decode(substr($data, $bfOffBits), $width);
72 break;
74 $bmpdata = '';
75 $padCnt = (4 - ceil($width / (8 / $biBitCount)) % 4) % 4;
76 switch ($biBitCount) {
77 case 1:
78 case 4:
79 case 8:
80 $w = floor($width / (8 / $biBitCount)) + ($width % (8 / $biBitCount) ? 1 : 0);
81 $w_row = $w + $padCnt;
82 if ($flip) {
83 for ($y = 0; $y < $height; $y++) {
84 $y0 = $y * $w_row;
85 for ($x = 0; $x < $w; $x++) {
86 $bmpdata .= $str[$y0 + $x];
89 } else {
90 for ($y = $height - 1; $y >= 0; $y--) {
91 $y0 = $y * $w_row;
92 for ($x = 0; $x < $w; $x++) {
93 $bmpdata .= $str[$y0 + $x];
97 break;
99 case 16:
100 $w_row = $width * 2 + $padCnt;
101 if ($flip) {
102 for ($y = 0; $y < $height; $y++) {
103 $y0 = $y * $w_row;
104 for ($x = 0; $x < $width; $x++) {
105 $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
106 $b = ($n & 31) << 3;
107 $g = ($n & 992) >> 2;
108 $r = ($n & 31744) >> 7;
109 $bmpdata .= chr($r) . chr($g) . chr($b);
112 } else {
113 for ($y = $height - 1; $y >= 0; $y--) {
114 $y0 = $y * $w_row;
115 for ($x = 0; $x < $width; $x++) {
116 $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x]));
117 $b = ($n & 31) << 3;
118 $g = ($n & 992) >> 2;
119 $r = ($n & 31744) >> 7;
120 $bmpdata .= chr($r) . chr($g) . chr($b);
124 break;
126 case 24:
127 case 32:
128 $byteCnt = $biBitCount / 8;
129 $w_row = $width * $byteCnt + $padCnt;
131 if ($flip) {
132 for ($y = 0; $y < $height; $y++) {
133 $y0 = $y * $w_row;
134 for ($x = 0; $x < $width; $x++) {
135 $i = $y0 + $x * $byteCnt; # + 1
136 $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
139 } else {
140 for ($y = $height - 1; $y >= 0; $y--) {
141 $y0 = $y * $w_row;
142 for ($x = 0; $x < $width; $x++) {
143 $i = $y0 + $x * $byteCnt; # + 1
144 $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i];
148 break;
150 default:
151 return ['error' => 'Error parsing BMP image - Unsupported image biBitCount'];
153 if ($this->mpdf->compress) {
154 $bmpdata = gzcompress($bmpdata);
155 $info['f'] = 'FlateDecode';
157 $info['data'] = $bmpdata;
158 $info['type'] = 'bmp';
159 return $info;
163 * Read a 4-byte integer from string
165 * @param $s
166 * @return int
168 private function _fourbytes2int_le($s)
170 return (ord($s[3]) << 24) + (ord($s[2]) << 16) + (ord($s[1]) << 8) + ord($s[0]);
174 * Read a 2-byte integer from string
176 * @param $s
177 * @return int
179 private function _twobytes2int_le($s)
181 return (ord(substr($s, 1, 1)) << 8) + ord(substr($s, 0, 1));
185 * Decoder for RLE8 compression in windows bitmaps
187 * @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
188 * @param $str
189 * @param $width
190 * @return string
192 private function rle8_decode($str, $width)
194 $lineWidth = $width + (3 - ($width - 1) % 4);
195 $out = '';
196 $cnt = strlen($str);
197 for ($i = 0; $i < $cnt; $i++) {
198 $o = ord($str[$i]);
199 if ($o === 0) { # ESCAPE
200 $i++;
201 switch (ord($str[$i])) {
202 case 0: # NEW LINE
203 $padCnt = $lineWidth - strlen($out) % $lineWidth;
204 if ($padCnt < $lineWidth) {
205 $out .= str_repeat(chr(0), $padCnt);# pad line
207 break;
208 case 1: # END OF FILE
209 $padCnt = $lineWidth - strlen($out) % $lineWidth;
210 if ($padCnt < $lineWidth) {
211 $out .= str_repeat(chr(0), $padCnt);# pad line
213 break 2;
214 case 2: # DELTA
215 $i += 2;
216 break;
217 default: # ABSOLUTE MODE
218 $num = ord($str[$i]);
219 for ($j = 0; $j < $num; $j++) {
220 $out .= $str[++$i];
222 if ($num % 2) {
223 $i++;
226 } else {
227 $out .= str_repeat($str[++$i], $o);
230 return $out;
234 * Decoder for RLE4 compression in windows bitmaps
236 * @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp
237 * @param $str
238 * @param $width
239 * @return string
241 private function rle4_decode($str, $width)
243 $w = floor($width / 2) + ($width % 2);
244 $lineWidth = $w + (3 - ( ($width - 1) / 2) % 4);
245 $pixels = [];
246 $cnt = strlen($str);
247 for ($i = 0; $i < $cnt; $i++) {
248 $o = ord($str[$i]);
249 if ($o === 0) { # ESCAPE
250 $i++;
251 switch (ord($str[$i])) {
252 case 0: # NEW LINE
253 while (count($pixels) % $lineWidth !== 0) {
254 $pixels[] = 0;
256 break;
257 case 1: # END OF FILE
258 while (count($pixels) % $lineWidth !== 0) {
259 $pixels[] = 0;
261 break 2;
262 case 2: # DELTA
263 $i += 2;
264 break;
265 default: # ABSOLUTE MODE
266 $num = ord($str[$i]);
267 for ($j = 0; $j < $num; $j++) {
268 if ($j % 2 === 0) {
269 $c = ord($str[++$i]);
270 $pixels[] = ($c & 240) >> 4;
271 } else {
272 $pixels[] = $c & 15; //FIXME: undefined var
275 if ($num % 2) {
276 $i++;
279 } else {
280 $c = ord($str[++$i]);
281 for ($j = 0; $j < $o; $j++) {
282 $pixels[] = ($j % 2 === 0 ? ($c & 240) >> 4 : $c & 15);
287 $out = '';
288 if (count($pixels) % 2) {
289 $pixels[] = 0;
291 $cnt = count($pixels) / 2;
292 for ($i = 0; $i < $cnt; $i++) {
293 $out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]);
295 return $out;