Pełny działający przykład dostępny na GitHub: read-and-write-xmp-in-psd-ai-files-java
Stara metoda była bolesna
Wyobraź sobie porządkowanie archiwum, do którego nikt nie chce się zgłosić. Folder z plikami PSD i źródłami AI wymaga umieszczenia informacji o prawach autorskich i słowach kluczowych, zanim trafi do systemu DAM. Rutyna: otwierasz plik w Photoshopie, otwierasz „File Info”, wpisujesz informacje o prawach autorskich, wpisujesz słowa kluczowe, zapisujesz, zamykasz, przechodzisz do kolejnego pliku. Każde zapisanie ponownie renderuje warstwowy plik tylko po to, by zmienić kilka ciągów metadanych XMP. Archiwum, które dało mi tę lekcję, było folderem nieoznaczonych plików Illustrator, których nikt nie mógł przeszukać; naprawiliśmy to pętlą, nie większą cierpliwością.
Pomnóż tę rutynę przez archiwum i przestaje być to zadanie, a staje się projektem. Co gorsza, jest nieaudytowalne: nikt nie może później udowodnić, które pliki zostały przetworzone, a te pominięte wyglądają identycznie, dopóki nie pojawi się pytanie o licencję. Metoda panelowa dodatkowo cicho łączy wprowadzanie danych z narzędziami projektowymi. Ktokolwiek naprawia metadane, potrzebuje miejsca w Adobe, stacji roboczej, która komfortowo otwiera warstwowe pliki, oraz cierpliwości, by czekać na zapisy, które ponownie renderują grafikę tylko po to, by zmienić ciągi znaków.
Rzeczywisty koszt ręcznego wykonywania: metadane poprawione ręcznie to metadane, których nikt nie może później zweryfikować; proces nie zostawia śladu, poza zmęczonymi projektantami.
Istnieje lepszy sposób
GroupDocs.Metadata for Java odczytuje i zapisuje pakiet XMP bezpośrednio. Rzutuj getRootPackage() na IXmp, a pakiet, jego schematy i tablice są zwykłymi obiektami Javy, identycznymi dla kontenerów PSD i AI, bez udziału oprogramowania Adobe. Dokumentacja wymienia ponad 170 formatów dostępnych przez to samo API.
Zanim zaczniemy, będziesz potrzebować:
- JDK 8 lub nowszy z Mavenem
- GroupDocs.Metadata for Java 24.7 (uzyskaj tymczasową licencję)
- Plik PSD lub AI do ćwiczeń
Dodaj zależność i repozytorium GroupDocs do swojego pom.xml:
mvn dependency:get -Dartifact=com.groupdocs:groupdocs-metadata:24.7
Repozytorium towarzyszące dostarcza gotowy pom.xml oraz przykładowe pliki obu formatów, i weryfikuje każdy poniższy krok.
Nowy sposób: cztery operacje w Javie
Krok 1 – Zobacz, co niesie plik
Migawka zrzuca pakiet i każdy schemat do jednego LinkedHashMap, zachowując kolejność zadeklarowaną w pliku.
// 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;
Małe pomocnicze metody put i collect preferują getInterpretedValue(), dzięki czemu daty są czytelne, a przeszukiwanie oparte na Specification łapie pakiety dostawców. Wersja w repozytorium przegląda siedem schematów; struktura pozostaje taka sama.
Krok 2 – Odczytaj pola, które odpowiadają na pytania
Licencjonowanie pyta o dc:rights. Wyszukiwanie interesuje dc:subject. Oba znajdują się w Dublin Core, a odczyt w zakresie kosztuje dziewięć pól, a nie pełne przeszukiwanie drzewa.
// 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);
}
Schemat Photoshop działa tak samo, korzystając z typowanych getterów (getCity(), getCredit(), getColorMode() i pięciu kolejnych), obejmując pola metadanych PSD odczytywane przez Bridge i filtry Lightroom. W repozytorium ten czytnik owija każdy getter pomocnikiem zabezpieczającym przed null, więc słabo wypełniony plik zwraca puste ciągi zamiast niespodzianek. Ten szczegół ma większe znaczenie, niż się wydaje: cały sens automatyzacji archiwum polega na tym, że nietypowe pliki przechodzą dalej, zamiast zatrzymywać pętlę.
Oba odczyty w zakresie mają podobny profil kosztowy, który warto nazwać. Jeden otwarcie pliku, jeden schemat, brak przeszukiwania drzewa. Umieść je w obsłudze żądań i bramkach; zachowaj pełną migawkę dla zadań ingestujących, które przechowują wszystko.
Krok 3 – Oznacz i otaguj bez otwierania Adobe
Zapisywacze tworzą brakujące elementy w razie potrzeby, co czyni je bezpiecznymi dla świeżych eksportów nieposiadających w ogóle pakietu.
// 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);
Słowa kluczowe podążają tym samym wzorcem przy jednym wywołaniu, zapisując całą torbę jako nieuporządkowaną tablicę:
// 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 zamyka pętlę: ponownie odczytuje wyniki i weryfikuje, że ciąg praw autorskich oraz pierwsze słowo kluczowe faktycznie przetrwały zapis.
To zamknięcie asercji zasługuje na zdanie propagujące. Zapisy metadanych zawodzą cicho, gdy się nie powiodą; plik zostaje zapisany, bajty się zmieniają, a wartość, którą chciałeś zapisać, po prostu nie istnieje, bo obiekt schematu był przestarzały lub ścieżka wskazywała na oryginał. Odczyt zwrotny po każdym zapisie kosztuje jedno dodatkowe otwarcie pliku i zamienia „skrypt zakończył się” w „wartości są obecne”, co jest właśnie tym, czego właściciel archiwum naprawdę chce. Trzymaj to w produkcji, nie tylko w demonstracji.
Krok 4 – Jak słowa kluczowe naprawdę czynią zasoby znajdowalnymi?
Narzędzia wyszukiwania nie czytają pikseli; czytają dc:subject. Bridge, indeksatory DAM i platformy stockowe traktują tę torbę jako słownictwo zasobu, więc plik bez słów kluczowych po prostu nigdy nie pasuje do zapytania. Zapisanie torby jako nieuporządkowanej XmpArray, tak jak robi to AddKeywords, jest tym, co przenosi zasób z niewidzialnego do widzialnego, a zapis kosztuje jedno zapisanie.
Porównanie: przed vs. po
| Przed (edycja w panelu) | Po (pipeline w Javie) | |
|---|---|---|
| Narzędzia | Photoshop lub Bridge dla każdego pliku | Jeden projekt Maven, bez miejsca w Adobe |
| Zasięg | Pola, które udostępnia panel | Każdy schemat plus pakiety dostawców |
| Powtarzalność | Zależy od tego, kto kliknął | Ta sama pętla, ten sam wynik, audytowalny |
| Pliki bez XMP | Zachowanie panelu jest zmienne | Guardy tworzą pakiet i schematy |
| Weryfikacja | Zaufanie | Asertywne odczyty zwrotne dla każdego pliku |
Wiersz weryfikacji rozstrzyga to dla archiwów: skrypt, który dowodzi własnych zapisów, to różnica między „oznaczyliśmy pliki” a „możemy wam to pokazać”.
Przykład z życia: przekazanie agencji
Studio otrzymuje mieszane dostawy PSD i AI od trzech agencji, z których każda ma własną dyscyplinę metadanych. Ich zadanie przyjęcia teraz uruchamia migawkę przy przybyciu, oznacza pliki, których dc:rights odczytuje pusty, nakłada na nie ustaloną linię praw, i zapisuje zestaw słów kluczowych kampanii. Ta sama pętla obsługuje oba formaty, ponieważ w kodzie nie ma nazwy kontenera, a metadane Adobe Illustrator, które przychodzą puste, zostają otagowane i możliwe do wyszukania.
Efekt uboczny, którego studio nie przewidziało, to karty wyników agencji. Ponieważ zadanie przyjęcia loguje, które dostawy przybyły z pustymi polami praw, dział zakupów widzi, które dostawcy dostarczają czyste metadane, a które polegają na kliencie, by je naprawić. Rozmowa z najgorszym sprawcą zajęła jeden wykres.
Co jeszcze możesz zrobić z GroupDocs.Metadata?
- EXIF i IPTC w tych samych plikach: PSD‑y zawierają trzy standardy metadanych; ta sama biblioteka odczytuje pozostałe dwa poprzez własne pakiety, więc pełny profil zasobu jest o dwa odczyty dalej.
- Ponad 170 innych formatów: identyczny punkt wejścia
Metadataobsługuje pliki Office, PDF, audio i wideo, co pozwala jednemu zadaniu przyjęcia objąć cały mieszany archiwum. - Wyszukiwanie właściwości:
findPropertieszSpecificationprzeszukuje dowolny plik pod kątem dowolnego predykatu, od kontroli praw po poszukiwania pól niestandardowych.
Podsumowanie
To, co kiedyś było rutyną panelową dla pojedynczego pliku, stało się teraz czterema operacjami w Javie: migawka, odczyt w zakresie, znacznik własności, zapis słów kluczowych. Ten sam kod obsługuje pliki PSD i AI, guardy czynią puste eksporty bezpiecznymi, a asertywny projekt przykładowy dowodzi całego zestawu, zanim skierujesz go na prawdziwe archiwum.
Gotowy, by pożegnać panel „File Info”?
- Zbuduj sample project przy pomocy
mvn compile exec:java - Przejrzyj przewodnik po scenariuszach użycia w stylu porównania
- Przeczytaj referencję Working with XMP metadata