iptcembed

(PHP 4, PHP 5, PHP 7, PHP 8)

iptcembed将二进制 IPTC 数据嵌入 JPEG 图像中

描述

iptcembed(string $iptc_data, string $filename, int $spool = 0): string|bool

将二进制 IPTC 数据嵌入 JPEG 图像中。

参数

iptc_data

要写入的数据。

filename

JPEG 图像的路径。

spool

存储标志。如果存储标志小于 2,则 JPEG 将作为字符串返回。否则,JPEG 将打印到 STDOUT。

返回值

如果 spool 小于 2,则将返回 JPEG,或在失败时返回 false。否则,在成功时返回 true,在失败时返回 false

示例

示例 #1 将 IPTC 数据嵌入 JPEG 中

<?php

// iptc_make_tag() 函数由 Thies C. Arntzen 提供
function iptc_make_tag($rec, $data, $value)
{
$length = strlen($value);
$retval = chr(0x1C) . chr($rec) . chr($data);

if(
$length < 0x8000)
{
$retval .= chr($length >> 8) . chr($length & 0xFF);
}
else
{
$retval .= chr(0x80) .
chr(0x04) .
chr(($length >> 24) & 0xFF) .
chr(($length >> 16) & 0xFF) .
chr(($length >> 8) & 0xFF) .
chr($length & 0xFF);
}

return
$retval . $value;
}

// JPEG 文件路径
$path = './phplogo.jpg';

// 设置 IPTC 标签
$iptc = array(
'2#120' => '测试图像',
'2#116' => '版权所有 2008-2009,PHP 小组'
);

// 将 IPTC 标签转换为二进制代码
$data = '';

foreach(
$iptc as $tag => $string)
{
$tag = substr($tag, 2);
$data .= iptc_make_tag(2, $tag, $string);
}

// 嵌入 IPTC 数据
$content = iptcembed($data, $path);

// 将新的图像数据写入文件。
$fp = fopen($path, "wb");
fwrite($fp, $content);
fclose($fp);
?>

注释

注意:

此函数不需要 GD 图像库。

添加注释

用户贡献的注释 17 个注释

13
ebashkoff at gmail dot com
10 年前
以下代码从源文件嵌入 IPTC APP 段 13 和 EXIF APP 段 1 数据,并将其嵌入到目标文件中。这克服了 iptcembed 语句似乎只嵌入 IPTC 数据而不是 EXIF 数据的限制。

