1<?php 2 3 /** 4##DOC-SIGNATURE## 5 6 This file is part of WideImage. 7 8 WideImage is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 2.1 of the License, or 11 (at your option) any later version. 12 13 WideImage is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU Lesser General Public License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with WideImage; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 22 * @package Internal/Mappers 23 **/ 24 25/** 26 * External code for BMP 27 * 28 * Adapted for use in WideImage. Code used with permission from the original author de77. 29 * http://de77.com/php/read-and-write-bmp-in-php-imagecreatefrombmp-imagebmp 30 * 31 * @author de77 32 * @license MIT 33 * @url de77.com 34 * @version 21.08.2010 35 * 36 * @package Internal/Mappers 37 */ 38 39namespace WideImage\vendor\de77; 40 41class BMP 42{ 43 public static function imagebmp(&$img, $filename = false) 44 { 45 $wid = imagesx($img); 46 $hei = imagesy($img); 47 $wid_pad = str_pad('', $wid % 4, "\0"); 48 49 $size = 54 + ($wid + $wid_pad) * $hei * 3; //fixed 50 51 //prepare & save header 52 $header['identifier'] = 'BM'; 53 $header['file_size'] = self::dword($size); 54 $header['reserved'] = self::dword(0); 55 $header['bitmap_data'] = self::dword(54); 56 $header['header_size'] = self::dword(40); 57 $header['width'] = self::dword($wid); 58 $header['height'] = self::dword($hei); 59 $header['planes'] = self::word(1); 60 $header['bits_per_pixel'] = self::word(24); 61 $header['compression'] = self::dword(0); 62 $header['data_size'] = self::dword(0); 63 $header['h_resolution'] = self::dword(0); 64 $header['v_resolution'] = self::dword(0); 65 $header['colors'] = self::dword(0); 66 $header['important_colors'] = self::dword(0); 67 68 if ($filename) { 69 $f = fopen($filename, "wb"); 70 71 foreach ($header as $h) { 72 fwrite($f, $h); 73 } 74 75 //save pixels 76 for ($y = $hei-1; $y >= 0; $y--) { 77 for ($x = 0; $x < $wid; $x++) { 78 $rgb = imagecolorat($img, $x, $y); 79 fwrite($f, self::byte3($rgb)); 80 } 81 82 fwrite($f, $wid_pad); 83 } 84 85 fclose($f); 86 } else { 87 foreach ($header as $h) { 88 echo $h; 89 } 90 91 //save pixels 92 for ($y = $hei-1; $y >= 0; $y--) { 93 for ($x = 0; $x < $wid; $x++) { 94 $rgb = imagecolorat($img, $x, $y); 95 echo self::byte3($rgb); 96 } 97 98 echo $wid_pad; 99 } 100 } 101 102 return true; 103 } 104 105 public static function imagecreatefromstring($data) 106 { 107 //read header 108 $pos = 0; 109 $header = substr($data, 0, 54); 110 $pos = 54; 111 112 if (strlen($header) < 54) { 113 return false; 114 } 115 116 $header = unpack( 'c2identifier/Vfile_size/Vreserved/Vbitmap_data/Vheader_size/' . 117 'Vwidth/Vheight/vplanes/vbits_per_pixel/Vcompression/Vdata_size/'. 118 'Vh_resolution/Vv_resolution/Vcolors/Vimportant_colors', $header); 119 120 if ($header['identifier1'] != 66 or $header['identifier2'] != 77) { 121 return false; 122 } 123 124 if (!in_array($header['bits_per_pixel'], array(24, 32, 8, 4, 1))) { 125 return false; 126 } 127 128 $bps = $header['bits_per_pixel']; //bits per pixel 129 $wid2 = ceil(($bps/8 * $header['width']) / 4) * 4; 130 $colors = $header['colors']; 131 132 $wid = $header['width']; 133 $hei = $header['height']; 134 135 $img = imagecreatetruecolor($header['width'], $header['height']); 136 137 //read palette 138 if ($bps < 9) { 139 for ($i = 0; $i < $colors; $i++) { 140 $palette[] = self::undword(substr($data, $pos, 4)); 141 $pos += 4; 142 } 143 } else { 144 if ($bps == 32) { 145 imagealphablending($img, false); 146 imagesavealpha($img, true); 147 } 148 149 $palette = array(); 150 } 151 152 //read pixels 153 for ($y = $hei-1; $y >= 0; $y--) { 154 $row = substr($data, $pos, $wid2); 155 $pos += $wid2; 156 $pixels = self::str_split2($row, $bps, $palette); 157 158 for ($x = 0; $x < $wid; $x++) { 159 self::makepixel($img, $x, $y, $pixels[$x], $bps); 160 } 161 } 162 163 return $img; 164 } 165 166 public static function imagecreatefrombmp($filename) 167 { 168 return self::imagecreatefromstring(file_get_contents($filename)); 169 } 170 171 private static function str_split2($row, $bps, $palette) 172 { 173 switch ($bps) { 174 case 32: 175 case 24: return str_split($row, $bps / 8); 176 case 8: $out = array(); 177 $count = strlen($row); 178 179 for ($i = 0; $i < $count; $i++) { 180 $out[] = $palette[ ord($row[$i]) ]; 181 } 182 183 return $out; 184 case 4: $out = array(); 185 $count = strlen($row); 186 187 for ($i = 0; $i < $count; $i++) { 188 $roww = ord($row[$i]); 189 $out[] = $palette[ ($roww & 240) >> 4 ]; 190 $out[] = $palette[ ($roww & 15) ]; 191 } 192 193 return $out; 194 case 1: $out = array(); 195 $count = strlen($row); 196 197 for ($i = 0; $i < $count; $i++) { 198 $roww = ord($row[$i]); 199 $out[] = $palette[ ($roww & 128) >> 7 ]; 200 $out[] = $palette[ ($roww & 64) >> 6 ]; 201 $out[] = $palette[ ($roww & 32) >> 5 ]; 202 $out[] = $palette[ ($roww & 16) >> 4 ]; 203 $out[] = $palette[ ($roww & 8) >> 3 ]; 204 $out[] = $palette[ ($roww & 4) >> 2 ]; 205 $out[] = $palette[ ($roww & 2) >> 1 ]; 206 $out[] = $palette[ ($roww & 1) ]; 207 } 208 209 return $out; 210 } 211 } 212 213 private static function makepixel($img, $x, $y, $str, $bps) 214 { 215 switch ($bps) { 216 case 32 : $a = ord($str[0]); 217 $b = ord($str[1]); 218 $c = ord($str[2]); 219 $d = 256 - ord($str[3]); //TODO: gives imperfect results 220 $pixel = $d*256*256*256 + $c*256*256 + $b*256 + $a; 221 imagesetpixel($img, $x, $y, $pixel); 222 break; 223 case 24 : $a = ord($str[0]); 224 $b = ord($str[1]); 225 $c = ord($str[2]); 226 $pixel = $c*256*256 + $b*256 + $a; 227 imagesetpixel($img, $x, $y, $pixel); 228 break; 229 case 8 : 230 case 4 : 231 case 1 : imagesetpixel($img, $x, $y, $str); 232 break; 233 } 234 } 235 236 private static function byte3($n) 237 { 238 return chr($n & 255) . chr(($n >> 8) & 255) . chr(($n >> 16) & 255); 239 } 240 241 private static function undword($n) 242 { 243 $r = unpack("V", $n); 244 return $r[1]; 245 } 246 247 private static function dword($n) 248 { 249 return pack("V", $n); 250 } 251 252 private static function word($n) 253 { 254 return pack("v", $n); 255 } 256} 257