Full working example available on GitHub: manage-xmp-in-psd-and-ai-files-python

Introducción

Un equipo de marketing deja caer 400 archivos PSD en tu plataforma de activos. La carga funciona. La búsqueda no, porque ninguno de los archivos lleva palabras clave, la mitad carece de un aviso de derechos de autor y los nombres de los diseñadores viven solo en una hoja de cálculo en algún lugar. La solución no es una hoja de cálculo más grande. La gestión de XMP es una capacidad de GroupDocs.Metadata para Python a través de .NET que lee y escribe el paquete de metadatos incrustado en archivos Photoshop PSD y Illustrator AI, lo que significa que la propiedad y los datos de búsqueda pueden vivir en los propios archivos.

XMP es un paquete XML dentro de un contenedor binario, organizado en esquemas: Dublin Core para los campos que todo sistema entiende, el esquema Photoshop para el contexto editorial, XmpBasic para la identidad de la herramienta. Analizar un PSD a mano para llegar a ese paquete es realmente difícil. Con la clase Metadata son tres búsquedas de atributos, y el mismo código sirve para archivos AI.

Este tutorial recorre todo el ciclo en cuatro pasos: capturar todo el paquete, leer los esquemas que importan, escribir derechos de autor y creador, y etiquetar palabras clave para la búsqueda. Cada fragmento proviene de un repositorio ejecutable que verifica que los valores escritos persisten.

Requisitos previos

Antes de comenzar, asegúrate de tener:

  • Python 3 con pip
  • GroupDocs.Metadata para Python a través de .NET (el repositorio fija la versión 26.5)
  • Un archivo PSD o AI para experimentar

Instalación

pip install groupdocs-metadata-net==26.5

Paso 1 - Captura del paquete XMP completo

Comienza viendo todo lo que el archivo lleva. La captura recorre el paquete raíz, cada esquema registrado y, finalmente, barre el árbol de propiedades para cualquier cosa no estándar, recopilándolo todo en un único diccionario plano.

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:                                  # root packet properties
            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:                       # catch custom packets
            put(result, p)

Puntos clave:

  • interpreted_value primero: fechas y enumeraciones llegan legibles para humanos en lugar de crudas.
  • Siete esquemas más un barrido: la pasada final find_properties captura paquetes de proveedores que los esquemas nombrados no detectan.
  • Un solo archivo abierto: toda la captura cuesta un único contexto Metadata, lo que importa en ingestiones masivas.

Consejo: indexa este diccionario en el momento de la ingestión y la mayoría de las preguntas posteriores sobre metadatos se convierten en búsquedas en el diccionario en lugar de lecturas de archivo.

¿Qué esquema XMP debería leer primero mi integración?

Comienza con Dublin Core. Sus nueve campos dc: llevan el título, creador, derechos y asunto que la mayoría de los sistemas DAM, índices de búsqueda y verificaciones de licencias aceptan, y tanto los archivos PSD como AI los exponen idénticamente. Lee el esquema Photoshop segundo para el contexto editorial como City, Credit y DateCreated. Guarda el barrido del paquete completo para trabajos de ingestión que deban capturar todo.

Paso 2 - Leer los esquemas que responden preguntas reales

Para código en tiempo de solicitud, limita la lectura a un esquema. Dublin Core responde preguntas de propiedad y búsqueda:

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>"))

El esquema Photoshop funciona de la misma manera a través de propiedades tipadas: ps.color_mode, ps.icc_profile, ps.city, ps.country, ps.date_created, ps.caption_writer, ps.credit y ps.source, cada una leída con una protección contra None. Esos son los campos que Bridge, Lightroom y los filtros de búsqueda DAM utilizan para archivos Adobe.

Observa lo que ocurre con archivos sin XMP: las protecciones producen un diccionario vacío, no una excepción. Los activos exportados recientemente hacen que este caso sea rutinario, así que mantén ese comportamiento en tu integración.

Las mismas tres búsquedas funcionan en archivos Illustrator. Cambia campaign-hero.psd por brand-mark.ai y nada más cambia, lo que hace que una única ruta de código sea realista para archivos Adobe mixtos. En la práctica, una exportación AI fresca tiende a llegar con menos esquemas poblados que un guardado de Photoshop, por lo que la ruta del diccionario vacío se ejerce con más frecuencia allí.

Paso 3 - Escribir derechos de autor y creador

