Passed
Push — master ( ba645d...9eba8c )
by Michael
07:09 queued 43s
created

BMP::imagecreatefromstring()   C

Complexity

Conditions 13
Paths 16

Size

Total Lines 73
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 40
c 0
b 0
f 0
nc 16
nop 1
dl 0
loc 73
rs 6.6166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
39
namespace WideImage\vendor\de77;
40
41
class 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';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$header was never initialized. Although not strictly required by PHP, it is generally a good practice to add $header = array(); before regardless.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
The assignment to $pos is dead and can be removed.
Loading history...
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
	    // The absolute height value is necessary because ImageHeight can be negative
132
	    // If Height is a positive number, then the image is a "bottom-up" bitmap with the origin in the lower-left corner.
133
	    // If Height is a negative number, then the image is a "top-down" bitmap with the origin in the upper-left corner.
134
	    $header['height'] = abs($header['height']);
135
136
	    $wid = $header['width'];
137
	    $hei = $header['height'];
138
139
	    $img = imagecreatetruecolor($header['width'], $header['height']);
0 ignored issues
show
Bug introduced by
It seems like $header['height'] can also be of type double; however, parameter $height of imagecreatetruecolor() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
	    $img = imagecreatetruecolor($header['width'], /** @scrutinizer ignore-type */ $header['height']);
Loading history...
140
	    if (!$img) {
141
		    return false; // Invalid width or height
142
	    }
143
	    //read palette
144
	    $palette = [];
145
146
		if ($bps < 9) {
147
			// A color table is mandatory for color depths <= 8
148
			if (isset($header['colors']) && $header['colors'] > 0) {
149
				// The number of entries in the palette is either 2n 
150
				// or a smaller number specified in the header
151
				$colors = min($header['colors'], $colors);
152
			}
153
			for ($i = 0; $i < $colors; $i++) {
154
				$palette[] = self::undword(substr($data, $pos, 4));
155
				$pos += 4;
156
			}
157
		} else {
158
			if ($bps == 32) {
159
				imagealphablending($img, false);
160
				imagesavealpha($img, true);
161
			}
162
163
			$palette = array();
164
		}
165
166
		//read pixels
167
	    for ($y = $hei-1; $y >= 0; $y--) {
168
			$row    = substr($data, $pos, $wid2);
0 ignored issues
show
Bug introduced by
$wid2 of type double is incompatible with the type integer|null expected by parameter $length of substr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

168
			$row    = substr($data, $pos, /** @scrutinizer ignore-type */ $wid2);
Loading history...
169
			$pos   += $wid2;
170
			$pixels = self::str_split2($row, $bps, $palette);
171
172
	    	for ($x = 0; $x < $wid; $x++) {
173
	    		self::makepixel($img, $x, $y, $pixels[$x], $bps);
174
	    	}
175
	    }
176
177
		return $img;
178
	}
179
180
	public static function imagecreatefrombmp($filename)
181
	{
182
		return self::imagecreatefromstring(file_get_contents($filename));
183
	}
184
185
	private static function str_split2($row, $bps, $palette)
186
	{
187
		switch ($bps) {
188
			case 32:
189
			case 24:	return str_split($row, $bps / 8);
190
			case  8:	$out   = array();
191
						$count = strlen($row);
192
193
						for ($i = 0; $i < $count; $i++) {
194
							$out[] = $palette[	ord($row[$i])		];
195
						}
196
197
						return $out;
198
			case  4:	$out   = array();
199
						$count = strlen($row);
200
201
						for ($i = 0; $i < $count; $i++) {
202
							$roww  = ord($row[$i]);
203
							$out[] = $palette[	($roww & 240) >> 4	];
204
							$out[] = $palette[	($roww & 15) 		];
205
						}
206
207
						return $out;
208
			case  1:	$out   = array();
209
						$count = strlen($row);
210
211
						for ($i = 0; $i < $count; $i++) {
212
							$roww  = ord($row[$i]);
213
							$out[] = $palette[	($roww & 128) >> 7	];
214
							$out[] = $palette[	($roww & 64) >> 6	];
215
							$out[] = $palette[	($roww & 32) >> 5	];
216
							$out[] = $palette[	($roww & 16) >> 4	];
217
							$out[] = $palette[	($roww & 8) >> 3	];
218
							$out[] = $palette[	($roww & 4) >> 2	];
219
							$out[] = $palette[	($roww & 2) >> 1	];
220
							$out[] = $palette[	($roww & 1)			];
221
						}
222
223
						return $out;
224
		}
225
	}
226
227
	private static function makepixel($img, $x, $y, $str, $bps)
228
	{
229
		switch ($bps) {
230
			case 32 :	$a = ord($str[0]);
231
						$b = ord($str[1]);
232
						$c = ord($str[2]);
233
						$d = 256 - ord($str[3]); //TODO: gives imperfect results
234
						$pixel = $d*256*256*256 + $c*256*256 + $b*256 + $a;
235
						imagesetpixel($img, $x, $y, $pixel);
236
						break;
237
			case 24 :	$a = ord($str[0]);
238
						$b = ord($str[1]);
239
						$c = ord($str[2]);
240
						$pixel = $c*256*256 + $b*256 + $a;
241
						imagesetpixel($img, $x, $y, $pixel);
242
						break;
243
			case 8 :
244
			case 4 :
245
			case 1 :	imagesetpixel($img, $x, $y, $str);
246
						break;
247
		}
248
	}
249
250
	private static function byte3($n)
251
	{
252
		return chr($n & 255) . chr(($n >> 8) & 255) . chr(($n >> 16) & 255);
253
	}
254
255
	private static function undword($n)
256
	{
257
		$r = unpack("V", $n);
258
		return $r[1];
259
	}
260
261
	private static function dword($n)
262
	{
263
		return pack("V", $n);
264
	}
265
266
	private static function word($n)
267
	{
268
		return pack("v", $n);
269
	}
270
}
271