Completed
Push — master ( 247290...01d05f )
by Michael
08:30
created

BMP::imagecreatefromstring()   C

Complexity

Conditions 10
Paths 12

Size

Total Lines 60
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 35
nc 12
nop 1
dl 0
loc 60
rs 6.5333
c 0
b 0
f 0

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
Coding Style Comprehensibility introduced by
$header was never initialized. Although not strictly required by PHP, it is generally a good practice to add $header = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

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 View Code Duplication
				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 View Code Duplication
				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)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
106
	{
107
		//read header
108
		$pos    = 0;
0 ignored issues
show
Unused Code introduced by
$pos is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

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) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
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));
0 ignored issues
show
Coding Style Comprehensibility introduced by
$palette was never initialized. Although not strictly required by PHP, it is generally a good practice to add $palette = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
141
				$pos += 4;
142
			}
143
		} else {
144
			if ($bps == 32) {
145
				imagealphablending($img, false);
0 ignored issues
show
Unused Code introduced by
The call to the function imagealphablending() seems unnecessary as the function has no side-effects.
Loading history...
146
				imagesavealpha($img, true);
0 ignored issues
show
Unused Code introduced by
The call to the function imagesavealpha() seems unnecessary as the function has no side-effects.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The variable $palette does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
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)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
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);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
176
			case  8:	$out   = array();
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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();
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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();
0 ignored issues
show
Coding Style introduced by
As per coding-style, case should be followed by a single space.

As per the PSR-2 coding standard, there must be a space after the case keyword, instead of the test immediately following it.

switch (true) {
    case!isset($a):  //wrong
        doSomething();
        break;
    case !isset($b):  //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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]);
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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]);
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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 :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
230
			case 4 :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
231
			case 1 :	imagesetpixel($img, $x, $y, $str);
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a CASE statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in case statements.

switch ($selector) {
    case "A": //right
        doSomething();
        break;
    case "B" : //wrong
        doSomethingElse();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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)
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
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