Полный рабочий пример доступен на GitHub:
manage-xmp-in-psd-and-ai-files-python

Введение

Маркетинговая команда загружает 400 PSD‑файлов в вашу платформу активов. Загрузка проходит успешно. Поиск не работает, потому что ни один файл не содержит ключевых слов, у половины отсутствует уведомление об авторских правах, а имена дизайнеров находятся только в какой‑то таблице. Решение — не более крупная таблица. Управление XMP — это возможность GroupDocs.Metadata для Python через .NET, которая читает и записывает пакет метаданных, встроенный в файлы Photoshop PSD и Illustrator AI, что позволяет хранить данные о праве собственности и поиске непосредственно в файлах.

XMP — это XML‑пакет внутри бинарного контейнера, организованный в схемы: Dublin Core — поля, понятные любой системе, схема Photoshop — редакционный контекст, XmpBasic — идентификация инструмента. Разобрать PSD вручную, чтобы добраться до этого пакета, действительно сложно. С классом Metadata это три обращения к атрибутам, и тот же код работает и с AI‑файлами.

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

Необходимые условия

Прежде чем начать, убедитесь, что у вас есть:

  • Python 3 с pip
  • GroupDocs.Metadata для Python через .NET (в репозитории зафиксирована версия 26.5)
  • PSD‑ или AI‑файл для экспериментов

Установка

pip install groupdocs-metadata-net==26.5

Шаг 1 — Снимок всего XMP пакета

Начните с просмотра всего, что содержит файл. Снимок проходит по корневому пакету, каждой зарегистрированной схеме и, наконец, сканирует дерево свойств в поисках чего‑нибудь нестандартного, собирая всё в один плоский словарь.

result = {}

def put(props, prop):
    value = (str(prop.interpreted_value) if prop.interpreted_value is not None
             else (str(prop.value) if prop.value is not None else ""))
    props[prop.name] = value

with Metadata("campaign-hero.psd") as metadata:
    root = metadata.get_root_package()
    xmp = getattr(root, "xmp_package", None)
    if xmp is not None:
        for p in xmp:                                  # свойства корневого пакета
            put(result, p)
        schemes = xmp.schemes
        for scheme in (schemes.dublin_core, schemes.xmp_basic, schemes.photoshop,
                       schemes.camera_raw, schemes.paged_text,
                       schemes.xmp_dynamic_media, schemes.xmp_media_management):
            if scheme is None:
                continue
            for p in scheme:
                put(result, p)
    for p in metadata.find_properties(lambda p: p.name is not None):
        if p.name not in result:                       # захват пользовательских пакетов
            put(result, p)

Ключевые моменты:

  • Сначала interpreted_value: даты и перечисления приходят в человекочитаемом виде, а не в сыром виде.
  • Семь схем плюс сканирование: завершающий проход find_properties ловит пакеты поставщиков, которые не охвачены именованными схемами.
  • Открыт только один файл: весь снимок выполняется в едином контексте Metadata, что важно при массовом вводе.

Подсказка: индексируйте этот словарь во время ввода, и большинство последующих вопросов к метаданным превращаются в поиск по словарю вместо чтения файлов.

Какую схему XMP должна сначала читать моя интеграция?

Начните с Dublin Core. Его девять полей dc: содержат заголовок, создателя, права и тему — значения, которые согласованы большинством DAM‑систем, поисковых индексов и проверок лицензий, и оба формата — PSD и AI — представляют их одинаково. Затем читайте схему Photoshop для редакционного контекста, например City, Credit и DateCreated. Полный скан пакета оставьте для задач ввода, которым необходимо захватить всё.

Шаг 2 — Чтение схем, отвечающих на реальные вопросы

Для кода, работающего по запросу, ограничьте чтение одной схемой. Dublin Core отвечает на вопросы о праве собственности и поиске:

dc_fields = {}
with Metadata("campaign-hero.psd") as metadata:
    xmp = getattr(metadata.get_root_package(), "xmp_package", None)
    dc = xmp.schemes.dublin_core if xmp is not None else None
    if dc is not None:
        for p in dc:
            dc_fields[p.name] = (str(p.interpreted_value)
                                 if p.interpreted_value is not None else
                                 str(p.value) if p.value is not None else "")

print(dc_fields.get("dc:rights", "<no rights recorded>"))

Схема Photoshop работает аналогично через типизированные свойства: ps.color_mode, ps.icc_profile, ps.city, ps.country, ps.date_created, ps.caption_writer, ps.credit и ps.source, каждое читается с проверкой на None. Именно эти поля используют Bridge, Lightroom и фильтры поиска DAM для файлов Adobe.

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

Тот же набор трёх запросов работает и с файлами Illustrator. Поменяйте campaign-hero.psd на brand-mark.ai, и ничего больше не меняется — это делает один путь кода реальным для смешанных архивов Adobe. На практике свежий экспорт AI обычно содержит меньше заполненных схем, чем сохранение Photoshop, поэтому путь с пустым словарём вызывается чаще.

Шаг 3 — Запись авторских прав и создателя

