完整的工作示例可在 GitHub 上获取:
read-and-write-xmp-in-psd-ai-files-java

过去的方式很痛苦

想象一下没有人愿意自愿承担的档案清理工作。一个装有 PSD 主文件和 AI 源文件的文件夹在进入 DAM 之前需要添加版权声明和关键字。常规流程是:在 Photoshop 中打开文件,打开“文件信息”,输入版权信息,输入关键字,保存,关闭,下一个文件。每次保存都会重新渲染分层文件,仅仅是为了更改几条 XMP 元数据。让我学到这课的档案是一个未标记的 Illustrator 文件夹,没人能搜索;我们用循环解决了它,而不是靠更多耐心。

把这种常规乘以一个档案库,它就不再是任务,而是项目。更糟的是,它不可审计:没有人事后能证明哪些文件已经处理,而那些被跳过的文件看起来与其他文件完全相同,直到出现许可问题才被发现。面板方式还悄悄地把数据录入与设计工具耦合在一起。谁要修改元数据就必须拥有 Adobe 许可证、一台能舒适打开分层主文件的工作站,以及等待保存重新渲染艺术作品仅为更改字符串的耐心。

手动操作的真实成本:手工修正的元数据是以后没人能验证的元数据;该过程除了疲惫的设计师外不留下任何痕迹。

有更好的方法

GroupDocs.Metadata for Java 直接读取和写入 XMP 包。将 getRootPackage() 强制转换为 IXmp,该包、其方案以及其数组都是普通的 Java 对象,对 PSD 和 AI 容器完全相同,且不需要 Adobe 软件。文档列出了 170 多种格式共用同一 API。

在开始之前,您需要:

  • JDK 8 或更高版本,配合 Maven
  • GroupDocs.Metadata for Java 24.7(获取临时许可证)
  • 用于练习的 PSD 或 AI 文件

将依赖项和 GroupDocs 仓库添加到您的 pom.xml:

mvn dependency:get -Dartifact=com.groupdocs:groupdocs-metadata:24.7