function transferIptcExif2File($srcfile, $destfile) {
// 此函数从 $srcfile 传输 EXIF (APP1) 和 IPTC (APP13),并将其添加到 $destfile
// JPEG 文件格式为 0xFFD8 + [APP0] + [APP1] + ... [APP15] + <图像数据>,其中 [APPi] 是可选的
// 段 APPi (其中 i=0x0 到 0xF) 格式为 0xFFEi + 0xMM + 0xLL + <数据> (其中 0xMM 是
// (strlen(<数据>) + 2) 的最高有效 8 位,而 0xLL 是 (strlen(<数据>) + 2) 的最低有效 8 位
//)。

if (file_exists($srcfile) && file_exists($destfile)) {
$srcsize = @getimagesize($srcfile, $imageinfo);
// 从源文件准备 EXIF 数据字节
$exifdata = (is_array($imageinfo) && key_exists("APP1", $imageinfo)) ? $imageinfo['APP1'] : null;
if ($exifdata) {
$exiflength = strlen($exifdata) + 2;
if ($exiflength > 0xFFFF) return false;
// 构造 EXIF 段
$exifdata = chr(0xFF) . chr(0xE1) . chr(($exiflength >> 8) & 0xFF) . chr($exiflength & 0xFF) . $exifdata;
}
// 从源文件准备 IPTC 数据字节
$iptcdata = (is_array($imageinfo) && key_exists("APP13", $imageinfo)) ? $imageinfo['APP13'] : null;
if ($iptcdata) {
$iptclength = strlen($iptcdata) + 2;
if ($iptclength > 0xFFFF) return false;
// 构造 IPTC 段
$iptcdata = chr(0xFF) . chr(0xED) . chr(($iptclength >> 8) & 0xFF) . chr($iptclength & 0xFF) . $iptcdata;
}
$destfilecontent = @file_get_contents($destfile);
if (!$destfilecontent) return false;
if (strlen($destfilecontent) > 0) {
$destfilecontent = substr($destfilecontent, 2);
$portiontoadd = chr(0xFF) . chr(0xD8); // 变量累积新的和原始的 IPTC 应用程序段
$exifadded = !$exifdata;
$iptcadded = !$iptcdata;

while ((substr($destfilecontent, 0, 2) & 0xFFF0) === 0xFFE0) {
$segmentlen = (substr($destfilecontent, 2, 2) & 0xFFFF);
$iptcsegmentnumber = (substr($destfilecontent, 1, 1) & 0x0F); // 第二个字节的最后 4 位是 IPTC 段号
if ($segmentlen <= 2) return false;
$thisexistingsegment = substr($destfilecontent, 0, $segmentlen + 2);
if ((1 <= $iptcsegmentnumber) && (!$exifadded)) {
$portiontoadd .= $exifdata;
$exifadded = true;
if (1 === $iptcsegmentnumber) $thisexistingsegment = '';
}
如果 ((13 <= $iptcsegmentnumber) && (!$iptcadded)) {
$portiontoadd .= $iptcdata;
$iptcadded = true;
如果 (13 === $iptcsegmentnumber) $thisexistingsegment = '';
}
$portiontoadd .= $thisexistingsegment;
$destfilecontent = substr($destfilecontent, $segmentlen + 2);
}
如果 (!$exifadded) $portiontoadd .= $exifdata; // 如果 EXIF 数据尚未添加,则添加 EXIF 数据
如果 (!$iptcadded) $portiontoadd .= $iptcdata; // 如果 IPTC 数据尚未添加,则添加 IPTC 数据
$outputfile = fopen($destfile, 'w');
如果 ($outputfile) 返回 fwrite($outputfile, $portiontoadd . $destfilecontent); 否则返回 false;
} 否则 {
返回 false;
}
} 否则 {
返回 false;
}
}
10
support at image-host-script dot com
15 年前
我最近编写了一个用于操作 JPEG 图像中的 IPTC 数据的类。它可以轻松地编辑现有数据。它只是将示例汇集到一个类中。

<?

/************************************************************\

IPTC EASY 1.0 - JPEG 图像的 IPTC 数据操作器

版权所有 www.image-host-script.com

2008 年 9 月 15 日

\************************************************************/

DEFINE('IPTC_OBJECT_NAME', '005');
DEFINE('IPTC_EDIT_STATUS', '007');
DEFINE('IPTC_PRIORITY', '010');
DEFINE('IPTC_CATEGORY', '015');
DEFINE('IPTC_SUPPLEMENTAL_CATEGORY', '020');
DEFINE('IPTC_FIXTURE_IDENTIFIER', '022');
DEFINE('IPTC_KEYWORDS', '025');
DEFINE('IPTC_RELEASE_DATE', '030');
DEFINE('IPTC_RELEASE_TIME', '035');
DEFINE('IPTC_SPECIAL_INSTRUCTIONS', '040');
DEFINE('IPTC_REFERENCE_SERVICE', '045');
DEFINE('IPTC_REFERENCE_DATE', '047');
DEFINE('IPTC_REFERENCE_NUMBER', '050');
DEFINE('IPTC_CREATED_DATE', '055');
DEFINE('IPTC_CREATED_TIME', '060');
DEFINE('IPTC_ORIGINATING_PROGRAM', '065');
DEFINE('IPTC_PROGRAM_VERSION', '070');
DEFINE('IPTC_OBJECT_CYCLE', '075');
DEFINE('IPTC_BYLINE', '080');
DEFINE('IPTC_BYLINE_TITLE', '085');
DEFINE('IPTC_CITY', '090');
DEFINE('IPTC_PROVINCE_STATE', '095');
DEFINE('IPTC_COUNTRY_CODE', '100');
DEFINE('IPTC_COUNTRY', '101');
DEFINE('IPTC_ORIGINAL_TRANSMISSION_REFERENCE', '103');
DEFINE('IPTC_HEADLINE', '105');
DEFINE('IPTC_CREDIT', '110');
DEFINE('IPTC_SOURCE', '115');
DEFINE('IPTC_COPYRIGHT_STRING', '116');
DEFINE('IPTC_CAPTION', '120');
DEFINE('IPTC_LOCAL_CAPTION', '121');

