WordPress Version: 6.5
/**
* Gets extended image metadata, exif or iptc as available.
*
* Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso
* created_timestamp, focal_length, shutter_speed, and title.
*
* The IPTC metadata that is retrieved is APP13, credit, byline, created date
* and time, caption, copyright, and title. Also includes FNumber, Model,
* DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime.
*
* @todo Try other exif libraries if available.
* @since 2.5.0
*
* @param string $file
* @return array|false Image metadata array on success, false on failure.
*/
function wp_read_image_metadata($file)
{
if (!file_exists($file)) {
return false;
}
list(, , $image_type) = wp_getimagesize($file);
/*
* EXIF contains a bunch of data we'll probably never need formatted in ways
* that are difficult to use. We'll normalize it and just extract the fields
* that are likely to be useful. Fractions and numbers are converted to
* floats, dates to unix timestamps, and everything else to strings.
*/
$meta = array('aperture' => 0, 'credit' => '', 'camera' => '', 'caption' => '', 'created_timestamp' => 0, 'copyright' => '', 'focal_length' => 0, 'iso' => 0, 'shutter_speed' => 0, 'title' => '', 'orientation' => 0, 'keywords' => array());
$iptc = array();
$info = array();
/*
* Read IPTC first, since it might contain data not available in exif such
* as caption, description etc.
*/
if (is_callable('iptcparse')) {
wp_getimagesize($file, $info);
if (!empty($info['APP13'])) {
// Don't silence errors when in debug mode, unless running unit tests.
if (defined('WP_DEBUG') && WP_DEBUG && !defined('WP_RUN_CORE_TESTS')) {
$iptc = iptcparse($info['APP13']);
} else {
// Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
$iptc = @iptcparse($info['APP13']);
}
if (!is_array($iptc)) {
$iptc = array();
}
// Headline, "A brief synopsis of the caption".
if (!empty($iptc['2#105'][0])) {
$meta['title'] = trim($iptc['2#105'][0]);
/*
* Title, "Many use the Title field to store the filename of the image,
* though the field may be used in many ways".
*/
} elseif (!empty($iptc['2#005'][0])) {
$meta['title'] = trim($iptc['2#005'][0]);
}
if (!empty($iptc['2#120'][0])) {
// Description / legacy caption.
$caption = trim($iptc['2#120'][0]);
mbstring_binary_safe_encoding();
$caption_length = strlen($caption);
reset_mbstring_encoding();
if (empty($meta['title']) && $caption_length < 80) {
// Assume the title is stored in 2:120 if it's short.
$meta['title'] = $caption;
}
$meta['caption'] = $caption;
}
if (!empty($iptc['2#110'][0])) {
// Credit.
$meta['credit'] = trim($iptc['2#110'][0]);
} elseif (!empty($iptc['2#080'][0])) {
// Creator / legacy byline.
$meta['credit'] = trim($iptc['2#080'][0]);
}
if (!empty($iptc['2#055'][0]) && !empty($iptc['2#060'][0])) {
// Created date and time.
$meta['created_timestamp'] = strtotime($iptc['2#055'][0] . ' ' . $iptc['2#060'][0]);
}
if (!empty($iptc['2#116'][0])) {
// Copyright.
$meta['copyright'] = trim($iptc['2#116'][0]);
}
if (!empty($iptc['2#025'][0])) {
// Keywords array.
$meta['keywords'] = array_values($iptc['2#025']);
}
}
}
$exif = array();
/**
* Filters the image types to check for exif data.
*
* @since 2.5.0
*
* @param int[] $image_types Array of image types to check for exif data. Each value
* is usually one of the `IMAGETYPE_*` constants.
*/
$exif_image_types = apply_filters('wp_read_image_metadata_types', array(IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM));
if (is_callable('exif_read_data') && in_array($image_type, $exif_image_types, true)) {
// Don't silence errors when in debug mode, unless running unit tests.
if (defined('WP_DEBUG') && WP_DEBUG && !defined('WP_RUN_CORE_TESTS')) {
$exif = exif_read_data($file);
} else {
// Silencing notice and warning is intentional. See https://core.trac.wordpress.org/ticket/42480
$exif = @exif_read_data($file);
}
if (!is_array($exif)) {
$exif = array();
}
$exif_description = '';
$exif_usercomment = '';
if (!empty($exif['ImageDescription'])) {
$exif_description = trim($exif['ImageDescription']);
}
if (!empty($exif['COMPUTED']['UserComment'])) {
$exif_usercomment = trim($exif['COMPUTED']['UserComment']);
}
if ($exif_description) {
mbstring_binary_safe_encoding();
$description_length = strlen($exif_description);
reset_mbstring_encoding();
if (empty($meta['title']) && $description_length < 80) {
// Assume the title is stored in ImageDescription.
$meta['title'] = $exif_description;
}
// If both user comments and description are present.
if (empty($meta['caption']) && $exif_description && $exif_usercomment) {
if (!empty($meta['title']) && $exif_description === $meta['title']) {
$caption = $exif_usercomment;
} else if ($exif_description === $exif_usercomment) {
$caption = $exif_description;
} else {
$caption = trim($exif_description . ' ' . $exif_usercomment);
}
$meta['caption'] = $caption;
}
if (empty($meta['caption']) && $exif_usercomment) {
$meta['caption'] = $exif_usercomment;
}
if (empty($meta['caption'])) {
$meta['caption'] = $exif_description;
}
} elseif (empty($meta['caption']) && $exif_usercomment) {
$meta['caption'] = $exif_usercomment;
$description_length = strlen($exif_usercomment);
if (empty($meta['title']) && $description_length < 80) {
$meta['title'] = trim($exif_usercomment);
}
} elseif (empty($meta['caption']) && !empty($exif['Comments'])) {
$meta['caption'] = trim($exif['Comments']);
}
if (empty($meta['credit'])) {
if (!empty($exif['Artist'])) {
$meta['credit'] = trim($exif['Artist']);
} elseif (!empty($exif['Author'])) {
$meta['credit'] = trim($exif['Author']);
}
}
if (empty($meta['copyright']) && !empty($exif['Copyright'])) {
$meta['copyright'] = trim($exif['Copyright']);
}
if (!empty($exif['FNumber']) && is_scalar($exif['FNumber'])) {
$meta['aperture'] = round(wp_exif_frac2dec($exif['FNumber']), 2);
}
if (!empty($exif['Model'])) {
$meta['camera'] = trim($exif['Model']);
}
if (empty($meta['created_timestamp']) && !empty($exif['DateTimeDigitized'])) {
$meta['created_timestamp'] = wp_exif_date2ts($exif['DateTimeDigitized']);
}
if (!empty($exif['FocalLength'])) {
$meta['focal_length'] = (string) $exif['FocalLength'];
if (is_scalar($exif['FocalLength'])) {
$meta['focal_length'] = (string) wp_exif_frac2dec($exif['FocalLength']);
}
}
if (!empty($exif['ISOSpeedRatings'])) {
$meta['iso'] = is_array($exif['ISOSpeedRatings']) ? reset($exif['ISOSpeedRatings']) : $exif['ISOSpeedRatings'];
$meta['iso'] = trim($meta['iso']);
}
if (!empty($exif['ExposureTime'])) {
$meta['shutter_speed'] = (string) $exif['ExposureTime'];
if (is_scalar($exif['ExposureTime'])) {
$meta['shutter_speed'] = (string) wp_exif_frac2dec($exif['ExposureTime']);
}
}
if (!empty($exif['Orientation'])) {
$meta['orientation'] = $exif['Orientation'];
}
}
foreach (array('title', 'caption', 'credit', 'copyright', 'camera', 'iso') as $key) {
if ($meta[$key] && !seems_utf8($meta[$key])) {
$meta[$key] = utf8_encode($meta[$key]);
}
}
foreach ($meta['keywords'] as $key => $keyword) {
if (!seems_utf8($keyword)) {
$meta['keywords'][$key] = utf8_encode($keyword);
}
}
$meta = wp_kses_post_deep($meta);
/**
* Filters the array of meta data read from an image's exif data.
*
* @since 2.5.0
* @since 4.4.0 The `$iptc` parameter was added.
* @since 5.0.0 The `$exif` parameter was added.
*
* @param array $meta Image meta data.
* @param string $file Path to image file.
* @param int $image_type Type of image, one of the `IMAGETYPE_XXX` constants.
* @param array $iptc IPTC data.
* @param array $exif EXIF data.
*/
return apply_filters('wp_read_image_metadata', $meta, $file, $image_type, $iptc, $exif);
}