@@ -10,65 +10,36 @@ class ImageUtils {
1010 * @param int $maxWidth - maximum new width
1111 * @param int $maxHeight - maximum new height
1212 * @param string $targetDir - target directory
13- * @return path of the new image file or NULL if it could not be created.
13+ * @return string - the path of the new image file, e.g. /target/dir/basename.variation.png ( or NULL in case of GD issues)
1414 */
1515 public static function createThumbnail ($ imagePath , $ maxWidth , $ maxHeight , $ targetDir = NULL ) {
16- $ pathinfo = pathinfo ($ imagePath );
17- $ targetPath = '. ' ;
18- if ($ targetDir == NULL ) {
19- $ targetPath = $ pathinfo ['dirname ' ].'/ ' .$ pathinfo ['filename ' ].'.thumbnail. ' ;
20- } else {
21- $ targetPath = $ targetDir .'/ ' .$ pathinfo ['filename ' ].'.thumbnail. ' ;
22- }
23- if (class_exists ('Imagick ' )) {
24- $ image = new \Imagick ($ imagePath );
25- $ image ->thumbnailImage ($ maxWidth , $ maxHeight , TRUE );
26- $ targetPath .= 'png ' ;
27- if (!$ image ->writeImage ($ targetPath )) {
28- $ targetPath = NULL ;
29- }
30- } else {
31- // We use GD
32- $ imageDetails = getimagesize ($ imagePath );
33- $ image = self ::readImage ($ imagePath , $ imageDetails );
34- if ($ image != NULL ) {
35- // Compute new dimensions
36- $ size = self ::computeNewSize ($ imageDetails [0 ], $ imageDetails [1 ], $ maxWidth , $ maxHeight );
16+ $ targetPath = self ::getNewPath ($ imagePath , 'thumbnail ' , $ targetDir );
3717
38- // Scale it
39- $ thumbnail = imagecreatetruecolor ($ size ->width , $ size -height);
40- imagecopyresized ($ thumbnail , $ image , 0 , 0 , 0 , 0 , $ size ->width , $ size ->height , $ imageDetails [0 ], $ imageDetails [1 ]);
41- // Writing it
42- $ gdInfo = gd_info ();
43- // Preferential order PNG, JPEG, WEBP, XPM, WBMP, GIF, BMP
44- if ($ gdInfo ['PNG Support ' ]) {
45- $ targetPath .= 'png ' ;
46- if (!imagepng ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
47- } else if ($ gdInfo ['JPEG Support ' ]) {
48- $ targetPath .= 'jpg ' ;
49- if (!imagejpeg ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
50- } else if ($ gdInfo ['WebP Support ' ]) {
51- $ targetPath .= 'webp ' ;
52- if (!imagewebp ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
53- } else if ($ gdInfo ['XPM Support ' ]) {
54- $ targetPath .= 'xpm ' ;
55- if (!imagexbm ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
56- } else if ($ gdInfo ['WBMP Support ' ]) {
57- $ targetPath .= 'wbmp ' ;
58- if (!imagewbmp ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
59- } else if ($ gdInfo ['GIF Create Support ' ]) {
60- $ targetPath .= 'gif ' ;
61- if (!imagegif ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
62- } else if ($ gdInfo ['BMP Support ' ]) {
63- $ targetPath .= 'bmp ' ;
64- if (!imagebmp ($ thumbnail , $ targetPath )) $ targetPath = NULL ;
65- } else {
18+ if ($ targetPath != NULL ) {
19+ if (class_exists ('Imagick ' )) {
20+ $ image = new \Imagick ($ imagePath );
21+ $ image ->thumbnailImage ($ maxWidth , $ maxHeight , TRUE );
22+ if (!$ image ->writeImage ($ targetPath )) {
6623 $ targetPath = NULL ;
6724 }
68- imagedestroy ($ thumbnail );
69- imagedestroy ($ image );
7025 } else {
71- $ targetPath = NULL ;
26+ // We use GD
27+ $ imageDetails = getimagesize ($ imagePath );
28+ $ image = self ::readImage ($ imagePath , $ imageDetails );
29+ if ($ image != NULL ) {
30+ // Compute new dimensions
31+ $ size = self ::computeNewSize ($ imageDetails [0 ], $ imageDetails [1 ], $ maxWidth , $ maxHeight );
32+
33+ // Scale it
34+ $ thumbnail = imagecreatetruecolor ($ size ->width , $ size ->height );
35+ imagecopyresized ($ thumbnail , $ image , 0 , 0 , 0 , 0 , $ size ->width , $ size ->height , $ imageDetails [0 ], $ imageDetails [1 ]);
36+ // Writing it
37+ $ targetPath = self ::writeImage ($ thumbnail , $ targetPath );
38+ imagedestroy ($ thumbnail );
39+ imagedestroy ($ image );
40+ } else {
41+ $ targetPath = NULL ;
42+ }
7243 }
7344 }
7445 return $ targetPath ;
@@ -130,6 +101,44 @@ public static function readImage($imagePath, $imageDetails = NULL) {
130101 return NULL ;
131102 }
132103
104+ /**
105+ * Write an GD image to the specified path.
106+ * @param resource $image - the GD image resource
107+ * @param string $path - the path where to write to (must include the filetype extension)
108+ * @return string - the path when writing was successful, NULL otherwise
109+ */
110+ public static function writeImage ($ image , $ path ) {
111+ $ gdInfo = gd_info ();
112+ $ ext = strtolower (pathinfo ($ path , PATHINFO_EXTENSION ));
113+ switch ($ ext ) {
114+ case 'png ' :
115+ if (!imagepng ($ thumbnail , $ path )) $ path = NULL ;
116+ break ;
117+ case 'jpg ' :
118+ case 'jpeg ' :
119+ if (!imagejpeg ($ thumbnail , $ path )) $ path = NULL ;
120+ break ;
121+ case 'webp ' :
122+ if (!imagewebp ($ thumbnail , $ path )) $ path = NULL ;
123+ break ;
124+ case 'xpm ' :
125+ if (!imagexbm ($ thumbnail , $ path )) $ path = NULL ;
126+ break ;
127+ case 'wbmp ' :
128+ if (!imagewbmp ($ thumbnail , $ path )) $ path = NULL ;
129+ break ;
130+ case 'gif ' :
131+ if (!imagegif ($ thumbnail , $ path )) $ path = NULL ;
132+ break ;
133+ case 'bmp ' :
134+ if (!imagebmp ($ thumbnail , $ path )) $ path = NULL ;
135+ break ;
136+ default :
137+ $ path = NULL ;
138+ }
139+ return $ path ;
140+ }
141+
133142 /**
134143 * Returns an object with width and height attributes to resize.
135144 * @param int $origWidth - original width
@@ -152,5 +161,145 @@ public static function computeNewSize($origWidth, $origHeight, $maxWidth, $maxHe
152161 }
153162 return $ rc ;
154163 }
164+
165+ /**
166+ * Cuts and scale the given image to new height and new width. The image will not be stretched or densed.
167+ * @param string $imagePath - path of image to read from
168+ * @param string $variation - The identifier to be included in the filename when writing the new image
169+ * @param int $newHeight - new height of image
170+ * @param int $newWidth - new width of image
171+ * @param string $targetDir - target directory
172+ * @return string the path to the new image file or NULL if action failed
173+ * @return string - the path of the new image file, e.g. /target/dir/basename.variation.png (or NULL in case of GD issues)
174+ */
175+ public static function cropAndScale ($ imagePath , $ variation , $ newHeight , $ newWidth , $ options = NULL , $ targetDir = NULL ) {
176+ $ targetPath = self ::getNewPath ($ imagePath , $ variation , $ targetDir );
177+ if ($ options == NULL ) $ options = self ::cropAndScaleOptions ();
178+
179+ if ($ targetPath != NULL ) {
180+ $ actions = NULL ;
181+ if (class_exists ('Imagick ' )) {
182+ $ image = new \Imagick ($ imagePath );
183+ $ width = $ image ->getImageWidth ();
184+ $ height = $ image ->getImageHeight ();
185+ $ actions = self ::computeCropAndScale ($ width , $ height , $ newWidth , $ newHeight , $ options );
186+ if ($ actions ->scale != 1 ) {
187+ $ image ->scaleImage ($ actions ->factor * $ width , 0 );
188+ }
189+ if ($ image ->cropImage ($ actions ->width , $ actions ->height , $ actions ->x , $ actions ->y )) {
190+ // Writing it
191+ if (!$ image ->writeImage ($ targetPath )) {
192+ $ targetPath = NULL ;
193+ }
194+ } else {
195+ $ targetPath = NULL ;
196+ }
197+ } else {
198+ // We use GD
199+ $ imageDetails = getimagesize ($ imagePath );
200+ $ actions = self ::computeCropAndScale ($ imageDetails [0 ], $ imageDetails [1 ], $ newWidth , $ newHeight , $ options );
201+
202+ // Scale it
203+ $ target = imagecreatetruecolor ($ actions ->width , $ actions ->height );
204+ imagecopyresized ($ target , $ image , 0 , 0 , $ actions ->x / $ actions ->factor , $ actions ->y / $ actions ->factor , $ newWidth , $ newHeight , $ imageDetails [0 ] / $ actions ->factor , $ imageDetails [1 ] / $ actions ->factor );
205+ $ targetPath = self ::writeImage ($ target , $ targetPath );
206+ imagedestroy ($ target );
207+ imagedestroy ($ image );
208+ }
209+ }
210+ return $ targetPath ;
211+ }
212+
213+ /**
214+ * Creates options for the cropAndScale() function.
215+ * @param boolean $cropX - whether cropping width is permitted
216+ * @param boolean $cropY - whether cropping height is permitted
217+ * @param boolean $centerX - whether new image will be centered at X axis in case of cropping
218+ * @param boolean $centerY - whether new image will be centered at Y axis in case of cropping
219+ * @return object - the options for the cropAndScale() function
220+ */
221+ public static function cropAndScaleOptions ($ centerX = TRUE , $ centerY = FALSE ) {
222+ $ rc = new \stdClass ;
223+ $ rc ->centerX = $ centerX ;
224+ $ rc ->centerY = $ centerY ;
225+ return $ rc ;
226+ }
227+
228+ public static function computeCropAndScale ($ origWidth , $ origHeight , $ maxWidth , $ maxHeight , $ options = NULL ) {
229+ $ rc = new \stdClass ;
230+ if ($ options == NULL ) $ options = self ::cropAndScaleOptions ();
231+
232+
233+ // Assume X scaling to maxWidth
234+ $ rc ->factor = $ maxWidth / $ origWidth ;
235+
236+ // Positioning for cropping
237+ $ rc ->x = 0 ;
238+ $ rc ->y = 0 ;
239+
240+ // Compute potential target
241+ $ rc ->width = $ maxWidth ;
242+ $ rc ->height = $ rc ->factor * $ origHeight ;
243+ $ rc ->options = $ options ;
244+
245+ if ($ rc ->height < $ maxHeight ) {
246+ // scale up and crop along X axis
247+ $ rc ->factor = $ maxHeight / $ origHeight ;
248+ $ rc ->width = $ rc ->factor * $ origWidth ;
249+ $ rc ->height = $ maxHeight ;
250+ if ($ options ->centerX ) {
251+ $ rc ->x = ($ rc ->width - $ maxWidth ) / 2 ;
252+ }
253+ } else if ($ rc ->height > $ maxHeight ) {
254+ if ($ options ->centerY ) {
255+ $ rc ->y = ($ rc ->height - $ maxHeight ) / 2 ;
256+ }
257+ }
258+ $ rc ->width = $ maxWidth ;
259+ $ rc ->height = $ maxHeight ;
260+
261+ return $ rc ;
262+ }
263+
264+ /**
265+ * Computes the variation path of an image file using a priority: PNG, JPEG, WEBP, XPM, WBMP, GIF, BMP
266+ * @param string $imagePath - the original image path
267+ * @param string $variation - the identifier to be included in new filename
268+ * @param string $targetDir - the target directory
269+ * @return string - the new path of the image file, e.g. /target/dir/basename.variation.png (or NULL in case of GD issues)
270+ */
271+ public static function getNewPath ($ imagePath , $ variation , $ targetDir = NULL ) {
272+ $ pathinfo = pathinfo ($ imagePath );
273+ $ targetPath = '. ' ;
274+ if ($ targetDir == NULL ) {
275+ $ targetPath = $ pathinfo ['dirname ' ].'/ ' .$ pathinfo ['filename ' ].'. ' .$ variation .'. ' ;
276+ } else {
277+ $ targetPath = $ targetDir .'/ ' .$ pathinfo ['filename ' ].'. ' .$ variation .'. ' ;
278+ }
279+ if (class_exists ('Imagick ' )) {
280+ $ targetPath .= 'png ' ;
281+ } else {
282+ $ gdInfo = gd_info ();
283+ // Preferential order PNG, JPEG, WEBP, XPM, WBMP, GIF, BMP
284+ if ($ gdInfo ['PNG Support ' ]) {
285+ $ targetPath .= 'png ' ;
286+ } else if ($ gdInfo ['JPEG Support ' ]) {
287+ $ targetPath .= 'jpg ' ;
288+ } else if ($ gdInfo ['WebP Support ' ]) {
289+ $ targetPath .= 'webp ' ;
290+ } else if ($ gdInfo ['XPM Support ' ]) {
291+ $ targetPath .= 'xpm ' ;
292+ } else if ($ gdInfo ['WBMP Support ' ]) {
293+ $ targetPath .= 'wbmp ' ;
294+ } else if ($ gdInfo ['GIF Create Support ' ]) {
295+ $ targetPath .= 'gif ' ;
296+ } else if ($ gdInfo ['BMP Support ' ]) {
297+ $ targetPath .= 'bmp ' ;
298+ } else {
299+ $ targetPath = NULL ;
300+ }
301+ }
302+ return $ targetPath ;
303+ }
155304}
156305
0 commit comments