mpdf = $mpdf; } public function _getBMPimage($data, $file) { // Adapted from script by Valentin Schmidt // http://staff.dasdeck.de/valentin/fpdf/fpdf_bmp/ $bfOffBits = $this->_fourbytes2int_le(substr($data, 10, 4)); $width = $this->_fourbytes2int_le(substr($data, 18, 4)); $height = $this->_fourbytes2int_le(substr($data, 22, 4)); $flip = ($height < 0); if ($flip) { $height = -$height; } $biBitCount = $this->_twobytes2int_le(substr($data, 28, 2)); $biCompression = $this->_fourbytes2int_le(substr($data, 30, 4)); $info = ['w' => $width, 'h' => $height]; if ($biBitCount < 16) { $info['cs'] = 'Indexed'; $info['bpc'] = $biBitCount; $palStr = substr($data, 54, $bfOffBits - 54); $pal = ''; $cnt = strlen($palStr) / 4; for ($i = 0; $i < $cnt; $i++) { $n = 4 * $i; $pal .= $palStr[$n + 2] . $palStr[$n + 1] . $palStr[$n]; } $info['pal'] = $pal; } else { $info['cs'] = 'DeviceRGB'; $info['bpc'] = 8; } if ($this->mpdf->restrictColorSpace == 1 || $this->mpdf->PDFX || $this->mpdf->restrictColorSpace == 3) { if (($this->mpdf->PDFA && !$this->mpdf->PDFAauto) || ($this->mpdf->PDFX && !$this->mpdf->PDFXauto)) { $this->mpdf->PDFAXwarnings[] = "Image cannot be converted to suitable colour space for PDFA or PDFX file - $file - (Image replaced by 'no-image'.)"; } return ['error' => "BMP Image cannot be converted to suitable colour space - $file - (Image replaced by 'no-image'.)"]; } $biXPelsPerMeter = $this->_fourbytes2int_le(substr($data, 38, 4)); // horizontal pixels per meter, usually set to zero //$biYPelsPerMeter=$this->_fourbytes2int_le(substr($data,42,4)); // vertical pixels per meter, usually set to zero $biXPelsPerMeter = round($biXPelsPerMeter / 1000 * 25.4); //$biYPelsPerMeter=round($biYPelsPerMeter/1000 *25.4); $info['set-dpi'] = $biXPelsPerMeter; switch ($biCompression) { case 0: $str = substr($data, $bfOffBits); break; case 1: # BI_RLE8 $str = $this->rle8_decode(substr($data, $bfOffBits), $width); break; case 2: # BI_RLE4 $str = $this->rle4_decode(substr($data, $bfOffBits), $width); break; } $bmpdata = ''; $padCnt = (4 - ceil($width / (8 / $biBitCount)) % 4) % 4; switch ($biBitCount) { case 1: case 4: case 8: $w = floor($width / (8 / $biBitCount)) + ($width % (8 / $biBitCount) ? 1 : 0); $w_row = $w + $padCnt; if ($flip) { for ($y = 0; $y < $height; $y++) { $y0 = $y * $w_row; for ($x = 0; $x < $w; $x++) { $bmpdata .= $str[$y0 + $x]; } } } else { for ($y = $height - 1; $y >= 0; $y--) { $y0 = $y * $w_row; for ($x = 0; $x < $w; $x++) { $bmpdata .= $str[$y0 + $x]; } } } break; case 16: $w_row = $width * 2 + $padCnt; if ($flip) { for ($y = 0; $y < $height; $y++) { $y0 = $y * $w_row; for ($x = 0; $x < $width; $x++) { $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x])); $b = ($n & 31) << 3; $g = ($n & 992) >> 2; $r = ($n & 31744) >> 7; $bmpdata .= chr($r) . chr($g) . chr($b); } } } else { for ($y = $height - 1; $y >= 0; $y--) { $y0 = $y * $w_row; for ($x = 0; $x < $width; $x++) { $n = (ord($str[$y0 + 2 * $x + 1]) * 256 + ord($str[$y0 + 2 * $x])); $b = ($n & 31) << 3; $g = ($n & 992) >> 2; $r = ($n & 31744) >> 7; $bmpdata .= chr($r) . chr($g) . chr($b); } } } break; case 24: case 32: $byteCnt = $biBitCount / 8; $w_row = $width * $byteCnt + $padCnt; if ($flip) { for ($y = 0; $y < $height; $y++) { $y0 = $y * $w_row; for ($x = 0; $x < $width; $x++) { $i = $y0 + $x * $byteCnt; # + 1 $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i]; } } } else { for ($y = $height - 1; $y >= 0; $y--) { $y0 = $y * $w_row; for ($x = 0; $x < $width; $x++) { $i = $y0 + $x * $byteCnt; # + 1 $bmpdata .= $str[$i + 2] . $str[$i + 1] . $str[$i]; } } } break; default: return ['error' => 'Error parsing BMP image - Unsupported image biBitCount']; } if ($this->mpdf->compress) { $bmpdata = gzcompress($bmpdata); $info['f'] = 'FlateDecode'; } $info['data'] = $bmpdata; $info['type'] = 'bmp'; return $info; } /** * Read a 4-byte integer from string * * @param $s * @return int */ private function _fourbytes2int_le($s) { return (ord($s[3]) << 24) + (ord($s[2]) << 16) + (ord($s[1]) << 8) + ord($s[0]); } /** * Read a 2-byte integer from string * * @param $s * @return int */ private function _twobytes2int_le($s) { return (ord(substr($s, 1, 1)) << 8) + ord(substr($s, 0, 1)); } /** * Decoder for RLE8 compression in windows bitmaps * * @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp * @param $str * @param $width * @return string */ private function rle8_decode($str, $width) { $lineWidth = $width + (3 - ($width - 1) % 4); $out = ''; $cnt = strlen($str); for ($i = 0; $i < $cnt; $i++) { $o = ord($str[$i]); if ($o === 0) { # ESCAPE $i++; switch (ord($str[$i])) { case 0: # NEW LINE $padCnt = $lineWidth - strlen($out) % $lineWidth; if ($padCnt < $lineWidth) { $out .= str_repeat(chr(0), $padCnt);# pad line } break; case 1: # END OF FILE $padCnt = $lineWidth - strlen($out) % $lineWidth; if ($padCnt < $lineWidth) { $out .= str_repeat(chr(0), $padCnt);# pad line } break 2; case 2: # DELTA $i += 2; break; default: # ABSOLUTE MODE $num = ord($str[$i]); for ($j = 0; $j < $num; $j++) { $out .= $str[++$i]; } if ($num % 2) { $i++; } } } else { $out .= str_repeat($str[++$i], $o); } } return $out; } /** * Decoder for RLE4 compression in windows bitmaps * * @see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_6x0u.asp * @param $str * @param $width * @return string */ private function rle4_decode($str, $width) { $w = floor($width / 2) + ($width % 2); $lineWidth = $w + (3 - ( ($width - 1) / 2) % 4); $pixels = []; $cnt = strlen($str); for ($i = 0; $i < $cnt; $i++) { $o = ord($str[$i]); if ($o === 0) { # ESCAPE $i++; switch (ord($str[$i])) { case 0: # NEW LINE while (count($pixels) % $lineWidth !== 0) { $pixels[] = 0; } break; case 1: # END OF FILE while (count($pixels) % $lineWidth !== 0) { $pixels[] = 0; } break 2; case 2: # DELTA $i += 2; break; default: # ABSOLUTE MODE $num = ord($str[$i]); for ($j = 0; $j < $num; $j++) { if ($j % 2 === 0) { $c = ord($str[++$i]); $pixels[] = ($c & 240) >> 4; } else { $pixels[] = $c & 15; //FIXME: undefined var } } if ($num % 2) { $i++; } } } else { $c = ord($str[++$i]); for ($j = 0; $j < $o; $j++) { $pixels[] = ($j % 2 === 0 ? ($c & 240) >> 4 : $c & 15); } } } $out = ''; if (count($pixels) % 2) { $pixels[] = 0; } $cnt = count($pixels) / 2; for ($i = 0; $i < $cnt; $i++) { $out .= chr(16 * $pixels[2 * $i] + $pixels[2 * $i + 1]); } return $out; } }