使用PHP imageCreateFromJpeg复制图像并保留其EXIF/IPTC数据?

15

我遇到了一个带有EXIF/IPTC数据的图像问题。
当我使用imageCreateFromJpeg(旋转/裁剪等)时,新存储的文件不会保留EXIF/IPTC数据。

我的当前代码如下:

<?php
// Before executing - EXIF/IPTC data is there (checked)
$image = "/path/to/my/image.jpg";
$source = imagecreatefromjpeg($image);
$rotate = imagerotate($source,90,0);
imageJPEG($rotate,$image);
// After executing  - EXIF/IPTC data doesn't exist anymore. 
?>

我做错了什么吗?

3个回答

9
您没有做错任何事情,但是GD不处理Exif或IPTC数据,因为这超出了GD所做的范围。
您需要使用第三方库或其他PHP扩展来从源图像中读取数据,并将其重新插入到由imagejpeg创建的输出图像中。
以下是一些有用的库:pel(php exif library),php.net上显示如何使用pel以实现您想要的内容的示例,php metadata toolkitiptcembed() function

1
啊...换句话说,我需要复制EXIF/IPTC数据并存储到新图像中? - tftd
3
正确的做法是,在创建图像之前或之后,您都需要从源图像中提取元数据。由于您使用imagejpeg输出最终图像,因此必须在保存图像后将其写入最终图像。 - drew010
1
很遗憾GD没有这个功能,这应该是默认的! - Tomas
3
为什么图书馆需要了解EXIF?仅仅盲目地将特定的字节块复制到新图像中就足够了吗?(我想EXIF是以一个单独的块形式出现的...) - Tomas
2
@Tomas 我也是这么想的。我很惊讶地发现它不会复制它!而且由于 EXIF 无法通过 php 函数嵌入,所以您需要编写自己的类来将标头放入图像中 - 真是浪费时间! - tftd
显示剩余3条评论

9
以下是使用gd进行图像缩放,并且使用PEL复制Exif和ICC颜色配置文件的示例:
function scaleImage($inputPath, $outputPath, $scale) {
    $inputImage = imagecreatefromjpeg($inputPath);
    list($width, $height) = getimagesize($inputPath);
    $outputImage = imagecreatetruecolor($width * $scale, $height * $scale);
    imagecopyresampled($outputImage, $inputImage, 0, 0, 0, 0, $width * $scale, $height * $scale, $width, $height);
    imagejpeg($outputImage, $outputPath, 100);
}

function copyMeta($inputPath, $outputPath) {
    $inputPel = new \lsolesen\pel\PelJpeg($inputPath);
    $outputPel = new \lsolesen\pel\PelJpeg($outputPath);
    if ($exif = $inputPel->getExif()) {
        $outputPel->setExif($exif);
    }
    if ($icc = $inputPel->getIcc()) {
        $outputPel->setIcc($icc);
    }
    $outputPel->saveFile($outputPath);
}

copy('https://istack.dev59.com/p42W6.webp', 'input.jpg');
scaleImage('input.jpg', 'without_icc.jpg', 0.2);
scaleImage('input.jpg', 'with_icc.jpg', 0.2);
copyMeta('input.jpg', 'with_icc.jpg');

输出图像:

没有ICC的输出 复制了ICC的输出

输入图片:

原始图像


PEL库可以在这里找到:https://github.com/pel/pel - jozi

1
@drew010的答案是正确的,没有外部库或其他程序无法完成此任务。但是,那个答案相当古老,现在至少有两种好的方法可以做到这一点。@Thiago Barcala给出了一个答案,使用PEL。
这里是另一种完全不同的方法,使用PERL脚本exiftool by Paul Harvey。我更喜欢这个解决方案,因为exiftool有着更长的发展和使用历史,文档更加详细,对我来说似乎更加稳定可靠。PEL比exiftool新近10年,具有不稳定的API,项目交接历史,尚未达到1.0版本。我尝试设置它,遇到了一些障碍,并且找不到克服它们的文档,而安装exiftool则能开箱即用。
安装exiftool,然后在将旧图像保存到新路径后运行:
exec('exiftool -TagsFromFile /full/path/to/original_image.jpg /full/path/to/newly_saved_image.jpg');

你必须保留这两个文件以便其正常工作;如果您像原始代码一样覆盖了该文件,则EXIF数据将丢失。
确保您的php.ini文件允许调用exec()函数;有时出于安全原因会禁用它。同时,要非常小心,不要在传递给该函数的任何参数中允许用户生成的输入,因为这可能允许攻击者以Web服务器的权限执行任意命令。如果您的脚本根据某些公式(例如仅使用字母数字字符)生成文件名,并具有固定的目录路径,然后将它们传递给exec()函数,则exec()调用最为安全。
如果您不想全局安装exiftool,则可以将exiftool替换为其完整路径。如果您正在使用SELinux,请确保设置exiftool脚本文件的上下文为httpd_exec_t,以允许Web服务器执行它,并确保整个脚本所在的目录具有httpd_sys_content_t或其他允许Web服务器访问的上下文。

1
太棒了!感谢您分享有关2021年如何做事的经验和技巧。不幸的是,我已经在2012年选择了一个答案,最接近的只能是给新答案点赞了... :) - tftd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接