67 return ( $image_types & IMG_JPG ) != 0; |
67 return ( $image_types & IMG_JPG ) != 0; |
68 case 'image/png': |
68 case 'image/png': |
69 return ( $image_types & IMG_PNG ) != 0; |
69 return ( $image_types & IMG_PNG ) != 0; |
70 case 'image/gif': |
70 case 'image/gif': |
71 return ( $image_types & IMG_GIF ) != 0; |
71 return ( $image_types & IMG_GIF ) != 0; |
|
72 case 'image/webp': |
|
73 return ( $image_types & IMG_WEBP ) != 0; // phpcs:ignore PHPCompatibility.Constants.NewConstants.img_webpFound |
72 } |
74 } |
73 |
75 |
74 return false; |
76 return false; |
75 } |
77 } |
76 |
78 |
77 /** |
79 /** |
78 * Loads image from $this->file into new GD Resource. |
80 * Loads image from $this->file into new GD Resource. |
79 * |
81 * |
80 * @since 3.5.0 |
82 * @since 3.5.0 |
81 * |
83 * |
82 * @return bool|WP_Error True if loaded successfully; WP_Error on failure. |
84 * @return true|WP_Error True if loaded successfully; WP_Error on failure. |
83 */ |
85 */ |
84 public function load() { |
86 public function load() { |
85 if ( $this->image ) { |
87 if ( $this->image ) { |
86 return true; |
88 return true; |
87 } |
89 } |
91 } |
93 } |
92 |
94 |
93 // Set artificially high because GD uses uncompressed images in memory. |
95 // Set artificially high because GD uses uncompressed images in memory. |
94 wp_raise_memory_limit( 'image' ); |
96 wp_raise_memory_limit( 'image' ); |
95 |
97 |
96 $this->image = @imagecreatefromstring( file_get_contents( $this->file ) ); |
98 $file_contents = @file_get_contents( $this->file ); |
97 |
99 |
98 if ( ! is_resource( $this->image ) ) { |
100 if ( ! $file_contents ) { |
|
101 return new WP_Error( 'error_loading_image', __( 'File doesn’t exist?' ), $this->file ); |
|
102 } |
|
103 |
|
104 // WebP may not work with imagecreatefromstring(). |
|
105 if ( |
|
106 function_exists( 'imagecreatefromwebp' ) && |
|
107 ( 'image/webp' === wp_get_image_mime( $this->file ) ) |
|
108 ) { |
|
109 $this->image = @imagecreatefromwebp( $this->file ); |
|
110 } else { |
|
111 $this->image = @imagecreatefromstring( $file_contents ); |
|
112 } |
|
113 |
|
114 if ( ! is_gd_image( $this->image ) ) { |
99 return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file ); |
115 return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file ); |
100 } |
116 } |
101 |
117 |
102 $size = @getimagesize( $this->file ); |
118 $size = wp_getimagesize( $this->file ); |
|
119 |
103 if ( ! $size ) { |
120 if ( ! $size ) { |
104 return new WP_Error( 'invalid_image', __( 'Could not read image size.' ), $this->file ); |
121 return new WP_Error( 'invalid_image', __( 'Could not read image size.' ), $this->file ); |
105 } |
122 } |
106 |
123 |
107 if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) { |
124 if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) { |
136 return parent::update_size( $width, $height ); |
153 return parent::update_size( $width, $height ); |
137 } |
154 } |
138 |
155 |
139 /** |
156 /** |
140 * Resizes current image. |
157 * Resizes current image. |
141 * Wraps _resize, since _resize returns a GD Resource. |
158 * |
142 * |
159 * Wraps `::_resize()` which returns a GD resource or GdImage instance. |
143 * At minimum, either a height or width must be provided. |
160 * |
144 * If one of the two is set to null, the resize will |
161 * At minimum, either a height or width must be provided. If one of the two is set |
145 * maintain aspect ratio according to the provided dimension. |
162 * to null, the resize will maintain aspect ratio according to the provided dimension. |
146 * |
163 * |
147 * @since 3.5.0 |
164 * @since 3.5.0 |
148 * |
165 * |
149 * @param int|null $max_w Image width. |
166 * @param int|null $max_w Image width. |
150 * @param int|null $max_h Image height. |
167 * @param int|null $max_h Image height. |
156 return true; |
173 return true; |
157 } |
174 } |
158 |
175 |
159 $resized = $this->_resize( $max_w, $max_h, $crop ); |
176 $resized = $this->_resize( $max_w, $max_h, $crop ); |
160 |
177 |
161 if ( is_resource( $resized ) ) { |
178 if ( is_gd_image( $resized ) ) { |
162 imagedestroy( $this->image ); |
179 imagedestroy( $this->image ); |
163 $this->image = $resized; |
180 $this->image = $resized; |
164 return true; |
181 return true; |
165 |
182 |
166 } elseif ( is_wp_error( $resized ) ) { |
183 } elseif ( is_wp_error( $resized ) ) { |
172 |
189 |
173 /** |
190 /** |
174 * @param int $max_w |
191 * @param int $max_w |
175 * @param int $max_h |
192 * @param int $max_h |
176 * @param bool|array $crop |
193 * @param bool|array $crop |
177 * @return resource|WP_Error |
194 * @return resource|GdImage|WP_Error |
178 */ |
195 */ |
179 protected function _resize( $max_w, $max_h, $crop = false ) { |
196 protected function _resize( $max_w, $max_h, $crop = false ) { |
180 $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); |
197 $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); |
181 |
198 |
182 if ( ! $dims ) { |
199 if ( ! $dims ) { |
186 list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims; |
203 list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims; |
187 |
204 |
188 $resized = wp_imagecreatetruecolor( $dst_w, $dst_h ); |
205 $resized = wp_imagecreatetruecolor( $dst_w, $dst_h ); |
189 imagecopyresampled( $resized, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); |
206 imagecopyresampled( $resized, $this->image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); |
190 |
207 |
191 if ( is_resource( $resized ) ) { |
208 if ( is_gd_image( $resized ) ) { |
192 $this->update_size( $dst_w, $dst_h ); |
209 $this->update_size( $dst_w, $dst_h ); |
193 return $resized; |
210 return $resized; |
194 } |
211 } |
195 |
212 |
196 return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ), $this->file ); |
213 return new WP_Error( 'image_resize_error', __( 'Image resize failed.' ), $this->file ); |
302 * @param int $src_w The width to crop. |
319 * @param int $src_w The width to crop. |
303 * @param int $src_h The height to crop. |
320 * @param int $src_h The height to crop. |
304 * @param int $dst_w Optional. The destination width. |
321 * @param int $dst_w Optional. The destination width. |
305 * @param int $dst_h Optional. The destination height. |
322 * @param int $dst_h Optional. The destination height. |
306 * @param bool $src_abs Optional. If the source crop points are absolute. |
323 * @param bool $src_abs Optional. If the source crop points are absolute. |
307 * @return bool|WP_Error |
324 * @return true|WP_Error |
308 */ |
325 */ |
309 public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { |
326 public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { |
310 // If destination width/height isn't specified, |
327 // If destination width/height isn't specified, |
311 // use same as width/height from source. |
328 // use same as width/height from source. |
312 if ( ! $dst_w ) { |
329 if ( ! $dst_w ) { |
314 } |
331 } |
315 if ( ! $dst_h ) { |
332 if ( ! $dst_h ) { |
316 $dst_h = $src_h; |
333 $dst_h = $src_h; |
317 } |
334 } |
318 |
335 |
319 $dst = wp_imagecreatetruecolor( $dst_w, $dst_h ); |
336 foreach ( array( $src_w, $src_h, $dst_w, $dst_h ) as $value ) { |
|
337 if ( ! is_numeric( $value ) || (int) $value <= 0 ) { |
|
338 return new WP_Error( 'image_crop_error', __( 'Image crop failed.' ), $this->file ); |
|
339 } |
|
340 } |
|
341 |
|
342 $dst = wp_imagecreatetruecolor( (int) $dst_w, (int) $dst_h ); |
320 |
343 |
321 if ( $src_abs ) { |
344 if ( $src_abs ) { |
322 $src_w -= $src_x; |
345 $src_w -= $src_x; |
323 $src_h -= $src_y; |
346 $src_h -= $src_y; |
324 } |
347 } |
325 |
348 |
326 if ( function_exists( 'imageantialias' ) ) { |
349 if ( function_exists( 'imageantialias' ) ) { |
327 imageantialias( $dst, true ); |
350 imageantialias( $dst, true ); |
328 } |
351 } |
329 |
352 |
330 imagecopyresampled( $dst, $this->image, 0, 0, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ); |
353 imagecopyresampled( $dst, $this->image, 0, 0, (int) $src_x, (int) $src_y, (int) $dst_w, (int) $dst_h, (int) $src_w, (int) $src_h ); |
331 |
354 |
332 if ( is_resource( $dst ) ) { |
355 if ( is_gd_image( $dst ) ) { |
333 imagedestroy( $this->image ); |
356 imagedestroy( $this->image ); |
334 $this->image = $dst; |
357 $this->image = $dst; |
335 $this->update_size(); |
358 $this->update_size(); |
336 return true; |
359 return true; |
337 } |
360 } |
351 public function rotate( $angle ) { |
374 public function rotate( $angle ) { |
352 if ( function_exists( 'imagerotate' ) ) { |
375 if ( function_exists( 'imagerotate' ) ) { |
353 $transparency = imagecolorallocatealpha( $this->image, 255, 255, 255, 127 ); |
376 $transparency = imagecolorallocatealpha( $this->image, 255, 255, 255, 127 ); |
354 $rotated = imagerotate( $this->image, $angle, $transparency ); |
377 $rotated = imagerotate( $this->image, $angle, $transparency ); |
355 |
378 |
356 if ( is_resource( $rotated ) ) { |
379 if ( is_gd_image( $rotated ) ) { |
357 imagealphablending( $rotated, true ); |
380 imagealphablending( $rotated, true ); |
358 imagesavealpha( $rotated, true ); |
381 imagesavealpha( $rotated, true ); |
359 imagedestroy( $this->image ); |
382 imagedestroy( $this->image ); |
360 $this->image = $rotated; |
383 $this->image = $rotated; |
361 $this->update_size(); |
384 $this->update_size(); |
362 return true; |
385 return true; |
363 } |
386 } |
364 } |
387 } |
|
388 |
365 return new WP_Error( 'image_rotate_error', __( 'Image rotate failed.' ), $this->file ); |
389 return new WP_Error( 'image_rotate_error', __( 'Image rotate failed.' ), $this->file ); |
366 } |
390 } |
367 |
391 |
368 /** |
392 /** |
369 * Flips current image. |
393 * Flips current image. |
377 public function flip( $horz, $vert ) { |
401 public function flip( $horz, $vert ) { |
378 $w = $this->size['width']; |
402 $w = $this->size['width']; |
379 $h = $this->size['height']; |
403 $h = $this->size['height']; |
380 $dst = wp_imagecreatetruecolor( $w, $h ); |
404 $dst = wp_imagecreatetruecolor( $w, $h ); |
381 |
405 |
382 if ( is_resource( $dst ) ) { |
406 if ( is_gd_image( $dst ) ) { |
383 $sx = $vert ? ( $w - 1 ) : 0; |
407 $sx = $vert ? ( $w - 1 ) : 0; |
384 $sy = $horz ? ( $h - 1 ) : 0; |
408 $sy = $horz ? ( $h - 1 ) : 0; |
385 $sw = $vert ? -$w : $w; |
409 $sw = $vert ? -$w : $w; |
386 $sh = $horz ? -$h : $h; |
410 $sh = $horz ? -$h : $h; |
387 |
411 |
413 |
438 |
414 return $saved; |
439 return $saved; |
415 } |
440 } |
416 |
441 |
417 /** |
442 /** |
418 * @param resource $image |
443 * @param resource|GdImage $image |
419 * @param string|null $filename |
444 * @param string|null $filename |
420 * @param string|null $mime_type |
445 * @param string|null $mime_type |
421 * @return array|WP_Error |
446 * @return array|WP_Error |
422 */ |
447 */ |
423 protected function _save( $image, $filename = null, $mime_type = null ) { |
448 protected function _save( $image, $filename = null, $mime_type = null ) { |
424 list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type ); |
449 list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type ); |
425 |
450 |
440 if ( ! $this->make_image( $filename, 'imagepng', array( $image, $filename ) ) ) { |
465 if ( ! $this->make_image( $filename, 'imagepng', array( $image, $filename ) ) ) { |
441 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
466 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
442 } |
467 } |
443 } elseif ( 'image/jpeg' === $mime_type ) { |
468 } elseif ( 'image/jpeg' === $mime_type ) { |
444 if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) { |
469 if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) { |
|
470 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
|
471 } |
|
472 } elseif ( 'image/webp' == $mime_type ) { |
|
473 if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) { |
445 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
474 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
446 } |
475 } |
447 } else { |
476 } else { |
448 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
477 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
449 } |
478 } |
485 header( 'Content-Type: image/png' ); |
514 header( 'Content-Type: image/png' ); |
486 return imagepng( $this->image ); |
515 return imagepng( $this->image ); |
487 case 'image/gif': |
516 case 'image/gif': |
488 header( 'Content-Type: image/gif' ); |
517 header( 'Content-Type: image/gif' ); |
489 return imagegif( $this->image ); |
518 return imagegif( $this->image ); |
|
519 case 'image/webp': |
|
520 if ( function_exists( 'imagewebp' ) ) { |
|
521 header( 'Content-Type: image/webp' ); |
|
522 return imagewebp( $this->image, null, $this->get_quality() ); |
|
523 } |
|
524 // Fall back to the default if webp isn't supported. |
490 default: |
525 default: |
491 header( 'Content-Type: image/jpeg' ); |
526 header( 'Content-Type: image/jpeg' ); |
492 return imagejpeg( $this->image, null, $this->get_quality() ); |
527 return imagejpeg( $this->image, null, $this->get_quality() ); |
493 } |
528 } |
494 } |
529 } |