Полный рабочий пример доступен на GitHub:
edit-xmp-in-psd-and-ai-files-using-groupdocs-metadata-dotnet

Производственная задача: метаданные, где никто не смотрит

Бренд‑студия выпускает кампанию: многослойные PSD‑мастера, исходные файлы AI, сотни активов, загруженных в DAM клиента. Три недели спустя отдел лицензирования спрашивает, кому принадлежит главное изображение. Ответ существует, но он спрятан в цепочке электронных писем, потому что в самом файле поле dc:rights пустое. Редактирование XMP — возможность GroupDocs.Metadata для .NET, которая решает такие проблемы на уровне конвейера, читая и записывая пакет XMP‑метаданных внутри файлов PSD и AI без какого‑либо программного обеспечения Adobe.

Проблема масштабирования появляется тихо. Один дизайнер может вручную заполнять панели метаданных, но только ограниченное время. Команда производства, обрабатывающая тысячи активов в квартал, не может этого делать, и каждый переход между агентством, студией и клиентом умножает количество файлов, чьи PSD‑метаданные никто не проверял. Поиск перестаёт находить существующие активы. Вопросы о правах превращаются в археологию, а у археологии нет SLA.

То, что действительно нужно этим командам, выглядит как спецификация API: зафиксировать всё, что файл несёт при загрузке, проверить конкретные поля на этапах лицензирования и записать владельца и ключевые слова при экспорте, используя одинаковый код для обоих форматов Adobe.

Проверка реальности: актив с пустым полем dc:rights не является нелицензированным, но никто ниже по цепочке не может доказать обратное без поиска человека, который помнит.

Почему обычные решения не работают

Команды обычно пробуют три подхода, прежде чем автоматизировать процесс:

  • Ручное редактирование панелей в Photoshop или Bridge: работает для отдельного файла, не поддаётся аудиту и требует лицензии Adobe для задачи, по сути являющейся вводом данных.
  • Внешние таблицы: метаданные существуют, но отделяются от актива в момент копирования, переименования или повторной доставки файла.
  • Собственный парсер: блоки ресурсов PSD и контейнеры AI — сложные форматы, а собственный парсер становится обязательством по обслуживанию, как только Adobe вносит изменения.

GroupDocs.Metadata закрывает этот разрыв одним API: приводите корневой пакет к IXmp, и пакет становится читаемым и записываемым для обоих форматов, наряду с более чем 170 другими, перечисленными в документации.

Решение: операции XMP внутри конвейера

GroupDocs.Metadata для .NET внедряется в конвейер активов в трёх точках. При загрузке он фиксирует весь пакет в словарь, который индексирует ваша база данных. На этапе лицензирования он читает Dublin Core, схему, где находятся dc:rights и dc:creator. При экспорте он записывает владельца и ключевые слова dc:subject, создавая недостающие схемы в файлах, которые вообще не содержат XMP. Я участвовал в слишком многих ретроспективах запусков, где коренной причиной был актив без данных о правах; наличие шлюза оправдано тем, что ретроспективы обходятся дороже, чем простое чтение.

Для реализации вам понадобится:

dotnet add package GroupDocs.Metadata --version 26.6.0

Сопутствующий репозиторий содержит образцы каждого формата и проверяет каждый шаг ниже.

Реализация рабочего процесса шаг за шагом

Шаг 1 — Фиксация всего при загрузке

Один проход захватывает пакет, именованные схемы и всё, что скрывают инструменты поставщика. Сохраните словарь рядом с записью актива, и последующие запросы станут простыми запросами к базе данных.

// Full XMP snapshot: packet, schemes, then a deep sweep
var result = new Dictionary<string, string>();
using (var metadata = new Metadata(adobeFilePath))
{
    var root = metadata.GetRootPackage() as IXmp;
    if (root?.XmpPackage == null) return result;

    foreach (var property in root.XmpPackage)
    {
        result[property.Name] = property.InterpretedValue?.ToString()
            ?? property.Value?.ToString() ?? string.Empty;
    }
    // CollectScheme(...) repeats this loop for DublinCore, XmpBasic,
    // Photoshop, CameraRaw, PagedText, XmpDynamicMedia, XmpMediaManagement
    foreach (var p in metadata.FindProperties(p => p.Name != null))
    {
        if (!result.ContainsKey(p.Name))
        {
            result[p.Name] = p.InterpretedValue?.ToString()
                ?? p.Value?.ToString() ?? string.Empty;
        }
    }
}
return result;

InterpretedValue берётся в первую очередь, поэтому даты и перечисления становятся человекочитаемыми. Последний проход FindProperties гарантирует полноту для метаданных Adobe Illustrator, записанных плагинами, о которых именованные схемы не знают.

Две практические заметки при масштабной загрузке: храните снимок, привязанный к ID актива, и помечайте его датой захвата, потому что файл может измениться, а снимок — ваша «до» картина. Пустой словарь следует рассматривать как сигнал, а не как ошибку; он направляет актив сразу к шагу штамповки, а не прерывает загрузку.

Шаг 2 — Проверка Dublin Core на этапе лицензирования

Девять полей dc:* отвечают на вопросы, которые действительно задают юридический и лицензионный отделы. Чтение только этой схемы делает шлюз быстрым.