类 iptc {
var $meta=Array();
var $hasmeta=false;
var $file=false;


函数 iptc($filename) {
$size = getimagesize($filename,$info);
$this->hasmeta = isset($info["APP13"]);
如果($this->hasmeta)
$this->meta = iptcparse ($info["APP13"]);
$this->file = $filename;
}
函数 set($tag, $data) {
$this->meta ["2#$tag"]= Array( $data );
$this->hasmeta=true;
}
函数 get($tag) {
返回 isset($this->meta["2#$tag"]) ? $this->meta["2#$tag"][0] : false;
}

函数 dump() {
print_r($this->meta);
}
函数 binary() {
$iptc_new = '';
foreach (array_keys($this->meta) as $s) {
$tag = str_replace("2#", "", $s);
$iptc_new .= $this->iptc_maketag(2, $tag, $this->meta[$s][0]);
}
返回 $iptc_new;
}
函数 iptc_maketag($rec,$dat,$val) {
$len = strlen($val);
如果 ($len < 0x8000) {
返回 chr(0x1c).chr($rec).chr($dat).
chr($len >> 8).
chr($len & 0xff).
$val;
} 否则 {
返回 chr(0x1c).chr($rec).chr($dat).
chr(0x80).chr(0x04).
chr(($len >> 24) & 0xff).
chr(($len >> 16) & 0xff).
chr(($len >> 8 ) & 0xff).
chr(($len ) & 0xff).
$val;

}
}
函数 write() {
如果(!function_exists('iptcembed')) 返回 false;
$mode = 0;
$content = iptcembed($this->binary(), $this->file, $mode);
$filename = $this->file;

@unlink($filename); # 如果存在则删除

$fp = fopen($filename, "w");
fwrite($fp, $content);
fclose($fp);
}

# 需要安装 GD 库
函数 removeAllTags() {
$this->hasmeta=false;
$this->meta=Array();
$img = imagecreatefromstring(implode(file($this->file)));
@unlink($this->file); # 如果存在则删除
imagejpeg($img,$this->file,100);
}
};


?>

示例读取版权字符串

$i = new iptc("test.jpg");
echo $i->get(IPTC_COPYRIGHT_STRING);

更新版权声明
$i = new iptc("test.jpg");
echo $i->set(IPTC_COPYRIGHT_STRING,"这里输入新的数据");
$i->write();

注意 1:数据可以是任何内容,甚至可以是二进制文件。到目前为止,我已经测试并将 MS-Excel 文件直接嵌入到 jpeg 中,并且它运行良好。

注意 2:写入目的,它使用 GD 库。

更多改进/更改请访问 www.image-host-script.com

希望它能有所帮助。
Ali..
4
critto at o2 dot pl
14 年前
如果你只想复制 IPTC 数据,例如在创建缩略图时,你不必将二进制 IPTC 数据解析成数组然后再转换回来;只需执行以下操作

<?php
$fullFilePath
='photo1.jpg';
$fullPathThumb = 'photo1thumb.jpg';
$imagesize = getImageSize($fullFilePath, $info);
如果(isset(
$info['APP13'])){
$content = iptcembed($info['APP13'], $fullPathThumb);
@
unlink($fullPathThumb);
$fw = fopen($fullPathThumb, 'w');
fwrite($fw, $content);
fclose($fw);
}
?>
2
evan at nospam dot ozhiker dot com
20 年前
你可能已经注意到,Photoshop 中的几个元数据字段无法通过 IPTC 获得。
此外,Photoshop 现在使用 XMP 作为其主要元数据,这意味着只有在不存在 XMP 的情况下,Photoshop 才会读取 IPTC。

