73 * Registered sub-sizes that are larger than the image are skipped. |
77 * Registered sub-sizes that are larger than the image are skipped. |
74 * |
78 * |
75 * @since 5.3.0 |
79 * @since 5.3.0 |
76 * |
80 * |
77 * @param int $attachment_id The image attachment post ID. |
81 * @param int $attachment_id The image attachment post ID. |
78 * @return array An array of the image sub-sizes that are currently defined but don't exist for this image. |
82 * @return array[] Associative array of arrays of image sub-size information for |
|
83 * missing image sizes, keyed by image size name. |
79 */ |
84 */ |
80 function wp_get_missing_image_subsizes( $attachment_id ) { |
85 function wp_get_missing_image_subsizes( $attachment_id ) { |
81 if ( ! wp_attachment_is_image( $attachment_id ) ) { |
86 if ( ! wp_attachment_is_image( $attachment_id ) ) { |
82 return array(); |
87 return array(); |
83 } |
88 } |
129 /** |
134 /** |
130 * Filters the array of missing image sub-sizes for an uploaded image. |
135 * Filters the array of missing image sub-sizes for an uploaded image. |
131 * |
136 * |
132 * @since 5.3.0 |
137 * @since 5.3.0 |
133 * |
138 * |
134 * @param array $missing_sizes Array with the missing image sub-sizes. |
139 * @param array[] $missing_sizes Associative array of arrays of image sub-size information for |
135 * @param array $image_meta The image meta data. |
140 * missing image sizes, keyed by image size name. |
136 * @param int $attachment_id The image attachment post ID. |
141 * @param array $image_meta The image meta data. |
|
142 * @param int $attachment_id The image attachment post ID. |
137 */ |
143 */ |
138 return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id ); |
144 return apply_filters( 'wp_get_missing_image_subsizes', $missing_sizes, $image_meta, $attachment_id ); |
139 } |
145 } |
140 |
146 |
141 /** |
147 /** |
206 $image_meta['file'] = _wp_relative_upload_path( $new_file ); |
212 $image_meta['file'] = _wp_relative_upload_path( $new_file ); |
207 |
213 |
208 // Store the original image file name in image_meta. |
214 // Store the original image file name in image_meta. |
209 $image_meta['original_image'] = wp_basename( $original_file ); |
215 $image_meta['original_image'] = wp_basename( $original_file ); |
210 |
216 |
|
217 // Add image file size. |
|
218 $image_meta['filesize'] = wp_filesize( $new_file ); |
|
219 |
211 return $image_meta; |
220 return $image_meta; |
212 } |
221 } |
213 |
222 |
214 /** |
223 /** |
215 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata. |
224 * Creates image sub-sizes, adds the new data to the image meta `sizes` array, and updates the image metadata. |
218 * sub-size is created. If there was an error, it is added to the returned image metadata array. |
227 * sub-size is created. If there was an error, it is added to the returned image metadata array. |
219 * |
228 * |
220 * @since 5.3.0 |
229 * @since 5.3.0 |
221 * |
230 * |
222 * @param string $file Full path to the image file. |
231 * @param string $file Full path to the image file. |
223 * @param int $attachment_id Attachment Id to process. |
232 * @param int $attachment_id Attachment ID to process. |
224 * @return array The image attachment meta data. |
233 * @return array The image attachment meta data. |
225 */ |
234 */ |
226 function wp_create_image_subsizes( $file, $attachment_id ) { |
235 function wp_create_image_subsizes( $file, $attachment_id ) { |
227 $imagesize = wp_getimagesize( $file ); |
236 $imagesize = wp_getimagesize( $file ); |
228 |
237 |
231 return array(); |
240 return array(); |
232 } |
241 } |
233 |
242 |
234 // Default image meta. |
243 // Default image meta. |
235 $image_meta = array( |
244 $image_meta = array( |
236 'width' => $imagesize[0], |
245 'width' => $imagesize[0], |
237 'height' => $imagesize[1], |
246 'height' => $imagesize[1], |
238 'file' => _wp_relative_upload_path( $file ), |
247 'file' => _wp_relative_upload_path( $file ), |
239 'sizes' => array(), |
248 'filesize' => wp_filesize( $file ), |
|
249 'sizes' => array(), |
240 ); |
250 ); |
241 |
251 |
242 // Fetch additional metadata from EXIF/IPTC. |
252 // Fetch additional metadata from EXIF/IPTC. |
243 $exif_meta = wp_read_image_metadata( $file ); |
253 $exif_meta = wp_read_image_metadata( $file ); |
244 |
254 |
376 * @access private |
386 * @access private |
377 * |
387 * |
378 * @param array $new_sizes Array defining what sizes to create. |
388 * @param array $new_sizes Array defining what sizes to create. |
379 * @param string $file Full path to the image file. |
389 * @param string $file Full path to the image file. |
380 * @param array $image_meta The attachment meta data array. |
390 * @param array $image_meta The attachment meta data array. |
381 * @param int $attachment_id Attachment Id to process. |
391 * @param int $attachment_id Attachment ID to process. |
382 * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. |
392 * @return array The attachment meta data with updated `sizes` array. Includes an array of errors encountered while resizing. |
383 */ |
393 */ |
384 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { |
394 function _wp_make_subsizes( $new_sizes, $file, $image_meta, $attachment_id ) { |
385 if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { |
395 if ( empty( $image_meta ) || ! is_array( $image_meta ) ) { |
386 // Not an image attachment. |
396 // Not an image attachment. |
466 /** |
476 /** |
467 * Generate attachment meta data and create image sub-sizes for images. |
477 * Generate attachment meta data and create image sub-sizes for images. |
468 * |
478 * |
469 * @since 2.1.0 |
479 * @since 2.1.0 |
470 * |
480 * |
471 * @param int $attachment_id Attachment Id to process. |
481 * @param int $attachment_id Attachment ID to process. |
472 * @param string $file Filepath of the Attached image. |
482 * @param string $file Filepath of the attached image. |
473 * @return array Metadata for attachment. |
483 * @return array Metadata for attachment. |
474 */ |
484 */ |
475 function wp_generate_attachment_metadata( $attachment_id, $file ) { |
485 function wp_generate_attachment_metadata( $attachment_id, $file ) { |
476 $attachment = get_post( $attachment_id ); |
486 $attachment = get_post( $attachment_id ); |
477 |
487 |
625 } |
635 } |
626 |
636 |
627 // Remove the blob of binary data from the array. |
637 // Remove the blob of binary data from the array. |
628 unset( $metadata['image']['data'] ); |
638 unset( $metadata['image']['data'] ); |
629 |
639 |
|
640 // Capture file size for cases where it has not been captured yet, such as PDFs. |
|
641 if ( ! isset( $metadata['filesize'] ) && file_exists( $file ) ) { |
|
642 $metadata['filesize'] = wp_filesize( $file ); |
|
643 } |
|
644 |
630 /** |
645 /** |
631 * Filters the generated attachment meta data. |
646 * Filters the generated attachment meta data. |
632 * |
647 * |
633 * @since 2.1.0 |
648 * @since 2.1.0 |
634 * @since 5.3.0 The `$context` parameter was added. |
649 * @since 5.3.0 The `$context` parameter was added. |
644 /** |
659 /** |
645 * Convert a fraction string to a decimal. |
660 * Convert a fraction string to a decimal. |
646 * |
661 * |
647 * @since 2.5.0 |
662 * @since 2.5.0 |
648 * |
663 * |
649 * @param string $str |
664 * @param string $str Fraction string. |
650 * @return int|float |
665 * @return int|float Returns calculated fraction or integer 0 on invalid input. |
651 */ |
666 */ |
652 function wp_exif_frac2dec( $str ) { |
667 function wp_exif_frac2dec( $str ) { |
653 if ( false === strpos( $str, '/' ) ) { |
668 if ( ! is_scalar( $str ) || is_bool( $str ) ) { |
654 return $str; |
669 return 0; |
|
670 } |
|
671 |
|
672 if ( ! is_string( $str ) ) { |
|
673 return $str; // This can only be an integer or float, so this is fine. |
|
674 } |
|
675 |
|
676 // Fractions passed as a string must contain a single `/`. |
|
677 if ( substr_count( $str, '/' ) !== 1 ) { |
|
678 if ( is_numeric( $str ) ) { |
|
679 return (float) $str; |
|
680 } |
|
681 |
|
682 return 0; |
655 } |
683 } |
656 |
684 |
657 list( $numerator, $denominator ) = explode( '/', $str ); |
685 list( $numerator, $denominator ) = explode( '/', $str ); |
658 if ( ! empty( $denominator ) ) { |
686 |
659 return $numerator / $denominator; |
687 // Both the numerator and the denominator must be numbers. |
660 } |
688 if ( ! is_numeric( $numerator ) || ! is_numeric( $denominator ) ) { |
661 return $str; |
689 return 0; |
|
690 } |
|
691 |
|
692 // The denominator must not be zero. |
|
693 if ( 0 == $denominator ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison -- Deliberate loose comparison. |
|
694 return 0; |
|
695 } |
|
696 |
|
697 return $numerator / $denominator; |
662 } |
698 } |
663 |
699 |
664 /** |
700 /** |
665 * Convert the exif date format to a unix timestamp. |
701 * Convert the exif date format to a unix timestamp. |
666 * |
702 * |
667 * @since 2.5.0 |
703 * @since 2.5.0 |
668 * |
704 * |
669 * @param string $str |
705 * @param string $str A date string expected to be in Exif format (Y:m:d H:i:s). |
670 * @return int |
706 * @return int|false The unix timestamp, or false on failure. |
671 */ |
707 */ |
672 function wp_exif_date2ts( $str ) { |
708 function wp_exif_date2ts( $str ) { |
673 list( $date, $time ) = explode( ' ', trim( $str ) ); |
709 list( $date, $time ) = explode( ' ', trim( $str ) ); |
674 list( $y, $m, $d ) = explode( ':', $date ); |
710 list( $y, $m, $d ) = explode( ':', $date ); |
675 |
711 |
738 } else { |
774 } else { |
739 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
775 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
740 $iptc = @iptcparse( $info['APP13'] ); |
776 $iptc = @iptcparse( $info['APP13'] ); |
741 } |
777 } |
742 |
778 |
|
779 if ( ! is_array( $iptc ) ) { |
|
780 $iptc = array(); |
|
781 } |
|
782 |
743 // Headline, "A brief synopsis of the caption". |
783 // Headline, "A brief synopsis of the caption". |
744 if ( ! empty( $iptc['2#105'][0] ) ) { |
784 if ( ! empty( $iptc['2#105'][0] ) ) { |
745 $meta['title'] = trim( $iptc['2#105'][0] ); |
785 $meta['title'] = trim( $iptc['2#105'][0] ); |
746 /* |
786 /* |
747 * Title, "Many use the Title field to store the filename of the image, |
787 * Title, "Many use the Title field to store the filename of the image, |
791 /** |
831 /** |
792 * Filters the image types to check for exif data. |
832 * Filters the image types to check for exif data. |
793 * |
833 * |
794 * @since 2.5.0 |
834 * @since 2.5.0 |
795 * |
835 * |
796 * @param array $image_types Image types to check for exif data. |
836 * @param int[] $image_types Array of image types to check for exif data. Each value |
|
837 * is usually one of the `IMAGETYPE_*` constants. |
797 */ |
838 */ |
798 $exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ); |
839 $exif_image_types = apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ); |
799 |
840 |
800 if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) { |
841 if ( is_callable( 'exif_read_data' ) && in_array( $image_type, $exif_image_types, true ) ) { |
801 // Don't silence errors when in debug mode, unless running unit tests. |
842 // Don't silence errors when in debug mode, unless running unit tests. |
806 } else { |
847 } else { |
807 // phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480 |
848 // 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 ); |
849 $exif = @exif_read_data( $file ); |
809 } |
850 } |
810 |
851 |
|
852 if ( ! is_array( $exif ) ) { |
|
853 $exif = array(); |
|
854 } |
|
855 |
811 if ( ! empty( $exif['ImageDescription'] ) ) { |
856 if ( ! empty( $exif['ImageDescription'] ) ) { |
812 mbstring_binary_safe_encoding(); |
857 mbstring_binary_safe_encoding(); |
813 $description_length = strlen( $exif['ImageDescription'] ); |
858 $description_length = strlen( $exif['ImageDescription'] ); |
814 reset_mbstring_encoding(); |
859 reset_mbstring_encoding(); |
815 |
860 |
838 } |
883 } |
839 |
884 |
840 if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) { |
885 if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) { |
841 $meta['copyright'] = trim( $exif['Copyright'] ); |
886 $meta['copyright'] = trim( $exif['Copyright'] ); |
842 } |
887 } |
843 if ( ! empty( $exif['FNumber'] ) ) { |
888 if ( ! empty( $exif['FNumber'] ) && is_scalar( $exif['FNumber'] ) ) { |
844 $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 ); |
889 $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 ); |
845 } |
890 } |
846 if ( ! empty( $exif['Model'] ) ) { |
891 if ( ! empty( $exif['Model'] ) ) { |
847 $meta['camera'] = trim( $exif['Model'] ); |
892 $meta['camera'] = trim( $exif['Model'] ); |
848 } |
893 } |
849 if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) { |
894 if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) { |
850 $meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] ); |
895 $meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] ); |
851 } |
896 } |
852 if ( ! empty( $exif['FocalLength'] ) ) { |
897 if ( ! empty( $exif['FocalLength'] ) ) { |
853 $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] ); |
898 $meta['focal_length'] = (string) $exif['FocalLength']; |
|
899 if ( is_scalar( $exif['FocalLength'] ) ) { |
|
900 $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] ); |
|
901 } |
854 } |
902 } |
855 if ( ! empty( $exif['ISOSpeedRatings'] ) ) { |
903 if ( ! empty( $exif['ISOSpeedRatings'] ) ) { |
856 $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings']; |
904 $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings']; |
857 $meta['iso'] = trim( $meta['iso'] ); |
905 $meta['iso'] = trim( $meta['iso'] ); |
858 } |
906 } |
859 if ( ! empty( $exif['ExposureTime'] ) ) { |
907 if ( ! empty( $exif['ExposureTime'] ) ) { |
860 $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] ); |
908 $meta['shutter_speed'] = (string) $exif['ExposureTime']; |
|
909 if ( is_scalar( $exif['ExposureTime'] ) ) { |
|
910 $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] ); |
|
911 } |
861 } |
912 } |
862 if ( ! empty( $exif['Orientation'] ) ) { |
913 if ( ! empty( $exif['Orientation'] ) ) { |
863 $meta['orientation'] = $exif['Orientation']; |
914 $meta['orientation'] = $exif['Orientation']; |
864 } |
915 } |
865 } |
916 } |
915 * |
966 * |
916 * @param string $path File path to test. |
967 * @param string $path File path to test. |
917 * @return bool True if suitable, false if not suitable. |
968 * @return bool True if suitable, false if not suitable. |
918 */ |
969 */ |
919 function file_is_displayable_image( $path ) { |
970 function file_is_displayable_image( $path ) { |
920 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); // phpcs:ignore PHPCompatibility.Constants.NewConstants.imagetype_webpFound |
971 $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP ); |
921 |
972 |
922 $info = wp_getimagesize( $path ); |
973 $info = wp_getimagesize( $path ); |
923 if ( empty( $info ) ) { |
974 if ( empty( $info ) ) { |
924 $result = false; |
975 $result = false; |
925 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |
976 } elseif ( ! in_array( $info[2], $displayable_image_types, true ) ) { |