伴随的仓库(https://github.com/groupdocs-metadata/read-and-write-xmp-in-psd-ai-files-java)提供了准备好的 pom.xml,以及两种格式的示例文件,并验证下面的每一步。

新方法:Java 中的四个操作

步骤 1 — 查看文件携带的内容

快照将包和每个方案转储到一个 LinkedHashMap 中,保留文件声明的顺序。

// Snapshot the packet, then sweep for anything the schemes missed
Map<String, String> result = new LinkedHashMap<>();
try (Metadata metadata = new Metadata(adobeFilePath)) {
    IXmp root = (IXmp) metadata.getRootPackage();
    if (root != null && root.getXmpPackage() != null) {
        for (MetadataProperty p : root.getXmpPackage()) {
            put(result, p);
        }
        XmpSchemes schemes = root.getXmpPackage().getSchemes();
        collect(result, schemes.getDublinCore());
        collect(result, schemes.getPhotoshop());
        collect(result, schemes.getXmpBasic());
        collect(result, schemes.getCameraRaw());
    }
    for (MetadataProperty p : metadata.findProperties(new NamedPropertySpec())) {
        if (!result.containsKey(p.getName())) put(result, p);
    }
}
return result;

小的 put 和 collect 辅助方法倾向于使用 getInterpretedValue(),因此日期以可读形式出现,且基于 Specification 的扫描能够捕获供应商包。仓库版本遍历了七个方案;结构保持不变。

步骤 2 — 读取回答问题的字段

许可会查询 dc:rights,搜索会关注 dc:subject。两者都位于 Dublin Core 中,受限读取只涉及九个字段,而不是遍历整棵树。

// dc:* only - the interoperability fields DAM systems agree on
XmpDublinCorePackage dc = root.getXmpPackage().getSchemes().getDublinCore();
if (dc == null) return result;
for (MetadataProperty p : dc) {
    String value = "";
    if (p.getInterpretedValue() != null
            && p.getInterpretedValue().getRawValue() != null) {
        value = String.valueOf(p.getInterpretedValue().getRawValue());
    } else if (p.getValue() != null && p.getValue().getRawValue() != null) {
        value = String.valueOf(p.getValue().getRawValue());
    }
    result.put(p.getName(), value);
}

Photoshop 方案通过类型化的 getter(getCity()、getCredit()、getColorMode() 等共五个)以相同方式工作,覆盖了 Bridge 和 Lightroom 读取的 PSD 元数据字段。仓库中的读取器为每个 getter 包装了空值安全的辅助方法,因此稀疏的文件会返回空字符串而不是异常。这个细节比看起来更重要:自动化档案的核心在于让异常文件顺畅通过,而不是让循环卡住。

两个受限读取共享一个值得命名的成本特征:一次文件打开、一次方案读取、无需遍历树。将它们放入请求处理器和网关中;对需要存储全部信息的摄取作业保存完整快照。

步骤 3 — 在不打开 Adobe 的情况下进行标记和标签

写入器会防护式地创建任何缺失的对象,这使得它们对完全没有包的全新导出也安全。

// Create missing layers, then write rights, creator, and CreatorTool
if (root.getXmpPackage() == null) {
    root.setXmpPackage(new XmpPacketWrapper());
}
if (root.getXmpPackage().getSchemes().getDublinCore() == null) {
    root.getXmpPackage().getSchemes().setDublinCore(new XmpDublinCorePackage());
}
XmpDublinCorePackage dc = root.getXmpPackage().getSchemes().getDublinCore();
dc.setRights(copyright);
dc.set("dc:creator", XmpArray.from(new String[]{creator}, XmpArrayType.Ordered));

if (root.getXmpPackage().getSchemes().getXmpBasic() == null) {
    root.getXmpPackage().getSchemes().setXmpBasic(new XmpBasicPackage());
}
root.getXmpPackage().getSchemes().getXmpBasic().setCreatorTool(creator);

metadata.save(outputPath);

关键字遵循相同模式,只需一次调用,将整个 bag 写入为无序数组:

// Replace the dc:subject bag - merge in Java first for additive tagging
root.getXmpPackage().getSchemes().getDublinCore().set(
        "dc:subject", XmpArray.from(keywords, XmpArrayType.Unordered));
metadata.save(outputPath);

Main.java 完成了闭环:它重新读取输出并断言版权字符串以及第一个关键字确实在保存后仍然存在。

这个闭环断言值得一段倡导的话。元数据写入在失败时会悄悄失败;文件会保存,字节会改变,而您本意写入的值可能因为方案对象已过期或路径指向原始对象而根本不存在。每次写入后进行读取回执会为每个文件额外增加一次打开,但它把“脚本执行完毕”转变为“值已存在”,这正是档案所有者真正想要的。请在生产环境中保留此做法,而不仅仅在演示中使用。

关键字到底如何让资产可检索?

搜索工具不读取像素,它们读取 dc:subject。Bridge、DAM 索引器以及素材平台将该 bag 视为资产的词汇表,因此没有关键字的文件根本不会匹配任何查询。将 bag 写入为无序的 XmpArray(AddKeywords 的做法),就是把资产从不可见变为可检索的方式,而写入只需一次保存。

对比:之前 vs. 之后

之前(面板编辑) 之后(Java 流程)
工具 每个文件使用 Photoshop 或 Bridge 一个 Maven 项目,无需 Adobe 许可证
覆盖范围 面板公开的字段 所有方案以及供应商数据包
可重复性 取决于谁点击 相同循环、相同结果、可审计
无 XMP 文件 面板行为各异 守护创建数据包和方案
验证 信任 每个文件的断言读取回执

验证行决定了档案的走向:能够自行证明写入结果的脚本,就是“我们已经标记了文件”和“我们可以向您展示”的区别。

实际案例:机构交接

一家工作室收到来自三家机构的混合 PSD 与 AI 交付,每家都有自己的元数据规范。现在,他们的摄取作业在文件到达时运行快照,标记 dc:rights 读取为空的文件,用合同约定的版权行进行盖章,并写入活动关键字集合。相同的循环同时适用于两种格式,因为代码中没有任何容器名称,而 Adobe Illustrator 的空白元数据也会在摄取时被标记并可搜索。

后续影响是工作室未曾预料到的:机构评分卡。由于摄取作业记录了哪些交付的版权字段为空,采购部门现在可以看到哪些供应商提供了干净的元数据,哪些依赖客户来修复。与表现最差的供应商的对话只用了一个图表。

GroupDocs.Metadata 还能做什么?

  • EXIF and IPTC in the same files:PSDs 包含三种元数据标准;同一库通过各自的包读取另外两种,因此完整的资产概况只需再读取两次。
  • 170+ other formats:相同的 Metadata 入口点服务于 Office、PDF、音频和视频文件,这也是一个摄取作业能够覆盖整个混合档案库的原因。
  • Property search:使用 findProperties 搭配 Specification 可以对任何文件进行任意谓词的扫描,从版权检查到自定义字段搜索皆可实现。

结论

过去的每文件面板例程现在变成了四个 Java 操作:快照、受限读取、所有权盖章、关键字写入。相同的代码同时服务于 PSD 与 AI 文件,守护使空导出安全,并且通过断言的示例项目在真正投入档案之前验证了全部流程。

准备好淘汰文件信息面板了吗?

其他资源