我编写了一个库“PHP JPEG 元数据工具包”,它绕过了这个问题,因为它允许读取、写入和解释几乎所有类型的元数据,包括 XMP、IPTC 和 EXIF。

试试看,并从以下地址下载:
http://www.ozhiker.com/electronics/pjmt/index.html
2
Christoph Tavan
13 年前
对于所有在 IPTC 字段中遇到 Unicode(UTF-8)文本问题的人,请在信封中设置“编码字符集”字段(1:90,请参见 http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf)。

这可以通过用以下行开始 $data 块来实现

<?php
// 这两行确保 UTF8 编码将起作用(设置信封中的 1:90 字段)
// @see http://cpanforum.com/threads/2114 获取提示
$utf8seq = chr(0x1b) . chr(0x25) . chr(0x47);
$length = strlen($utf8seq);
$data = chr(0x1C) . chr(1) . chr('090') . chr($length >> 8) . chr($length & 0xFF) . $utf8seq;
?>

之后,你可以像示例中一样继续

<?php
foreach($iptc as $tag => $string)
{
$tag = substr($tag, 2);
$data .= iptc_make_tag(2, $tag, $string);
}
?>
2
rupix at rediffmail dot com
22 年前
Windows 区分“文本”文件和“二进制”文件。因此,如果你在 Windows 平台上运行上述代码,它将生成一个乱码图像。要解决此问题,请在 fopen() 中将文件模式设置为“wb”而不是“w”。

欢呼!!

Rupinder
1
soporte at etic dot com dot mx
13 年前
我在尝试使用 binary 函数写入多个关键字(一个数组)时发现了一个错误... 请考虑使用以下内容

<?php
function binary() {
$iptc_new = '';
foreach (
array_keys($this->meta) as $s) {
$tag = str_replace("2#", "", $s);
如果(
count($this->meta[$s])>1){
foreach (
$this->meta[$s] as $row){
$iptc_new .= $this->iptc_maketag(2, $tag, $row);
}
}否则 {
$iptc_new .= $this->iptc_maketag(2, $tag, $this->meta[$s][0]);
}
}
返回
$iptc_new;
}
?>
1
dj dot cyberdance at gmx dot at
20 年前
我花了一整天时间调试我的代码(它基于 knut 发布的以下示例),直到我发现,iptcembed() 仅在 jpeg_file_name 中指定的图像中包含 IPTC 字段时才有效。

这意味着您无法在没有预先存在的 IPTC 信息的 jpeg 文件中写入 IPTC 字段。

IPTC 字段的更新也只对少数文件有效,我不太清楚它是否有效取决于什么。(当然,这取决于 IPTC 头部 :-)

我使用的是 PHP 4.2.1,也许在更新的版本中已经修复了这个问题,但我认为...

尽管如此,这里是我尝试过的一些代码片段

我替换了以下行

<?
$iptc_old = iptcparse ($info["APP13"]);
?>

来自以下 knut 的示例

<?
$iptc_old["2#000"][0] = chr(0) . chr(2);
?>

这根据 IPTC 规范只创建一个空的“头部”。使用 iptcparse() 获取 IPTC 信息时,也会包含它。所以我的目的是创建一个全新的头部,但是之后使用 iptcembed() 时,新文件的尺寸比原始文件小了一点,但是没有存储任何 IPTC 信息。
1
pprem at pprem dot net
20 年前
我在 ltrim 函数方面遇到了问题:有时它删除的字符比应删除的更多,因此最好删除以下行

<?
// $image = rtrim ($image, $endchar);
?>

在 XMP_remove_from_jpeg 函数中
0
micheall at inthemdl dot net
13 年前
在使用下面提到的类文件时,您会注意到使用 set() 函数设置一组关键词将无法正常工作。请尝试以下方法
<?php
function set($tag, $data) {
if(
is_array($data)){
$c = count($data);
for (
$i=0; $i <$c; $i++){
$this->meta["2#$tag"][$i] = $data[$i];
}
$this->hasmeta=true;
} else {
$this->meta["2#$tag"]= Array( $data );
$this->hasmeta=true;
}
}
?>
0
jb at ibbeck dot de
16 年前
如果您有一个没有 IPTC 记录的文件,可以通过使用空字符串作为第一个参数调用 iptcembed 来添加一个新的空记录,例如

