Volledig werkend voorbeeld beschikbaar op GitHub:
read-and-write-xmp-in-psd-ai-files-java
De oude manier was pijnlijk
Stel je de archiefopruiming voor waar niemand zich vrijwillig voor aanmeldt. Een map met PSD‑masters en AI‑bronnen heeft rechtenvermeldingen en trefwoorden nodig voordat ze het DAM binnenkomen. De routine: een bestand openen in Photoshop, File Info openen, het copyright typen, de trefwoorden typen, opslaan, sluiten, volgend bestand. Elke keer opslaan rendert een gelaagd bestand opnieuw alleen om een paar strings van xmp‑metadata te wijzigen. Het archief dat me deze les leerde was een map met ongemarkeerde Illustrator‑bestanden die niemand kon doorzoeken; we losten het op met een lus, niet met meer geduld.
Vermenigvuldig die routine met een heel archief en het wordt geen taak meer maar een project. Slechter nog, het is niet controleerbaar: niemand kan later bewijzen welke bestanden zijn verwerkt, en de bestanden die zijn overgeslagen zien er identiek uit totdat een licentievraag ze aan het licht brengt. De paneelroute koppelt bovendien stilzwijgend gegevensinvoer aan ontwerpgereedschap. Wie metadata moet aanpassen, heeft een Adobe‑licentie nodig, een werkstation dat gelaagde masters comfortabel kan openen, en het geduld om te wachten op opslagen die het artwork opnieuw renderen alleen om strings te wijzigen.
De werkelijke kosten van handmatig doen: metadata die handmatig wordt aangepast, is metadata die later door niemand kan worden geverifieerd; het proces laat geen spoor achter behalve vermoeide ontwerpers.
Er is een betere manier
GroupDocs.Metadata voor Java leest en schrijft het XMP‑pakket direct. Cast getRootPackage() naar IXmp en het pakket, de schema’s en de arrays zijn gewone Java‑objecten, identiek voor PSD‑ en AI‑containers, zonder Adobe‑software. De documentatie vermeldt meer dan 170 formaten achter dezelfde API.
Voordat we beginnen, heb je nodig:
- JDK 8 of later met Maven
- GroupDocs.Metadata voor Java 24.7 (verkrijg een tijdelijke licentie)
- Een PSD‑ of AI‑bestand om op te oefenen
Voeg de afhankelijkheid en de GroupDocs‑repository toe aan je pom.xml:
mvn dependency:get -Dartifact=com.groupdocs:groupdocs-metadata:24.7
De companion repository levert een kant‑klaar pom.xml plus voorbeeldbestanden van beide formaten, en bevestigt elke stap hieronder.
De nieuwe manier: vier bewerkingen in Java
Stap 1 — Zie wat een bestand bevat
De snapshot dumpt het pakket en elk schema in één LinkedHashMap, waarbij de volgorde die het bestand declareert behouden blijft.
// 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;
De kleine put‑ en collect‑helpers geven de voorkeur aan getInterpretedValue() zodat datums leesbaar aankomen, en de op Specification gebaseerde sweep vangt leverancierspakketten op. De repository‑versie doorloopt zeven schema’s; de vorm blijft hetzelfde.
Stap 2 — Lees de velden die vragen beantwoorden
Licenties vragen om dc:rights. Zoeken heeft dc:subject nodig. Beide leven in Dublin Core, en de scoped read kost negen velden, geen boomdoorloop.
// 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);
}
Het Photoshop‑schema werkt op dezelfde manier via getypte getters (getCity(), getCredit(), getColorMode() en nog vijf), die de psd‑metadata‑velden dekt die Bridge‑ en Lightroom‑filters lezen. In de repository wikkelt die lezer elke getter in een null‑veilige helper, zodat een schaars gevuld bestand lege strings teruggeeft in plaats van verrassingen. Dat detail is belangrijker dan het lijkt: het hele punt van het automatiseren van een archief is dat vreemde bestanden door de lus blijven stromen in plaats van die te laten stoppen.
Beide scoped reads delen een kostenprofiel dat het waard is te benoemen. Eén bestand openen, één schema, geen boomdoorloop. Plaats ze in request‑handlers en poorten; bewaar de volledige snapshot voor ingestie‑taken die alles opslaan.
Stap 3 — Stempelen en taggen zonder Adobe te openen
De writers maken alles wat ontbreekt guard‑create, waardoor ze veilig zijn voor verse exports die helemaal geen pakket hebben.
// 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);
Trefwoorden volgen hetzelfde patroon met één aanroep, waarbij de hele bag wordt geschreven als een Unordered‑array:
// 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 sluit de lus: het leest de outputs opnieuw en controleert of de copyright‑string en het eerste trefwoord daadwerkelijk de save hebben overleefd.
Die afsluitende assert verdient een zin van pleitbezorging. Metadata‑writes falen stilletjes wanneer ze falen; het bestand wordt opgeslagen, de bytes veranderen, en de waarde die je wilde schrijven is er simpelweg niet omdat een schema‑object verouderd was of een pad naar het origineel wees. Een read‑back na elke write‑run kost één extra open per bestand en zet “het script is klaar” om in “de waarden zijn aanwezig”, wat de uitspraak is die een archiefbeheerder echt wil. Houd het in productie, niet alleen in de demo.
Hoe maken trefwoorden assets eigenlijk vindbaar?
Zoektools lezen geen pixels; ze lezen dc:subject. Bridge, DAM‑indexers en stock‑platformen behandelen die bag als de vocabulaire van het asset, dus een bestand zonder trefwoorden komt simpelweg nooit overeen met een query. Het schrijven van de bag als een Unordered XmpArray, zoals AddKeywords doet, is wat een asset van onzichtbaar naar vindbaar verplaatst, en de write kost één save.
Zij‑aan‑zij: Voor vs. Na
| Voor (paneelbewerking) | Na (Java‑pijplijn) | |
|---|---|---|
| Gereedschap | Photoshop of Bridge per bestand | Eén Maven‑project, geen Adobe‑licentie |
| Dekking | Velden die het paneel toont | Elk schema plus leverancierspakketten |
| Herhaalbaarheid | Afhankelijk van wie klikt | Zelfde lus, zelfde resultaat, controleerbaar |
| XMP‑loze bestanden | Paneelgedrag varieert | Beveiligingen maken het pakket en de schema’s |
| Verificatie | Vertrouwen | Bevestigde teruglezen per bestand |
De verificatierij beslist voor archieven: een script dat zijn eigen writes bewijst, is het verschil tussen “we hebben de bestanden getagd” en “we kunnen het je laten zien”.
Praktijkvoorbeeld: De overdracht van het bureau
Een studio ontvangt gemengde PSD‑ en AI‑leveringen van drie bureaus, elk met hun eigen metadata‑discipline. Hun intake‑taak draait nu de snapshot bij aankomst, markeert bestanden waarvan dc:rights leeg is, stempelt ze met de gecontracteerde rechtenregel, en schrijft de campagne‑trefwoordset. dezelfde lus dient beide formaten omdat er in de code niets een container noemt, en Adobe Illustrator‑metadata die leeg arriveert laat de intake getagd en doorzoekbaar achter.
Het vervolg effect is het deel dat de studio niet had voorspeld: bureaubeoordelingskaarten. Omdat de intake‑taak logt welke leveringen met lege rechtenvelden aankomen, ziet inkoop nu welke leveranciers schone metadata leveren en welke op de klant vertrouwen om het te fixen. Het gesprek met de grootste overtreders kostte één grafiek.
Wat kun je nog meer doen met GroupDocs.Metadata?
- EXIF en IPTC in dezelfde bestanden: PSD’s dragen drie metadata‑standaarden; dezelfde bibliotheek leest de andere twee via hun eigen pakketten, dus een volledig asset‑profiel is twee reads verwijderd.
- 170+ andere formaten: het identieke
Metadata‑ingangspunt dient Office, PDF, audio‑ en videobestanden, waardoor één intake‑taak een heel gemengd archief kan dekken. - Eigenschap zoeken:
findPropertiesmet eenSpecificationdoorzoekt elk bestand op welke predicaat je ook definieert, van rechtencontroles tot aangepaste‑veld jacht.
Conclusie
Wat vroeger een per‑bestand paneelroutine was, is nu vier Java‑bewerkingen: snapshot, scoped read, eigendomstempel, trefwoord‑write. dezelfde code dient PSD‑ en AI‑bestanden, guard‑mechanismen maken lege exports veilig, en het bevestigde voorbeeldproject bewijst de volledige set voordat je het op een echt archief richt.
Klaar om het File Info‑paneel te laten vervallen?
- Bouw het voorbeeldproject met
mvn compile exec:java - Doorloop de comparison‑style use case guide
- Lees de Working with XMP metadata referentie