Полный рабочий пример доступен на GitHub:
read-and-write-xmp-in-psd-ai-files-java
Старый способ был болезненным
Представьте себе очистку архива, к которой никто не желает прибегать. Папка с мастер‑файлами PSD и исходниками AI нуждается в уведомлениях о правах и ключевых словах, прежде чем попасть в DAM. Обычная процедура: открыть файл в Photoshop, открыть «File Info», ввести копирайт, ввести ключевые слова, сохранить, закрыть, перейти к следующему файлу. Каждый сохранение повторно рендерит слоистый файл только для изменения нескольких строк XMP‑метаданных. Архив, который преподал мне этот урок, был папкой с неразмеченными файлами Illustrator, которые никто не мог найти; мы исправили это с помощью цикла, а не терпения.
Умножьте эту рутину на архив, и она перестаёт быть задачей и становится проектом. Хуже того, процесс не поддаётся аудиту: никто не может позже доказать, какие файлы были обработаны, а те, что пропущены, выглядят одинаково, пока вопрос лицензирования не выявит их. Путь через панель также тихо связывает ввод данных с инструментами дизайна. Тот, кто исправляет метаданные, нужен Adobe‑аккаунт, рабочая станция, способная комфортно открывать слоистые мастера, и терпение ждать сохранений, которые повторно рендерят графику лишь для изменения строк.
Настоящая стоимость ручного выполнения: метаданные, исправленные вручную, — это метаданные, которые никто не может позже проверить; процесс не оставляет следов, кроме уставших дизайнеров.
Есть лучший способ
GroupDocs.Metadata для Java читает и записывает пакет XMP напрямую. Приведите getRootPackage() к IXmp, и пакет, его схемы и массивы становятся обычными объектами Java, одинаковыми для контейнеров PSD и AI, без участия программного обеспечения Adobe. Документация перечисляет более 170 форматов, доступных через один и тот же API.
Прежде чем начать, вам понадобится:
- JDK 8 или новее с Maven
- GroupDocs.Metadata для Java 24.7 (получить временную лицензию)
- Файл PSD или AI для практики
Добавьте зависимость и репозиторий GroupDocs в ваш pom.xml:
mvn dependency:get -Dartifact=com.groupdocs:groupdocs-metadata:24.7
Сопутствующий репозиторий поставляется с готовым 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, и scoped‑чтение затрагивает девять полей, а не обход дерева.
// 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 работает аналогично через типизированные геттеры (getCity(), getCredit(), getColorMode() и ещё пять), покрывая поля метаданных PSD, которые читают фильтры Bridge и Lightroom. В репозитории каждый геттер обёрнут в null‑безопасный помощник, поэтому файл с редкими данными возвращает пустые строки вместо неожиданностей. Эта деталь важнее, чем кажется: вся идея автоматизации архива в том, что «странные» файлы проходят сквозь процесс, а не останавливают цикл.
Оба scoped‑чтения имеют одинаковый профиль затрат, который стоит назвать. Одно открытие файла, одна схема, без обхода дерева. Поместите их в обработчики запросов и шлюзы; сохраняйте полный снимок для задач загрузки, которые хранят всё.
Шаг 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);
Ключевые слова следуют той же схеме одним вызовом, записывая весь набор как неупорядоченный массив:
// 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 и стоковые платформы рассматривают этот набор как словарь ресурса, поэтому файл без ключевых слов просто никогда не совпадает с запросом. Запись набора как неупорядоченного XmpArray, как делает AddKeywords, переводит ресурс из невидимого в находящийся, а запись требует одного сохранения.
Сравнение: до и после
| До (редактирование через панель) | После (Java‑конвейер) | |
|---|---|---|
| Инструменты | Photoshop или Bridge для каждого файла | Один Maven‑проект, без Adobe‑аккаунта |
| Охват | Поля, которые показывает панель | Все схемы плюс пакеты поставщиков |
| Повторяемость | Зависит от того, кто нажимал | Один и тот же цикл, один результат, аудируемо |
| Файлы без XMP | Поведение панели различается | Защищённые функции создают пакет и схемы |
| Проверка | Доверие | Проверка чтения обратно для каждого файла |
Строка проверки решает всё для архивов: скрипт, который доказывает свои записи, отличает «мы пометили файлы» от «мы можем вам это показать».
Пример из реального мира: передача агентства
Студия получает смешанные поставки PSD и AI от трёх агентств, каждое со своей дисциплиной метаданных. Их задача по приёму теперь запускает снимок при поступлении, помечает файлы, у которых dc:rights пуст, ставит строку прав согласно контракту и записывает набор ключевых слов кампании. Один и тот же цикл обслуживает оба формата, потому что в коде нет упоминаний о контейнере, а метаданные Adobe Illustrator, пришедшие пустыми, оставляют приём помеченным и доступным для поиска.
Последующий эффект — то, чего студия не предвидела: оценочные карточки агентств. Поскольку задача по приёму логирует, какие поставки пришли с пустыми полями прав, закупки теперь видят, какие поставщики поставляют чистые метаданные, а какие полагаются на клиента для их исправления. Разговор с самым проблемным поставщиком занял один график.
Что ещё можно сделать с GroupDocs.Metadata?
- EXIF и IPTC в тех же файлах: PSD‑файлы содержат три стандарта метаданных; та же библиотека читает остальные два через их собственные пакеты, так что полный профиль ресурса находится в двух чтениях дальше.
- 170+ других форматов: одинаковая точка входа
Metadataобслуживает Office, PDF, аудио и видео файлы, что позволяет одной задаче по приёму охватить весь смешанный архив. - Поиск по свойствам:
findPropertiesсSpecificationпросеивает любой файл по произвольному предикату, от проверок прав до поиска пользовательских полей.
Заключение
То, что раньше было рутиной по‑файловому панельному интерфейсу, теперь превратилось в четыре операции Java: снимок, scoped‑чтение, штамп владения, запись ключевых слов. Один и тот же код обслуживает PSD и AI, защитные функции делают пустые экспорты безопасными, а проверенный пример проекта доказывает всю цепочку перед тем, как вы направите её на реальный архив.
Готовы избавиться от панели «File Info»?
- Соберите пример проекта с помощью
mvn compile exec:java - Пройдите руководство по использованию в стиле сравнения
- Ознакомьтесь с справочником Работа с XMP‑метаданными