Pełny działający przykład dostępny na GitHubie:
manage-xmp-in-psd-and-ai-files-python

Wprowadzenie

Zespół marketingowy wrzuca 400 plików PSD do Twojej platformy zasobów. Przesyłanie działa. Wyszukiwanie nie, ponieważ żaden z plików nie zawiera słów kluczowych, połowa nie ma informacji o prawach autorskich, a nazwiska projektantów istnieją tylko w jakimś arkuszu kalkulacyjnym. Rozwiązaniem nie jest większy arkusz. Zarządzanie XMP to funkcja GroupDocs.Metadata dla Pythona przez .NET, która odczytuje i zapisuje pakiet metadanych osadzony w plikach Photoshop PSD i Illustrator AI, co oznacza, że informacje o własności i wyszukiwaniu mogą znajdować się w samych plikach.

XMP to pakiet XML wewnątrz kontenera binarnego, podzielony na schematy: Dublin Core dla pól rozumianych przez wszystkie systemy, schemat Photoshop dla kontekstu redakcyjnego, XmpBasic dla tożsamości narzędzia. Ręczne parsowanie PSD, aby dotrzeć do tego pakietu, jest naprawdę trudne. Z klasą Metadata to trzy odwołania do atrybutów, a ten sam kod działa również dla plików AI.

Ten samouczek prowadzi przez pełny cykl w czterech krokach: zrzut całego pakietu, odczyt istotnych schematów, zapis praw autorskich i twórcy oraz oznaczenie słów kluczowych do wyszukiwania. Każdy fragment kodu pochodzi z działającego repozytorium, które sprawdza, że zapisane wartości pozostają w pliku.

Wymagania wstępne

Przed rozpoczęciem upewnij się, że masz:

  • Python 3 z pip
  • GroupDocs.Metadata dla Pythona przez .NET (repozytorium wymusza wersję 26.5)
  • Plik PSD lub AI do eksperymentów

Instalacja

pip install groupdocs-metadata-net==26.5

Krok 1 – Zrzut całego pakietu XMP

Zacznij od zobaczenia wszystkiego, co plik zawiera. Zrzut przegląda pakiet główny, każdy zarejestrowany schemat i na końcu przeszukuje drzewo właściwości pod kątem wszystkiego niestandardowego, zbierając to wszystko w jedną płaską słownikową strukturę.

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:                                  # właściwości pakietu głównego
            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:                       # przechwycenie własnych pakietów
            put(result, p)

Kluczowe punkty:

  • interpreted_value najpierw: daty i wyliczenia pojawiają się w formie czytelnej dla człowieka, a nie w surowej.
  • Siedem schematów plus przeszukiwanie: końcowy przebieg find_properties łapie pakiety dostawców, które nie zostały objęte nazwanymi schematami.
  • Jedno otwarcie pliku: cały zrzut kosztuje jedynie jednego kontekstu Metadata, co ma znaczenie przy masowym ingestowaniu.

Wskazówka: zindeksuj ten słownik w czasie ingestowania, a większość późniejszych pytań o metadane stanie się odwołaniem do słownika zamiast odczytu pliku.

Który schemat XMP powinien najpierw odczytać moja integracja?

Zacznij od Dublin Core. Jego dziewięć pól dc: zawiera tytuł, twórcę, prawa i temat, które większość systemów DAM, indeksów wyszukiwania i kontroli licencji uznaje, a zarówno pliki PSD, jak i AI udostępniają je identycznie. Drugi odczytuj schemat Photoshop, aby uzyskać kontekst redakcyjny, taki jak City, Credit i DateCreated. Pełny przegląd pakietu zostaw na zadania ingestujące, które muszą przechwycić wszystko.

Krok 2 – Odczyt schematów, które odpowiadają na rzeczywiste pytania

W kodzie wywoływanym w czasie żądania ogranicz odczyt do jednego schematu. Dublin Core odpowiada na pytania o własność i wyszukiwanie:

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

Schemat Photoshop działa w ten sam sposób poprzez typowane właściwości: ps.color_mode, ps.icc_profile, ps.city, ps.country, ps.date_created, ps.caption_writer, ps.credit i ps.source, każda odczytywana z zabezpieczeniem przed None. Są to pola, na które filtrują Bridge, Lightroom i wyszukiwarki DAM w plikach Adobe.

Zwróć uwagę, co się dzieje w plikach bez XMP: zabezpieczenia zwracają pusty słownik, a nie wyjątek. Świeżo wyeksportowane zasoby często tak właśnie wyglądają, więc zachowaj tę logikę w swojej integracji.

Te same trzy odczyty działają również w plikach Illustrator. Zamień campaign-hero.psd na brand-mark.ai i nic się nie zmieni, co czyni jedną ścieżkę kodu realistyczną dla mieszanych archiwów Adobe. W praktyce świeży eksport AI zazwyczaj zawiera mniej wypełnionych schematów niż zapis Photoshop, więc ścieżka zwracająca pusty słownik jest tam wykorzystywana częściej.

Krok 3 – Zapis praw autorskich i twórcy

