9 /** |
9 /** |
10 * Crops an image to a given size. |
10 * Crops an image to a given size. |
11 * |
11 * |
12 * @since 2.1.0 |
12 * @since 2.1.0 |
13 * |
13 * |
14 * @param string|int $src The source file or Attachment ID. |
14 * @param string|int $src The source file or Attachment ID. |
15 * @param int $src_x The start x position to crop from. |
15 * @param int $src_x The start x position to crop from. |
16 * @param int $src_y The start y position to crop from. |
16 * @param int $src_y The start y position to crop from. |
17 * @param int $src_w The width to crop. |
17 * @param int $src_w The width to crop. |
18 * @param int $src_h The height to crop. |
18 * @param int $src_h The height to crop. |
19 * @param int $dst_w The destination width. |
19 * @param int $dst_w The destination width. |
20 * @param int $dst_h The destination height. |
20 * @param int $dst_h The destination height. |
21 * @param bool $src_abs Optional. If the source crop points are absolute. |
21 * @param bool|false $src_abs Optional. If the source crop points are absolute. |
22 * @param string $dst_file Optional. The destination file to write to. |
22 * @param string|false $dst_file Optional. The destination file to write to. |
23 * @return string|WP_Error New filepath on success, WP_Error on failure. |
23 * @return string|WP_Error New filepath on success, WP_Error on failure. |
24 */ |
24 */ |
25 function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) { |
25 function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) { |
26 $src_file = $src; |
26 $src_file = $src; |
27 if ( is_numeric( $src ) ) { // Handle int as attachment ID. |
27 if ( is_numeric( $src ) ) { // Handle int as attachment ID. |
91 } |
91 } |
92 |
92 |
93 // Use the originally uploaded image dimensions as full_width and full_height. |
93 // Use the originally uploaded image dimensions as full_width and full_height. |
94 if ( ! empty( $image_meta['original_image'] ) ) { |
94 if ( ! empty( $image_meta['original_image'] ) ) { |
95 $image_file = wp_get_original_image_path( $attachment_id ); |
95 $image_file = wp_get_original_image_path( $attachment_id ); |
96 $imagesize = @getimagesize( $image_file ); |
96 $imagesize = wp_getimagesize( $image_file ); |
97 } |
97 } |
98 |
98 |
99 if ( ! empty( $imagesize ) ) { |
99 if ( ! empty( $imagesize ) ) { |
100 $full_width = $imagesize[0]; |
100 $full_width = $imagesize[0]; |
101 $full_height = $imagesize[1]; |
101 $full_height = $imagesize[1]; |
222 * @param string $file Full path to the image file. |
222 * @param string $file Full path to the image file. |
223 * @param int $attachment_id Attachment Id to process. |
223 * @param int $attachment_id Attachment Id to process. |
224 * @return array The image attachment meta data. |
224 * @return array The image attachment meta data. |
225 */ |
225 */ |
226 function wp_create_image_subsizes( $file, $attachment_id ) { |
226 function wp_create_image_subsizes( $file, $attachment_id ) { |
227 $imagesize = @getimagesize( $file ); |
227 $imagesize = wp_getimagesize( $file ); |
228 |
228 |
229 if ( empty( $imagesize ) ) { |
229 if ( empty( $imagesize ) ) { |
230 // File is not an image. |
230 // File is not an image. |
231 return array(); |
231 return array(); |
232 } |
232 } |
486 $metadata = wp_read_video_metadata( $file ); |
486 $metadata = wp_read_video_metadata( $file ); |
487 $support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' ); |
487 $support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' ); |
488 } elseif ( wp_attachment_is( 'audio', $attachment ) ) { |
488 } elseif ( wp_attachment_is( 'audio', $attachment ) ) { |
489 $metadata = wp_read_audio_metadata( $file ); |
489 $metadata = wp_read_audio_metadata( $file ); |
490 $support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) || post_type_supports( 'attachment:audio', 'thumbnail' ); |
490 $support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) || post_type_supports( 'attachment:audio', 'thumbnail' ); |
|
491 } |
|
492 |
|
493 /* |
|
494 * wp_read_video_metadata() and wp_read_audio_metadata() return `false` |
|
495 * if the attachment does not exist in the local filesystem, |
|
496 * so make sure to convert the value to an array. |
|
497 */ |
|
498 if ( ! is_array( $metadata ) ) { |
|
499 $metadata = array(); |
491 } |
500 } |
492 |
501 |
493 if ( $support && ! empty( $metadata['image']['data'] ) ) { |
502 if ( $support && ! empty( $metadata['image']['data'] ) ) { |
494 // Check for existing cover. |
503 // Check for existing cover. |
495 $hash = md5( $metadata['image']['data'] ); |
504 $hash = md5( $metadata['image']['data'] ); |
678 * |
688 * |
679 * @todo Try other exif libraries if available. |
689 * @todo Try other exif libraries if available. |
680 * @since 2.5.0 |
690 * @since 2.5.0 |
681 * |
691 * |
682 * @param string $file |
692 * @param string $file |
683 * @return bool|array False on failure. Image metadata array on success. |
693 * @return array|false Image metadata array on success, false on failure. |
684 */ |
694 */ |
685 function wp_read_image_metadata( $file ) { |
695 function wp_read_image_metadata( $file ) { |
686 if ( ! file_exists( $file ) ) { |
696 if ( ! file_exists( $file ) ) { |
687 return false; |
697 return false; |
688 } |
698 } |
689 |
699 |
690 list( , , $image_type ) = @getimagesize( $file ); |
700 list( , , $image_type ) = wp_getimagesize( $file ); |
691 |
701 |
692 /* |
702 /* |
693 * EXIF contains a bunch of data we'll probably never need formatted in ways |
703 * EXIF contains a bunch of data we'll probably never need formatted in ways |
694 * that are difficult to use. We'll normalize it and just extract the fields |
704 * that are difficult to use. We'll normalize it and just extract the fields |
695 * that are likely to be useful. Fractions and numbers are converted to |
705 * that are likely to be useful. Fractions and numbers are converted to |
709 'orientation' => 0, |
719 'orientation' => 0, |
710 'keywords' => array(), |
720 'keywords' => array(), |
711 ); |
721 ); |
712 |
722 |
713 $iptc = array(); |
723 $iptc = array(); |
|
724 $info = array(); |
714 /* |
725 /* |
715 * Read IPTC first, since it might contain data not available in exif such |
726 * Read IPTC first, since it might contain data not available in exif such |
716 * as caption, description etc. |
727 * as caption, description etc. |
717 */ |
728 */ |
718 if ( is_callable( 'iptcparse' ) ) { |
729 if ( is_callable( 'iptcparse' ) ) { |
719 @getimagesize( $file, $info ); |
730 wp_getimagesize( $file, $info ); |
720 |
731 |
721 if ( ! empty( $info['APP13'] ) ) { |
732 if ( ! empty( $info['APP13'] ) ) { |
722 $iptc = @iptcparse( $info['APP13'] ); |
733 // Don't silence errors when in debug mode, unless running unit tests. |
|
734 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
|
735 && ! defined( 'WP_RUN_CORE_TESTS' ) |
|
736 ) { |
|
737 $iptc = iptcparse( $info['APP13'] ); |
|
738 } else { |
|
739 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
|
740 $iptc = @iptcparse( $info['APP13'] ); |
|
741 } |
723 |
742 |
724 // Headline, "A brief synopsis of the caption". |
743 // Headline, "A brief synopsis of the caption". |
725 if ( ! empty( $iptc['2#105'][0] ) ) { |
744 if ( ! empty( $iptc['2#105'][0] ) ) { |
726 $meta['title'] = trim( $iptc['2#105'][0] ); |
745 $meta['title'] = trim( $iptc['2#105'][0] ); |
727 /* |
746 /* |
777 * @param array $image_types Image types to check for exif data. |
796 * @param array $image_types Image types to check for exif data. |
778 */ |
797 */ |
779 $exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ); |
798 $exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ); |
780 |
799 |
781 if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) { |
800 if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) { |
782 $exif = @exif_read_data( $file ); |
801 // Don't silence errors when in debug mode, unless running unit tests. |
|
802 if ( defined( 'WP_DEBUG' ) && WP_DEBUG |
|
803 && ! defined( 'WP_RUN_CORE_TESTS' ) |
|
804 ) { |
|
805 $exif = exif_read_data( $file ); |
|
806 } else { |
|
807 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
|
808 $exif = @exif_read_data( $file ); |
|
809 } |
783 |
810 |
784 if ( ! empty( $exif['ImageDescription'] ) ) { |
811 if ( ! empty( $exif['ImageDescription'] ) ) { |
785 mbstring_binary_safe_encoding(); |
812 mbstring_binary_safe_encoding(); |
786 $description_length = strlen( $exif['ImageDescription'] ); |
813 $description_length = strlen( $exif['ImageDescription'] ); |
787 reset_mbstring_encoding(); |
814 reset_mbstring_encoding(); |
888 * |
915 * |
889 * @param string $path File path to test. |
916 * @param string $path File path to test. |
890 * @return bool True if suitable, false if not suitable. |
917 * @return bool True if suitable, false if not suitable. |
891 */ |
918 */ |
892 function file_is_displayable_image( $path ) { |
919 function file_is_displayable_image( $path ) { |
893 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO ); |
920 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound |
894 |
921 |
895 $info = @getimagesize( $path ); |
922 $info = wp_getimagesize( $path ); |
896 if ( empty( $info ) ) { |
923 if ( empty( $info ) ) { |
897 $result = false; |
924 $result = false; |
898 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |
925 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |
899 $result = false; |
926 $result = false; |
900 } else { |
927 } else { |
915 /** |
942 /** |
916 * Load an image resource for editing. |
943 * Load an image resource for editing. |
917 * |
944 * |
918 * @since 2.9.0 |
945 * @since 2.9.0 |
919 * |
946 * |
920 * @param string $attachment_id Attachment ID. |
947 * @param int $attachment_id Attachment ID. |
921 * @param string $mime_type Image mime type. |
948 * @param string $mime_type Image mime type. |
922 * @param string $size Optional. Image size, defaults to 'full'. |
949 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array |
923 * @return resource|false The resulting image resource on success, false on failure. |
950 * of width and height values in pixels (in that order). Default 'full'. |
|
951 * @return resource|GdImage|false The resulting image resource or GdImage instance on success, |
|
952 * false on failure. |
924 */ |
953 */ |
925 function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) { |
954 function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) { |
926 $filepath = _load_image_to_edit_path( $attachment_id, $size ); |
955 $filepath = _load_image_to_edit_path( $attachment_id, $size ); |
927 if ( empty( $filepath ) ) { |
956 if ( empty( $filepath ) ) { |
928 return false; |
957 return false; |
936 $image = imagecreatefrompng( $filepath ); |
965 $image = imagecreatefrompng( $filepath ); |
937 break; |
966 break; |
938 case 'image/gif': |
967 case 'image/gif': |
939 $image = imagecreatefromgif( $filepath ); |
968 $image = imagecreatefromgif( $filepath ); |
940 break; |
969 break; |
|
970 case 'image/webp': |
|
971 $image = false; |
|
972 if ( function_exists( 'imagecreatefromwebp' ) ) { |
|
973 $image = imagecreatefromwebp( $filepath ); |
|
974 } |
|
975 break; |
941 default: |
976 default: |
942 $image = false; |
977 $image = false; |
943 break; |
978 break; |
944 } |
979 } |
945 if ( is_resource( $image ) ) { |
980 |
|
981 if ( is_gd_image( $image ) ) { |
946 /** |
982 /** |
947 * Filters the current image being loaded for editing. |
983 * Filters the current image being loaded for editing. |
948 * |
984 * |
949 * @since 2.9.0 |
985 * @since 2.9.0 |
950 * |
986 * |
951 * @param resource $image Current image. |
987 * @param resource|GdImage $image Current image. |
952 * @param string $attachment_id Attachment ID. |
988 * @param int $attachment_id Attachment ID. |
953 * @param string $size Image size. |
989 * @param string|int[] $size Requested image size. Can be any registered image size name, or |
|
990 * an array of width and height values in pixels (in that order). |
954 */ |
991 */ |
955 $image = apply_filters( 'load_image_to_edit', $image, $attachment_id, $size ); |
992 $image = apply_filters( 'load_image_to_edit', $image, $attachment_id, $size ); |
|
993 |
956 if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) { |
994 if ( function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) { |
957 imagealphablending( $image, false ); |
995 imagealphablending( $image, false ); |
958 imagesavealpha( $image, true ); |
996 imagesavealpha( $image, true ); |
959 } |
997 } |
960 } |
998 } |
|
999 |
961 return $image; |
1000 return $image; |
962 } |
1001 } |
963 |
1002 |
964 /** |
1003 /** |
965 * Retrieve the path or url of an attachment's attached file. |
1004 * Retrieve the path or URL of an attachment's attached file. |
966 * |
1005 * |
967 * If the attached file is not present on the local filesystem (usually due to replication plugins), |
1006 * If the attached file is not present on the local filesystem (usually due to replication plugins), |
968 * then the url of the file is returned if url fopen is supported. |
1007 * then the URL of the file is returned if `allow_url_fopen` is supported. |
969 * |
1008 * |
970 * @since 3.4.0 |
1009 * @since 3.4.0 |
971 * @access private |
1010 * @access private |
972 * |
1011 * |
973 * @param string $attachment_id Attachment ID. |
1012 * @param int $attachment_id Attachment ID. |
974 * @param string $size Optional. Image size, defaults to 'full'. |
1013 * @param string|int[] $size Optional. Image size. Accepts any registered image size name, or an array |
975 * @return string|false File path or url on success, false on failure. |
1014 * of width and height values in pixels (in that order). Default 'full'. |
|
1015 * @return string|false File path or URL on success, false on failure. |
976 */ |
1016 */ |
977 function _load_image_to_edit_path( $attachment_id, $size = 'full' ) { |
1017 function _load_image_to_edit_path( $attachment_id, $size = 'full' ) { |
978 $filepath = get_attached_file( $attachment_id ); |
1018 $filepath = get_attached_file( $attachment_id ); |
979 |
1019 |
980 if ( $filepath && file_exists( $filepath ) ) { |
1020 if ( $filepath && file_exists( $filepath ) ) { |
983 |
1023 |
984 if ( $data ) { |
1024 if ( $data ) { |
985 $filepath = path_join( dirname( $filepath ), $data['file'] ); |
1025 $filepath = path_join( dirname( $filepath ), $data['file'] ); |
986 |
1026 |
987 /** |
1027 /** |
988 * Filters the path to the current image. |
1028 * Filters the path to an attachment's file when editing the image. |
989 * |
1029 * |
990 * The filter is evaluated for all image sizes except 'full'. |
1030 * The filter is evaluated for all image sizes except 'full'. |
991 * |
1031 * |
992 * @since 3.1.0 |
1032 * @since 3.1.0 |
993 * |
1033 * |
994 * @param string $path Path to the current image. |
1034 * @param string $path Path to the current image. |
995 * @param string $attachment_id Attachment ID. |
1035 * @param int $attachment_id Attachment ID. |
996 * @param string $size Size of the image. |
1036 * @param string|int[] $size Requested image size. Can be any registered image size name, or |
|
1037 * an array of width and height values in pixels (in that order). |
997 */ |
1038 */ |
998 $filepath = apply_filters( 'load_image_to_edit_filesystempath', $filepath, $attachment_id, $size ); |
1039 $filepath = apply_filters( 'load_image_to_edit_filesystempath', $filepath, $attachment_id, $size ); |
999 } |
1040 } |
1000 } |
1041 } |
1001 } elseif ( function_exists( 'fopen' ) && ini_get( 'allow_url_fopen' ) ) { |
1042 } elseif ( function_exists( 'fopen' ) && ini_get( 'allow_url_fopen' ) ) { |
1002 /** |
1043 /** |
1003 * Filters the image URL if not in the local filesystem. |
1044 * Filters the path to an attachment's URL when editing the image. |
1004 * |
1045 * |
1005 * The filter is only evaluated if fopen is enabled on the server. |
1046 * The filter is only evaluated if the file isn't stored locally and `allow_url_fopen` is enabled on the server. |
1006 * |
1047 * |
1007 * @since 3.1.0 |
1048 * @since 3.1.0 |
1008 * |
1049 * |
1009 * @param string $image_url Current image URL. |
1050 * @param string|false $image_url Current image URL. |
1010 * @param string $attachment_id Attachment ID. |
1051 * @param int $attachment_id Attachment ID. |
1011 * @param string $size Size of the image. |
1052 * @param string|int[] $size Requested image size. Can be any registered image size name, or |
|
1053 * an array of width and height values in pixels (in that order). |
1012 */ |
1054 */ |
1013 $filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size ); |
1055 $filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size ); |
1014 } |
1056 } |
1015 |
1057 |
1016 /** |
1058 /** |
1017 * Filters the returned path or URL of the current image. |
1059 * Filters the returned path or URL of the current image. |
1018 * |
1060 * |
1019 * @since 2.9.0 |
1061 * @since 2.9.0 |
1020 * |
1062 * |
1021 * @param string|bool $filepath File path or URL to current image, or false. |
1063 * @param string|false $filepath File path or URL to current image, or false. |
1022 * @param string $attachment_id Attachment ID. |
1064 * @param int $attachment_id Attachment ID. |
1023 * @param string $size Size of the image. |
1065 * @param string|int[] $size Requested image size. Can be any registered image size name, or |
|
1066 * an array of width and height values in pixels (in that order). |
1024 */ |
1067 */ |
1025 return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size ); |
1068 return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size ); |
1026 } |
1069 } |
1027 |
1070 |
1028 /** |
1071 /** |
1029 * Copy an existing image file. |
1072 * Copy an existing image file. |
1030 * |
1073 * |
1031 * @since 3.4.0 |
1074 * @since 3.4.0 |
1032 * @access private |
1075 * @access private |
1033 * |
1076 * |
1034 * @param string $attachment_id Attachment ID. |
1077 * @param int $attachment_id Attachment ID. |
1035 * @return string|false New file path on success, false on failure. |
1078 * @return string|false New file path on success, false on failure. |
1036 */ |
1079 */ |
1037 function _copy_image_file( $attachment_id ) { |
1080 function _copy_image_file( $attachment_id ) { |
1038 $dst_file = get_attached_file( $attachment_id ); |
1081 $dst_file = get_attached_file( $attachment_id ); |
1039 $src_file = $dst_file; |
1082 $src_file = $dst_file; |