Passed
Push — master ( 3f6c85...9c6499 )
by Jens
02:40
created

Image::loadImage()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 13
nc 5
nop 1
dl 0
loc 17
rs 8.2222
c 0
b 0
f 0
1
<?php
2
/**
3
 * Image
4
 *
5
 * @Author : Jens Kooij
6
 * @Version: 1.0
7
 * @package: JNS MVC
8
 * @Licence: http://creativecommons.org/licenses/by-nc-nd/3.0/ Attribution-NonCommercial-NoDerivs 3.0 Unported
9
 */
10
11
namespace library\images {
12
	class Image
13
	{
14
		private $_imageResource;
15
16
		/**
17
		 * Load the a image resource into $this->_imageResource
18
		 * automagically :-)
19
		 *
20
		 * @param    resource | string | path
21
		 *
22
		 * @throws    \Exception
23
		 */
24
		public function loadImage($imageContainer)
25
		{
26
			if (is_resource($imageContainer) && get_resource_type($imageContainer) === 'gd') {
27
				$this->_imageResource = $imageContainer;
28
			} elseif (is_string($imageContainer) && file_exists($imageContainer)) {
29
				if ($this->getImageMimeType($imageContainer) == IMAGETYPE_BMP) {
30
					$this->_imageResource = $this->createImageFromBmp($imageContainer);
31
				} else {
32
					$imageContent = file_get_contents($imageContainer);
33
					$this->_imageResource = imagecreatefromstring($imageContent);
34
				}
35
			} elseif (is_string($imageContainer)) {
36
				$this->_imageResource = imagecreatefromstring($imageContainer);
37
			} else {
38
				throw new \Exception('Could not create image resource, accepted inputs are: "resource of type (gd)", path_to_image and "string". <br /><pre>' . var_export($imageContainer, true) . '</pre>');
39
			}
40
		}
41
42
		/**
43
		 * Saves the image to a file
44
		 *
45
		 * @param string $path
46
		 * @param int    $mimeTypeConstantValue
47
		 * @param int    $quality
48
		 * @param null   $imageResource If no resource is given, uses $this->_imageResource
49
		 *
50
		 * @return bool
51
		 * @throws \Exception
52
		 */
53
		public function saveImage($path, $mimeTypeConstantValue, $quality = 100, $imageResource = null)
54
		{
55
			if ($imageResource == null) {
56
				$imageResource = $this->getImageResource();
57
			}
58
59
			if ($mimeTypeConstantValue == IMAGETYPE_GIF) {
60
				return imagegif($imageResource, $path);
61
			} elseif ($mimeTypeConstantValue == IMAGETYPE_JPEG) {
62
				return imagejpeg($imageResource, $path, $quality);
63
			} elseif ($mimeTypeConstantValue == IMAGETYPE_PNG) {
64
				return imagepng($imageResource, $path, (intval($quality / 10) - 1));
65
			} else {
66
				throw new \Exception('Not a valid mimetypeconstant given see function documentation');
67
			}
68
		}
69
70
		/**
71
		 * Returns either the Mime-Type Constant value
72
		 * or the default extension for the detected mime-type;
73
		 *
74
		 * @see http://www.php.net/manual/en/function.image-type-to-mime-type.php
75
		 *
76
		 * @param string $imagePath
77
		 * @param bool   $getExtension
78
		 *
79
		 * @return bool|int|string
80
		 */
81
		public function getImageMimeType($imagePath, $getExtension = false)
82
		{
83
			if (function_exists('exif_imagetype')) {
84
				$exif = exif_imagetype($imagePath);
85
			} else {
86
				if ((list($width, $height, $type, $attr) = getimagesize($imagePath)) !== false) {
87
					$exif = $type;
88
				} else {
89
					$exif = false;
90
				}
91
			}
92
93
			return $getExtension ? image_type_to_extension($exif) : $exif;
94
		}
95
96
		/**
97
		 * Create Image resource from Bitmap
98
		 *
99
		 * @see       http://www.php.net/manual/en/function.imagecreatefromwbmp.php#86214
100
		 * @author    alexander at alexauto dot nl
101
		 *
102
		 * @param    string $pathToBitmapFile
103
		 *
104
		 * @return  resource
105
		 */
106
		public function createImageFromBmp($pathToBitmapFile)
107
		{
108
			$bitmapFileData = $this->getBitmapFileData($pathToBitmapFile);
109
110
			$temp = unpack("H*", $bitmapFileData);
111
			$hex = $temp[1];
112
			$header = substr($hex, 0, 108);
113
			list($width, $height) = $this->calculateWidthAndHeight($header);
114
115
			//    Define starting X and Y 
116
			$x = 0;
117
			$y = 1;
118
119
			$image = imagecreatetruecolor($width, $height);
120
121
			//    Grab the body from the image 
122
			$body = substr($hex, 108);
123
124
			//    Calculate if padding at the end-line is needed. Divided by two to keep overview. 1 byte = 2 HEX-chars
125
			$bodySize = (strlen($body) / 2);
126
			$headerSize = ($width * $height);
127
128
			//    Use end-line padding? Only when needed 
129
			$usePadding = ($bodySize > ($headerSize * 3) + 4);
130
			$this->loopThroughBodyAndCalculatePixels($bodySize, $x, $width, $usePadding, $y, $height, $body, $image);
131
132
			unset($body);
133
134
			return $image;
135
		}
136
137
		/**
138
		 * Returns the image resource
139
		 * @return resource
140
		 * @throws \Exception
141
		 */
142
		final public function getImageResource()
143
		{
144
			if (is_resource($this->_imageResource) && get_resource_type($this->_imageResource) === 'gd') {
145
				return $this->_imageResource;
146
			} else {
147
				throw new \Exception('Image resource is not set. Use $this->LoadImage to load an image into the resource');
148
			}
149
		}
150
151
		/**
152
		 * @param $pathToBitmapFile
153
		 *
154
		 * @return string
155
		 */
156
		private function getBitmapFileData($pathToBitmapFile)
157
		{
158
			$fileHandle = fopen($pathToBitmapFile, "rb");
159
			$bitmapFileData = fread($fileHandle, 10);
160
			while (!feof($fileHandle) && ($bitmapFileData <> "")) {
161
				$bitmapFileData .= fread($fileHandle, 1024);
162
			}
163
164
			return $bitmapFileData;
165
		}
166
167
		/**
168
		 * @param $header
169
		 *
170
		 * @return array
171
		 */
172
		private function calculateWidthAndHeight($header)
173
		{
174
			$width = null;
175
			$height = null;
176
177
			//    Structure: http://www.fastgraph.com/help/bmp_header_format.html
178
			if (substr($header, 0, 4) == "424d") {
179
				//    Cut it in parts of 2 bytes
180
				$header_parts = str_split($header, 2);
181
				//    Get the width        4 bytes
182
				$width = hexdec($header_parts[19] . $header_parts[18]);
183
				//    Get the height        4 bytes
184
				$height = hexdec($header_parts[23] . $header_parts[22]);
185
				//    Unset the header params
186
				unset($header_parts);
187
188
				return array($width, $height);
189
			}
190
191
			return array($width, $height);
192
		}
193
194
		/**
195
		 * Loop through the data in the body of the bitmap
196
		 * file and calculate each individual pixel based on the
197
		 * bytes
198
		 * @param $bodySize
199
		 * @param $x
200
		 * @param $width
201
		 * @param $usePadding
202
		 * @param $y
203
		 * @param $height
204
		 * @param $body
205
		 * @param $image
206
		 */
207
		private function loopThroughBodyAndCalculatePixels($bodySize, $x, $width, $usePadding, $y, $height, $body, $image)
208
		{
209
//    Using a for-loop with index-calculation instead of str_split to avoid large memory consumption
210
			//    Calculate the next DWORD-position in the body
211
			for ($i = 0; $i < $bodySize; $i += 3) {
212
				//    Calculate line-ending and padding
213
				if ($x >= $width) {
214
					//    If padding needed, ignore image-padding. Shift i to the ending of the current 32-bit-block
215
					if ($usePadding) {
216
						$i += $width % 4;
217
					}
218
					//    Reset horizontal position
219
					$x = 0;
220
					//    Raise the height-position (bottom-up)
221
					$y++;
222
					//    Reached the image-height? Break the for-loop
223
					if ($y > $height) {
224
						break;
225
					}
226
				}
227
				//    Calculation of the RGB-pixel (defined as BGR in image-data). Define $iPos as absolute position in the body
228
				$iPos = $i * 2;
229
				$r = hexdec($body[$iPos + 4] . $body[$iPos + 5]);
230
				$g = hexdec($body[$iPos + 2] . $body[$iPos + 3]);
231
				$b = hexdec($body[$iPos] . $body[$iPos + 1]);
232
				//    Calculate and draw the pixel
233
				$color = imagecolorallocate($image, $r, $g, $b);
234
				imagesetpixel($image, $x, $height - $y, $color);
235
				//    Raise the horizontal position
236
				$x++;
237
			}
238
		}
239
	}
240
}