// dc:* fields only - Title, Creator, Rights, Subject and friends
var result = new Dictionary<string, string>();
using (var metadata = new Metadata(adobeFilePath))
{
    var root = metadata.GetRootPackage() as IXmp;
    var dc = root?.XmpPackage?.Schemes?.DublinCore;
    if (dc == null) return result;

    foreach (var property in dc)
    {
        result[property.Name] = property.InterpretedValue?.ToString()
            ?? property.Value?.ToString() ?? string.Empty;
    }
}
return result;

Почему эти настройки важны для производственных команд:

  • Null‑conditional chain: файлы без XMP — обычное дело в свежих экспортированных версиях; пустой словарь означает «поставьте штамп», а не «упади».
  • Объём схемы: шлюзы работают при каждом перемещении актива, поэтому чтение девяти полей вместо полного дерева экономит ресурсы.

Шаг 3 — Штампование владельца при экспорте

Запись затрагивает три уровня, чтобы любой читатель, поддерживающий XMP или нет, видел одинаковую информацию. Сначала создаются недостающие объекты пакета и схемы.

// Guard-create the packet and scheme, then write rights and creator
using (var metadata = new Metadata(inputPath))
{
    var root = metadata.GetRootPackage() as IXmp;
    if (root == null) return;

    if (root.XmpPackage == null)
        root.XmpPackage = new XmpPacketWrapper();
    if (root.XmpPackage.Schemes.DublinCore == null)
        root.XmpPackage.Schemes.DublinCore = new XmpDublinCorePackage();

    var dc = root.XmpPackage.Schemes.DublinCore;
    dc.SetRights(copyright);
    dc.Set("dc:creator", XmpArray.From(new[] { creator }, XmpArrayType.Ordered));
    // Mirror the identity for XmpBasic readers and tag-classified fields
    if (root.XmpPackage.Schemes.XmpBasic == null)
        root.XmpPackage.Schemes.XmpBasic = new XmpBasicPackage();
    root.XmpPackage.Schemes.XmpBasic.CreatorTool = creator;

    metadata.SetProperties(p => p.Tags.Contains(Tags.Person.Creator),
        new PropertyValue(creator));

    metadata.Save(outputPath);
}

Вызов SetProperties с Tags.Person.Creator — это деталь, которую стоит позаимствовать: он обновляет каждое свойство, которое библиотека классифицирует как поле создателя, где бы формат его ни хранил, поэтому инструменты, которые никогда не читают XMP, всё равно показывают правильное имя.

Шаг 4 — Запись ключевых слов для поиска

dc:subject — словарь, по которому DAM‑поиск индексирует активы. Без него активы существуют, но никогда не попадают в результаты запросов.

// Replace the dc:subject bag with the pipeline's keyword list
root.XmpPackage.Schemes.DublinCore.Set(
    "dc:subject",
    XmpArray.From(keywords, XmpArrayType.Unordered));
metadata.Save(outputPath);

Запись заменяет существующий набор, поэтому добавление тегов подразумевает: чтение → слияние в C# → запись. Репозиторий записывает три примерных ключевых слова и проверяет, что первое сохраняется в байтах. Команды, которые версионируют свою таксономию, обычно хранят канонический набор ключевых слов для каждой кампании и позволяют конвейеру согласовывать файлы с этим набором при каждом экспорте, превращая дрейф тегов в diff, а не в спор.

Нужно ли покупать лицензии Photoshop только для исправления метаданных?

Нет, и обычно в этом и заключается смысл автоматизации. GroupDocs.Metadata читает и пишет пакет напрямую в .NET, поэтому серверный процесс может ставить права или исправлять ключевые слова в архиве без открытия единого приложения Adobe. Дизайнеры сохраняют свои инструменты для работы над дизайном, а конвейер отвечает за чистоту метаданных в масштабе.

Что это меняет для бизнеса

Описанный выше рабочий процесс превращает три повторяющихся инцидента в не‑события. Вопросы о правах перестают требовать человеческой памяти, потому что dc:rights проверяется на шлюзе и ставится, если отсутствует. Непоисковываемые активы перестают накапливаться, потому что ключевые слова пишет конвейер, а не кто‑то, кто вспомнил. И работа с метаданными больше не потребляет лицензии Adobe, так как ни один из четырёх шагов не открывает приложение дизайнера.

Есть также аудитная история, которую ручное редактирование не может предоставить. Каждое решение на шлюзе и каждый штамп фиксируются в коде, так что когда клиент спрашивает, как у актива появилась строка прав, ответом будет временная метка в журнале конвейера. Весь процесс состоит из пяти небольших методов, каждый из которых проверен в сопутствующем репозитории как на PSD, так и на AI‑примерах — именно тот объём, который платформа может поддерживать без выделенного обслуживающего специалиста.

Заключение

XMP‑метаданные в файлах PSD и AI перестают быть ручной рутиной, как только конвейер берёт их под контроль: фиксировать при загрузке, проверять Dublin Core на шлюзах, ставить владельца и ключевые слова при экспорте. Один каст к IXmp обслуживает оба формата, охранные проверки делают новые экспорты безопасным вводом, а каждая показанная операция проверена в примерах репозитория.

Готовы внедрить это в ваш конвейер?

Дополнительные ресурсы