Teraz ścieżka zapisu. Oznaczenie własności dotyka trzech pól, aby każdy czytnik widział tę samą tożsamość: dc:rights jako informacja prawna, dc:creator jako lista uporządkowana oraz xmp:CreatorTool dla narzędzi, które odczytują schemat XmpBasic zamiast Dublin Core. Kiedyś straciłem popołudnie na baner licencyjny wyświetlający „Nieznany autor” w zasobach, które projektanci zapewniali, że są otagowane; wartości znajdowały się w dc:creator, a narzędzie odczytywało tylko xmp:CreatorTool. Zapis obu zakończył tę klasę błędów.

with Metadata("campaign-hero.psd") as metadata:
    root = metadata.get_root_package()
    xmp = getattr(root, "xmp_package", None)
    if xmp is None:                          # plik nie ma w ogóle 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")

Kluczowe punkty:

  • Zabezpieczenia tworzą brakujące warstwy: XmpPacketWrapper i XmpDublinCorePackage są tworzone w razie potrzeby, więc zapis działa także w plikach bez XMP.
  • Tablica ORDERED dla twórców: kolejność autorów ma znaczenie, dlatego lista twórców używa uporządkowanej XmpArray.
  • Zapisz pod nową ścieżką: plik źródłowy pozostaje niezmieniony, co jest właściwym domyślnym zachowaniem przy krokach eksportu.

Krok 4 – Oznaczanie słów kluczowych do wyszukiwania

dc:subject to worek słów kluczowych, którego używają indeksy wyszukiwania DAM. Zapis zastępuje cały worek w jednym wywołaniu:

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

Słowa kluczowe używają tablicy UNORDERED, ponieważ kolejność nie ma znaczenia dla indeksatora. Ponieważ set zastępuje istniejący worek, najpierw odczytaj bieżące słowa kluczowe i połącz je w Pythonie, gdy potrzebujesz dodawania tagów zamiast ich zastępowania.

Aby zweryfikować każdy zapis, ponownie uruchom czytnik z Kroku 2 na pliku wyjściowym. Repozytorium automatyzuje dokładnie to: ponownie odczytuje swoje wyniki i sprawdza, czy ciąg praw autorskich oraz pierwsze słowo kluczowe przetrwały w zapisanych bajtach.

Praktyczne zastosowania

Ingestja DAM

Uruchom zrzut z Kroku 1 na każdym przychodzącym pliku i przechowuj słownik razem z rekordem zasobu. Wyszukiwanie, deduplikacja i kontrole praw potem odbywają się na bazie danych zamiast ponownego otwierania plików binarnych. Zrzut małej próbki PSD z repozytorium już zwraca solidny zestaw właściwości w jednym przebiegu, a to samo wywołanie zachowuje swoją formę, gdy wejściem staje się folder z tysiącami plików.

Egzekwowanie licencji

Zanim zasób trafi do portalu klienta, wymagaj niepustego dc:rights. Pliki, które nie spełniają tego warunku, automatycznie przechodzą przez proces znakowania z Kroku 3, więc nic nie opuszcza systemu bez odpowiedniej informacji.

Masowa zmiana tagów

Gdy zmienia się taksonomia, odczytaj dc:subject każdego pliku, zamapuj stare terminy na nowe w Pythonie i zapisz połączony worek z powrotem przy użyciu Kroku 4. Zarówno archiwa PSD, jak i AI korzystają z tej samej pętli. Nie potrzebujesz licencji Photoshop.

Najlepsze praktyki i wskazówki

  • Traktuj pusty jako normalny: pliki bez XMP są rutyną, nie błędem; wzorzec wczesnego zwrotu utrzymuje przepływy w pipeline.
  • Scal przed zapisem słów kluczowych: set zastępuje dc:subject, więc dodawanie tagów wymaga odczytu, rozszerzenia i zapisu.
  • Zapisuj tożsamość w obu schematach: parowanie dc:creator z xmp:CreatorTool utrzymuje zgodność czytników Dublin Core i XmpBasic.
  • Weryfikuj zapisy odczytem zwrotnym: ponowne odczytanie po zapisie jest tanie i natychmiast wykrywa niespodziewane zmiany w kontenerze.
  • Licencja na produkcję: tryb ewaluacyjny uruchamia wszystko, co pokazano tutaj; przed znakowaniem rzeczywistych zasobów klientów użyj licencji.

Zakończenie

Odczyt i zapis XMP w plikach Adobe sprowadza się do trzech kroków: rozwiąż pakiet przez get_root_package(), zabezpiecz potrzebny schemat i odczytaj lub zapisz typowane wartości. Dzięki tym krokom zbudowałeś pełny cykl w tym samouczku – od zrzutu pakietu, przez odczyt schematów, po znakowanie praw autorskich i tagowanie słów kluczowych – przy użyciu tego samego kodu dla plików PSD i AI.

Gotowy, aby wdrożyć to w swoim projekcie? Oto kolejne kroki:

Dodatkowe zasoby

Masz pytania dotyczące swojego przepływu pracy XMP? Zapytaj na forum wsparcia.