$buffer = iptcembed("",$imagename,0);
$fp = fopen($imagename,"w");
fwrite($fp,$buffer);
fclose($fp);
0
Bryce Fisher
17 年前
在下面 Thomas 提供的精彩代码片段中,第二个参数需要更改为 "$filename",否则脚本无法写入文件。所以代码应该写成

<?php
// 此函数会从 JPG 中删除所有头部数据
function remove_XMP($image_in, $filename) {
$filename_in = addslashes($image_in);
list(
$width, $height) = getimagesize($filename_in);
$image_dest = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($filename_in);
imagecopyresampled($image_dest, $image, 0, 0, 0, 0, $width, $height,$width, $height);
imagejpeg($image_dest, $filename);
}
?>
0
muguran
19 年前
注意不要添加值为 0 的代码;其行为可能会很奇怪...
(例如 $iptc_old["2#015"][0] = "")
-2
dj dot cyberdance at gmx dot at
20 年前
又是我 :-) 花了一些时间在其他地方搜索写入 JPEG 文件的 IPTC 字段的其他可能性后,我找到了这个

http://www.zonageek.com/software/php/jpeg/index.php

这个看起来运行得很好,请记住您需要安装 PEAR 才能运行它(Debian 包 php4-pear)。
-2
pprem at pprem dot net
20 年前
使用 PEAR 函数读取和更改 IPTC 不会出现问题,但最近的 Adobe 软件会在 JPEG 文件中添加 XMP 数据并读取它们,而不是 IPTC 数据。如果您需要更改 JPEG 文件中的 IPTC,并且希望 Adobe PS7 读取它们,那么您有两种解决方案
- 同时写入 XMP 和 IPTC 数据
- 写入 IPTC 数据并删除 XMP 数据

由于我没有足够的时间处理 XMP 数据,所以我选择了第二种解决方案。以下是我工作的成果

<?php
// 从 JPEG 文件中删除 XMP 数据
// (c) Patrick Premartin 19/02/2004

function XMP_remove_from_jpeg (&$image) {
$xmp_str = "http://ns.adobe.com/xap/1.0/";
$xmp_end = "<?xpacket end='w'?>";
$n_str = strpos ($image, $xmp_str);
$n_end = strpos ($image, $xmp_end);
if ((
$n_str !== false) && ($n_end !== false) && ($n_str < $n_end)) {
$n_str -= 4; // FF E1 .x. .y. (xy 是 XMP 块的长度 -> 该块的第一个字符
$n_end += strlen ($xmp_end)-1; // 该块的最后一个字符
$endchar = $image [$n_str-1];
if (
$endchar == " ") {
$endchar = "A";
} else {
$endchar = " ";
}
$xmp_len = $n_end-$n_str+1;
$img_len = strlen ($image);
$len = $img_len - $xmp_len;
for (
$i = $n_str; $i < $img_len; $i ++) {
if (
$i < $len) {
$image [$i] = $image [$i+$xmp_len];
} else {
$image [$i] = $endchar;
}
}
$image = rtrim ($image, $endchar);
return
true;
} else {
return
false;
}
}

function
XMP_remove_from_jpegfile ($filename_in, $filename_out="") {
if (
""==$filename_out) {
$filename_out = $filename_in;
}
if ((
""!=$filename_in) && (file_exists ($filename_in)) && (($len_in = filesize ($filename_in)) > 0)) {
// 将文件加载到内存中
$f_in = fopen ($filename_in, "rb");
$img = fread ($f_in, $len_in);
fclose ($f_in);
// 从图片中删除 XMP
if (XMP_remove_from_jpeg ($img)) {
// 将文件保存到磁盘
$f_out = fopen ($filename_out, "wb");
fwrite ($f_out, $img, strlen ($img));
fclose ($f_out);
}
}
}