Ahora la ruta de escritura. El marcado de propiedad toca tres campos para que todo lector vea la misma identidad: dc:rights para el aviso legal, dc:creator como una lista ordenada, y xmp:CreatorTool para herramientas que leen el esquema XmpBasic en lugar de Dublin Core. Una vez perdí una tarde con un banner de licencia que mostraba “Autor desconocido” en activos que los diseñadores juraban estaban etiquetados; los valores estaban en dc:creator mientras la herramienta solo leía xmp:CreatorTool. Escribir ambos acabó con esa clase de error.

with Metadata("campaign-hero.psd") as metadata:
    root = metadata.get_root_package()
    xmp = getattr(root, "xmp_package", None)
    if xmp is None:                          # file has no XMP at all
        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")

Puntos clave:

  • Las protecciones crean capas faltantes: XmpPacketWrapper y XmpDublinCorePackage se crean bajo demanda, por lo que la escritura funciona en archivos sin XMP.
  • Array ORDERED para creadores: el orden del autor tiene significado, así que la lista de creadores usa un XmpArray ordenado.
  • Guardar en una ruta nueva: el archivo fuente permanece intacto, que es el valor predeterminado correcto para pasos de exportación.

Paso 4 - Etiquetar palabras clave para búsqueda

dc:subject es la bolsa de palabras clave que los índices DAM utilizan. La escritura reemplaza toda la bolsa en una sola llamada:

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")

Las palabras clave usan un array UNORDERED porque el orden no significa nada para un indexador. Y dado que set reemplaza la bolsa existente, lee primero las palabras clave actuales y combínalas en Python cuando necesites etiquetado aditivo en lugar de reemplazo.

Para verificar cualquier escritura, vuelve a ejecutar el lector del Paso 2 contra el archivo de salida. El repositorio automatiza exactamente eso: vuelve a leer sus salidas y afirma que la cadena de derechos de autor y la primera palabra clave sobreviven en los bytes guardados.

Aplicaciones del mundo real

Ingesta DAM

Ejecuta la captura del Paso 1 en cada archivo entrante y almacena el diccionario junto al registro del activo. La búsqueda, deduplicación y verificaciones de derechos luego se ejecutan contra tu base de datos en lugar de volver a abrir archivos binarios. La captura de la pequeña muestra PSD del repositorio ya devuelve un conjunto saludable de propiedades en una pasada, y la misma llamada mantiene su forma cuando la entrada se convierte en una carpeta de miles.

Aplicación de licencias

Antes de que un activo se envíe a un portal de cliente, exige un dc:rights no vacío. Los archivos que fallan reciben automáticamente el tratamiento de estampado del Paso 3, de modo que nada sale sin un aviso.

Reetiquetado por lotes

Cuando la taxonomía cambia, lee el dc:subject de cada archivo, mapea los términos antiguos a los nuevos en Python y escribe la bolsa combinada de nuevo con el Paso 4. Tanto los archivos PSD como AI siguen el mismo bucle. No se requiere una licencia de Photoshop.

Mejores prácticas y consejos

  • Trata el vacío como normal: los archivos sin XMP son rutinarios, no errores; el patrón de retorno temprano mantiene los pipelines fluyendo.
  • Combina antes de escribir palabras clave: set reemplaza dc:subject, así que el etiquetado aditivo implica leer, ampliar, escribir.
  • Escribe la identidad en ambos esquemas: combinar dc:creator con xmp:CreatorTool mantiene a los lectores de Dublin Core y XmpBasic de acuerdo.
  • Verifica las escrituras con una lectura posterior: una relectura después de guardar es barata y captura sorpresas del contenedor de inmediato.
  • Licencia para producción: el modo de evaluación ejecuta todo lo mostrado aquí; usa una licencia antes de estampar activos reales de clientes.

Conclusión

Leer y escribir XMP en archivos Adobe se reduce a tres movimientos: resolver el paquete mediante get_root_package(), proteger el esquema que necesitas y leer o escribir valores tipados. Con esos movimientos construiste un ciclo completo en este tutorial, desde la captura del paquete hasta lecturas de esquemas, estampado de derechos de autor y etiquetado de palabras clave, con el mismo código sirviendo a archivos PSD y AI.

¿Listo para implementar esto en tu proyecto? Aquí tienes algunos pasos siguientes:

Recursos adicionales

¿Preguntas sobre tu flujo de trabajo XMP? Pregunta en el forum de soporte.