Теперь путь записи. Маркировка собственности затрагивает три поля, чтобы каждый читатель видел одинаковую информацию: dc:rights — юридическое уведомление, dc:creator — упорядоченный список, и xmp:CreatorTool — инструмент, читающий схему XmpBasic вместо Dublin Core. Однажды я потерял полдня, пытаясь избавиться от баннера лицензии «Неизвестный автор» в активах, которые дизайнеры уверяли, что пометили; значения находились в dc:creator, а инструмент читал только xmp:CreatorTool. Запись обоих полей устранила эту категорию багов.

with Metadata("campaign-hero.psd") as metadata:
    root = metadata.get_root_package()
    xmp = getattr(root, "xmp_package", None)
    if xmp is None:                          # файл вообще не имеет XMP
        root.xmp_package = XmpPacketWrapper()
        xmp = root.xmp_package
    if xmp.schemes.dublin_core is None:
        xmp.schemes.dublin_core = XmpDublinCorePackage()

    dc = xmp.schemes.dublin_core
    dc.set_rights("(C) 2026 GroupDocs Sample")
    dc.set("dc:creator", XmpArray.from_(["Digital Asset Team"],
                                        XmpArrayType.ORDERED))

    if xmp.schemes.xmp_basic is None:
        xmp.schemes.xmp_basic = XmpBasicPackage()
    xmp.schemes.xmp_basic.creator_tool = "Digital Asset Team"

    metadata.save("campaign-hero-stamped.psd")

Ключевые моменты:

  • Проверки создают недостающие уровни: XmpPacketWrapper и XmpDublinCorePackage создаются по требованию, поэтому запись работает и в файлах без XMP.
  • Упорядоченный массив для создателей: порядок авторов имеет значение, поэтому список создателей использует упорядоченный XmpArray.
  • Сохранение в новый путь: исходный файл остаётся нетронутым, что является правильным поведением по умолчанию при экспортных шагах.

Шаг 4 — Тегирование ключевых слов для поиска

dc:subject — это набор ключевых слов для индексов DAM. Запись заменяет весь набор одним вызовом:

with Metadata("campaign-hero.psd") as metadata:
    root = metadata.get_root_package()
    xmp = getattr(root, "xmp_package", None)
    if xmp is None:
        root.xmp_package = XmpPacketWrapper()
        xmp = root.xmp_package
    if xmp.schemes.dublin_core is None:
        xmp.schemes.dublin_core = XmpDublinCorePackage()

    xmp.schemes.dublin_core.set(
        "dc:subject",
        XmpArray.from_(["landscape", "sunset", "commercial"],
                       XmpArrayType.UNORDERED))
    metadata.save("campaign-hero-tagged.psd")

Ключевые слова используют массив UNORDERED, потому что порядок не важен для индексатора. Поскольку set заменяет существующий набор, сначала прочитайте текущие ключевые слова и объедините их в Python, если вам нужно добавить, а не заменить.

Чтобы проверить любую запись, повторно выполните читатель Шага 2 над полученным файлом. Репозиторий автоматизирует именно это: он перечитывает свои выводы и проверяет, что строка авторских прав и первое ключевое слово сохраняются в записанных байтах.

Примеры из реального мира

Ввод в DAM

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

Применение лицензий

Перед тем как актив будет отправлен в клиентский портал, требуйте непустое dc:rights. Файлы, у которых это поле пустое, автоматически проходят обработку Шага 3, поэтому ничего не покидает систему без уведомления.

Массовое пере‑тегирование

Когда меняется таксономия, прочитайте dc:subject каждого файла, сопоставьте старые термины с новыми в Python и запишите объединённый набор обратно с помощью Шага 4. И PSD, и AI‑архивы обрабатываются одним и тем же циклом. Никакой лицензии Photoshop не требуется.

Лучшие практики и советы

  • Считать пустоту нормой: файлы без XMP — обычное дело, а не ошибка; шаблон раннего возврата поддерживает плавность конвейеров.
  • Объединять перед записью ключевых слов: set заменяет dc:subject, поэтому добавление подразумевает чтение, расширение, запись.
  • Записывать идентификацию в обе схемы: сопоставление dc:creator с xmp:CreatorTool обеспечивает согласованность между читателями Dublin Core и XmpBasic.
  • Проверять записи повторным чтением: повторный читатель после сохранения дешёв и сразу выявляет неожиданные изменения контейнера.
  • Лицензировать для продакшна: режим оценки работает для всех показанных примеров; используйте лицензию перед тем, как ставить штамп на реальные клиентские активы.

Заключение

Чтение и запись XMP в файлах Adobe сводится к трем действиям: получить пакет через get_root_package(), проверить наличие нужной схемы и прочитать или записать типизированные значения. С этими действиями вы построили полный цикл в этом учебнике — от снимка пакета до чтения схем, маркировки авторских прав и тегирования ключевых слов, используя один и тот же код для PSD и AI файлов.

Готовы внедрить это в свой проект? Следующие шаги:

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

Вопросы о вашем XMP‑рабочем процессе? Спросите на форуме поддержки.