XMP_remove_from_jpegfile ("ps7_hr.jpg", "ps7_hr_.jpg"); // 创建一个没有 XMP 数据的新图片

XMP_remove_from_jpegfile ("ps8_hr.jpg"); // 替换现有文件
?>

将来,我将以相同的方式更改 XMP 数据和 IPTC,并将它发布在 PEAR 中或作为 PEAR 中的一个包。

愿力量与我们同在 :-)
-2
knut dot satre dot NoSpam at No_Spam dot nord dot no
22 年前
从图像中读取 IPTC 文本的示例,使用 iptcparse 和 iptcembed 函数更改文本并写入新文件。

还列出了最常见的 IPTC 字段。

<?
// 原始文件名
$image_name_old = "test.jpg";

// 新文件名
$image_name_new = "test2.jpg";

// 将 IPTC 文本读入数组 '$iptc' 中
// '#' 后面的数字是 IPTC 字段
// 例如:$iptc["2#120"][0] 是标题
// $iptc["2#055"][0]; 是创建时间
$size = GetImageSize ("$image_name_old",&$info);
$iptc_old = iptcparse ($info["APP13"]);

// 添加或替换 IPTC 文本
// 此示例替换原始类别,如果类别不存在则创建它
$iptc_old["2#015"][0] = "Sport";
// .. 并在原始标题中添加更多文本
$iptc_old["2#120"][0] .= " More caption text";

// 创建新的 IPTC 字符串
foreach (array_keys($iptc_old) as $s){
// 查找 IPTC 数字
$tag = str_replace("2#", "", $s);
// 创建字符串
$iptc_new .= iptc_maketag(2, $tag, $iptc_old[$s][0]);
}

// 将原始文件和新的 IPTC 文本放入 $content 中
// 模式 0 - 将图像文件放入 $content 中
// 模式 1 - 将图像文件放入 $content 中并直接发送到 Web 客户端
// 模式 2 - 将图像文件发送到 Web 客户端
$mode = 0;
$content = iptcembed($iptc_new, $image_name_old, $mode);

// 编写新文件
$fp = fopen($image_name_new, "w");
fwrite($fp, $content);
fclose($fp);

// 格式化新 IPTC 文本的函数(感谢 Thies C. Arntzen)
function iptc_maketag($rec,$dat,$val){
$len = strlen($val);
if ($len < 0x8000)
返回 chr(0x1c).chr($rec).chr($dat).
chr($len >> 8).
chr($len & 0xff).
$val;
else
返回 chr(0x1c).chr($rec).chr($dat).
chr(0x80).chr(0x04).
chr(($len >> 24) & 0xff).
chr(($len >> 16) & 0xff).
chr(($len >> 8 ) & 0xff).
chr(($len ) & 0xff).
$val;
}

?>

--- 最常见的 IPTC 字段
005 - 对象名称
007 - 编辑状态
010 - 优先级
015 - 类别
020 - 补充类别
022 - 固定装置标识符
025 - 关键字
030 - 发布日期
035 - 发布时间
040 - 特殊说明
045 - 参考服务
047 - 参考日期
050 - 参考号码
055 - 创建时间
060 - 创建时间
065 - 来源程序
070 - 程序版本
075 - 对象循环
080 - 作者
085 - 作者头衔
090 - 城市
095 - 省份/州
100 - 国家代码
101 - 国家
103 - 原始传输参考
105 - 标题
110 - 署名
115 - 来源
116 - 版权字符串
120 - 标题
121 - 本地标题
-4
Jarek Milewski
13 年前
要从 jpeg 文件中删除所有 EXIF、XMP 等标签,您不需要重新采样(顺便说一句,这可能会导致内存问题)。只需重新创建图像即可,最好使用 100% 的质量,以确保不丢失任何内容。代码很简单

<?php
$img
= imagecreatefromjpeg ($path);
imagejpeg ($img, $path, 100);
imagedestroy ($img);
?>
To Top