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