62 */ |
62 */ |
63 public static function supports_mime_type( $mime_type ) { |
63 public static function supports_mime_type( $mime_type ) { |
64 $image_types = imagetypes(); |
64 $image_types = imagetypes(); |
65 switch ( $mime_type ) { |
65 switch ( $mime_type ) { |
66 case 'image/jpeg': |
66 case 'image/jpeg': |
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': |
72 case 'image/webp': |
73 return ( $image_types & IMG_WEBP ) != 0; |
73 return ( $image_types & IMG_WEBP ) !== 0; |
|
74 case 'image/avif': |
|
75 return ( $image_types & IMG_AVIF ) !== 0 && function_exists( 'imageavif' ); |
74 } |
76 } |
75 |
77 |
76 return false; |
78 return false; |
77 } |
79 } |
78 |
80 |
109 $this->image = @imagecreatefromwebp( $this->file ); |
111 $this->image = @imagecreatefromwebp( $this->file ); |
110 } else { |
112 } else { |
111 $this->image = @imagecreatefromstring( $file_contents ); |
113 $this->image = @imagecreatefromstring( $file_contents ); |
112 } |
114 } |
113 |
115 |
|
116 // AVIF may not work with imagecreatefromstring(). |
|
117 if ( |
|
118 function_exists( 'imagecreatefromavif' ) && |
|
119 ( 'image/avif' === wp_get_image_mime( $this->file ) ) |
|
120 ) { |
|
121 $this->image = @imagecreatefromavif( $this->file ); |
|
122 } else { |
|
123 $this->image = @imagecreatefromstring( $file_contents ); |
|
124 } |
|
125 |
114 if ( ! is_gd_image( $this->image ) ) { |
126 if ( ! is_gd_image( $this->image ) ) { |
115 return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file ); |
127 return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file ); |
116 } |
128 } |
117 |
129 |
118 $size = wp_getimagesize( $this->file ); |
130 $size = wp_getimagesize( $this->file ); |
161 * At minimum, either a height or width must be provided. If one of the two is set |
173 * At minimum, either a height or width must be provided. If one of the two is set |
162 * to null, the resize will maintain aspect ratio according to the provided dimension. |
174 * to null, the resize will maintain aspect ratio according to the provided dimension. |
163 * |
175 * |
164 * @since 3.5.0 |
176 * @since 3.5.0 |
165 * |
177 * |
166 * @param int|null $max_w Image width. |
178 * @param int|null $max_w Image width. |
167 * @param int|null $max_h Image height. |
179 * @param int|null $max_h Image height. |
168 * @param bool $crop |
180 * @param bool|array $crop { |
|
181 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
|
182 * If true, image will be cropped to the specified dimensions using center positions. |
|
183 * If an array, the image will be cropped using the array to specify the crop location: |
|
184 * |
|
185 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
|
186 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
187 * } |
169 * @return true|WP_Error |
188 * @return true|WP_Error |
170 */ |
189 */ |
171 public function resize( $max_w, $max_h, $crop = false ) { |
190 public function resize( $max_w, $max_h, $crop = false ) { |
172 if ( ( $this->size['width'] == $max_w ) && ( $this->size['height'] == $max_h ) ) { |
191 if ( ( $this->size['width'] === $max_w ) && ( $this->size['height'] === $max_h ) ) { |
173 return true; |
192 return true; |
174 } |
193 } |
175 |
194 |
176 $resized = $this->_resize( $max_w, $max_h, $crop ); |
195 $resized = $this->_resize( $max_w, $max_h, $crop ); |
177 |
196 |
188 } |
207 } |
189 |
208 |
190 /** |
209 /** |
191 * @param int $max_w |
210 * @param int $max_w |
192 * @param int $max_h |
211 * @param int $max_h |
193 * @param bool|array $crop |
212 * @param bool|array $crop { |
|
213 * Optional. Image cropping behavior. If false, the image will be scaled (default). |
|
214 * If true, image will be cropped to the specified dimensions using center positions. |
|
215 * If an array, the image will be cropped using the array to specify the crop location: |
|
216 * |
|
217 * @type string $0 The x crop position. Accepts 'left' 'center', or 'right'. |
|
218 * @type string $1 The y crop position. Accepts 'top', 'center', or 'bottom'. |
|
219 * } |
194 * @return resource|GdImage|WP_Error |
220 * @return resource|GdImage|WP_Error |
195 */ |
221 */ |
196 protected function _resize( $max_w, $max_h, $crop = false ) { |
222 protected function _resize( $max_w, $max_h, $crop = false ) { |
197 $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); |
223 $dims = image_resize_dimensions( $this->size['width'], $this->size['height'], $max_w, $max_h, $crop ); |
198 |
224 |
234 * maintain aspect ratio according to the source image. |
260 * maintain aspect ratio according to the source image. |
235 * |
261 * |
236 * @type array ...$0 { |
262 * @type array ...$0 { |
237 * Array of height, width values, and whether to crop. |
263 * Array of height, width values, and whether to crop. |
238 * |
264 * |
239 * @type int $width Image width. Optional if `$height` is specified. |
265 * @type int $width Image width. Optional if `$height` is specified. |
240 * @type int $height Image height. Optional if `$width` is specified. |
266 * @type int $height Image height. Optional if `$width` is specified. |
241 * @type bool $crop Optional. Whether to crop the image. Default false. |
267 * @type bool|array $crop Optional. Whether to crop the image. Default false. |
242 * } |
268 * } |
243 * } |
269 * } |
244 * @return array An array of resized images' metadata by size. |
270 * @return array An array of resized images' metadata by size. |
245 */ |
271 */ |
246 public function multi_resize( $sizes ) { |
272 public function multi_resize( $sizes ) { |
263 * @since 5.3.0 |
289 * @since 5.3.0 |
264 * |
290 * |
265 * @param array $size_data { |
291 * @param array $size_data { |
266 * Array of size data. |
292 * Array of size data. |
267 * |
293 * |
268 * @type int $width The maximum width in pixels. |
294 * @type int $width The maximum width in pixels. |
269 * @type int $height The maximum height in pixels. |
295 * @type int $height The maximum height in pixels. |
270 * @type bool $crop Whether to crop the image to exact dimensions. |
296 * @type bool|array $crop Whether to crop the image to exact dimensions. |
271 * } |
297 * } |
272 * @return array|WP_Error The image data array for inclusion in the `sizes` array in the image meta, |
298 * @return array|WP_Error The image data array for inclusion in the `sizes` array in the image meta, |
273 * WP_Error object on error. |
299 * WP_Error object on error. |
274 */ |
300 */ |
275 public function make_subsize( $size_data ) { |
301 public function make_subsize( $size_data ) { |
322 * @param int $dst_h Optional. The destination height. |
348 * @param int $dst_h Optional. The destination height. |
323 * @param bool $src_abs Optional. If the source crop points are absolute. |
349 * @param bool $src_abs Optional. If the source crop points are absolute. |
324 * @return true|WP_Error |
350 * @return true|WP_Error |
325 */ |
351 */ |
326 public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { |
352 public function crop( $src_x, $src_y, $src_w, $src_h, $dst_w = null, $dst_h = null, $src_abs = false ) { |
327 // If destination width/height isn't specified, |
353 /* |
328 // use same as width/height from source. |
354 * If destination width/height isn't specified, |
|
355 * use same as width/height from source. |
|
356 */ |
329 if ( ! $dst_w ) { |
357 if ( ! $dst_w ) { |
330 $dst_w = $src_w; |
358 $dst_w = $src_w; |
331 } |
359 } |
332 if ( ! $dst_h ) { |
360 if ( ! $dst_h ) { |
333 $dst_h = $src_h; |
361 $dst_h = $src_h; |
423 * Saves current in-memory image to file. |
451 * Saves current in-memory image to file. |
424 * |
452 * |
425 * @since 3.5.0 |
453 * @since 3.5.0 |
426 * @since 5.9.0 Renamed `$filename` to `$destfilename` to match parent class |
454 * @since 5.9.0 Renamed `$filename` to `$destfilename` to match parent class |
427 * for PHP 8 named parameter support. |
455 * for PHP 8 named parameter support. |
|
456 * @since 6.0.0 The `$filesize` value was added to the returned array. |
428 * |
457 * |
429 * @param string|null $destfilename Optional. Destination filename. Default null. |
458 * @param string|null $destfilename Optional. Destination filename. Default null. |
430 * @param string|null $mime_type Optional. The mime-type. Default null. |
459 * @param string|null $mime_type Optional. The mime-type. Default null. |
431 * @return array|WP_Error {'path'=>string, 'file'=>string, 'width'=>int, 'height'=>int, 'mime-type'=>string} |
460 * @return array|WP_Error { |
|
461 * Array on success or WP_Error if the file failed to save. |
|
462 * |
|
463 * @type string $path Path to the image file. |
|
464 * @type string $file Name of the image file. |
|
465 * @type int $width Image width. |
|
466 * @type int $height Image height. |
|
467 * @type string $mime-type The mime type of the image. |
|
468 * @type int $filesize File size of the image. |
|
469 * } |
432 */ |
470 */ |
433 public function save( $destfilename = null, $mime_type = null ) { |
471 public function save( $destfilename = null, $mime_type = null ) { |
434 $saved = $this->_save( $this->image, $destfilename, $mime_type ); |
472 $saved = $this->_save( $this->image, $destfilename, $mime_type ); |
435 |
473 |
436 if ( ! is_wp_error( $saved ) ) { |
474 if ( ! is_wp_error( $saved ) ) { |
440 |
478 |
441 return $saved; |
479 return $saved; |
442 } |
480 } |
443 |
481 |
444 /** |
482 /** |
|
483 * @since 3.5.0 |
|
484 * @since 6.0.0 The `$filesize` value was added to the returned array. |
|
485 * |
445 * @param resource|GdImage $image |
486 * @param resource|GdImage $image |
446 * @param string|null $filename |
487 * @param string|null $filename |
447 * @param string|null $mime_type |
488 * @param string|null $mime_type |
448 * @return array|WP_Error |
489 * @return array|WP_Error { |
|
490 * Array on success or WP_Error if the file failed to save. |
|
491 * |
|
492 * @type string $path Path to the image file. |
|
493 * @type string $file Name of the image file. |
|
494 * @type int $width Image width. |
|
495 * @type int $height Image height. |
|
496 * @type string $mime-type The mime type of the image. |
|
497 * @type int $filesize File size of the image. |
|
498 * } |
449 */ |
499 */ |
450 protected function _save( $image, $filename = null, $mime_type = null ) { |
500 protected function _save( $image, $filename = null, $mime_type = null ) { |
451 list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type ); |
501 list( $filename, $extension, $mime_type ) = $this->get_output_format( $filename, $mime_type ); |
452 |
502 |
453 if ( ! $filename ) { |
503 if ( ! $filename ) { |
454 $filename = $this->generate_filename( null, null, $extension ); |
504 $filename = $this->generate_filename( null, null, $extension ); |
|
505 } |
|
506 |
|
507 if ( function_exists( 'imageinterlace' ) ) { |
|
508 /** |
|
509 * Filters whether to output progressive images (if available). |
|
510 * |
|
511 * @since 6.5.0 |
|
512 * |
|
513 * @param bool $interlace Whether to use progressive images for output if available. Default false. |
|
514 * @param string $mime_type The mime type being saved. |
|
515 */ |
|
516 imageinterlace( $image, apply_filters( 'image_save_progressive', false, $mime_type ) ); |
455 } |
517 } |
456 |
518 |
457 if ( 'image/gif' === $mime_type ) { |
519 if ( 'image/gif' === $mime_type ) { |
458 if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) { |
520 if ( ! $this->make_image( $filename, 'imagegif', array( $image, $filename ) ) ) { |
459 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
521 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
469 } |
531 } |
470 } elseif ( 'image/jpeg' === $mime_type ) { |
532 } elseif ( 'image/jpeg' === $mime_type ) { |
471 if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) { |
533 if ( ! $this->make_image( $filename, 'imagejpeg', array( $image, $filename, $this->get_quality() ) ) ) { |
472 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
534 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
473 } |
535 } |
474 } elseif ( 'image/webp' == $mime_type ) { |
536 } elseif ( 'image/webp' === $mime_type ) { |
475 if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) { |
537 if ( ! function_exists( 'imagewebp' ) |
|
538 || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) |
|
539 ) { |
|
540 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
|
541 } |
|
542 } elseif ( 'image/avif' === $mime_type ) { |
|
543 if ( ! function_exists( 'imageavif' ) |
|
544 || ! $this->make_image( $filename, 'imageavif', array( $image, $filename, $this->get_quality() ) ) |
|
545 ) { |
476 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
546 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
477 } |
547 } |
478 } else { |
548 } else { |
479 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
549 return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) ); |
480 } |
550 } |
521 return imagegif( $this->image ); |
591 return imagegif( $this->image ); |
522 case 'image/webp': |
592 case 'image/webp': |
523 if ( function_exists( 'imagewebp' ) ) { |
593 if ( function_exists( 'imagewebp' ) ) { |
524 header( 'Content-Type: image/webp' ); |
594 header( 'Content-Type: image/webp' ); |
525 return imagewebp( $this->image, null, $this->get_quality() ); |
595 return imagewebp( $this->image, null, $this->get_quality() ); |
|
596 } else { |
|
597 // Fall back to JPEG. |
|
598 header( 'Content-Type: image/jpeg' ); |
|
599 return imagejpeg( $this->image, null, $this->get_quality() ); |
526 } |
600 } |
527 // Fall back to the default if webp isn't supported. |
601 case 'image/avif': |
|
602 if ( function_exists( 'imageavif' ) ) { |
|
603 header( 'Content-Type: image/avif' ); |
|
604 return imageavif( $this->image, null, $this->get_quality() ); |
|
605 } |
|
606 // Fall back to JPEG. |
528 default: |
607 default: |
529 header( 'Content-Type: image/jpeg' ); |
608 header( 'Content-Type: image/jpeg' ); |
530 return imagejpeg( $this->image, null, $this->get_quality() ); |
609 return imagejpeg( $this->image, null, $this->get_quality() ); |
531 } |
610 } |
532 } |
611 } |