Passed
Push — develop ( d3878a...248214 )
by Jens
02:17
created

Image::createImageResourceFromResource()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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