Du har ti tusen kontrakts-PDF-er fra en dusin ulike generatorer, og juridisk avdeling vil ha riktig Author, en korrigert Producer-tekst og et visningsmodus som åpner bokmerke-ruten ved oppstart. En naiv løsning er å laste hver fil, bygge om sidene og skrive en helt ny PDF. Da mister du alle eksisterende objektnumre, historikken for inkrementelle oppdateringer, eventuelle digitale signaturer og den nøye justerte xref som originalverktøyet opprettet, og resultatet blir en fil med ukjent struktur selv om sidene ser like ut. For en metadataendring er det en feil tilnærming
Riktig framgangsmåte er å behandle den innlastede PDF-en som en objektgraf du redigerer på stedet: oppdater /Info-ordboken, /Metadata-strømmen og Catalog, skriv tilbake bare feltene du vil endre, og lagre endringene uten å rekonstruere hele dokumentstrukturen. HotPDF, det native VCL PDF-komponenten for Delphi og C++Builder, tilbyr disse operasjonene via skrive-APIet for allerede innlastede dokumenter. Denne artikkelen viser hvordan du bruker det korrekt, og peker på den vanligste feilen: å oppdatere /Info uten å oppdatere den parallelle XMP-kopien
Samme metadata lagres på to steder, og de kan avvike
PDF lagrer dokumentdata to steder samtidig, og dette er årsaken til de fleste meldinger om at tittelen er endret, men Acrobat fortsatt viser den gamle verdien. Det første er dokumentinformasjonsordboken, det klassiske /Info-objektet med nøkler som /Title, /Author, /Subject, /Keywords, /Creator og /Producer etter ISO 32000-1 §14.3.3. Det andre er en XMP-pakke, et XML-dokument lagret som en strøm hengende under Catalog under /Metadata, definert i §14.3.2 på Adobe XMP-modellen
Begge stedene kan inneholde tittel. Spesifikasjonen krever ikke at de stemmer overens. Moderne visningsprogrammer og de fleste PDF/A-kontroller foretrekker XMP hvis den finnes, og bruker ellers /Info hvis den mangler. Hvis du oppdaterer bare /Info — noe det meste av "endre PDF-metadata"-kode gjør — vil en visning som leser XMP fortsatt vise gammel verdi, og en PDF/A-validering vil påpeke avviket. For en fil som allerede har XMP må du derfor skrive begge steder, først /Info og deretter XMP, for å beholde samsvar. HotPDF gir tilgang til begge delene, og kvaliteten på resultatet avhenger av at du bruker dem sammen
Redigering av /Info-ordboken
Hjelperne på Info-siden er små og forutsigbare. SetLoadedTitle, SetLoadedAuthor, SetLoadedSubject, SetLoadedKeywords, SetLoadedCreator og SetLoadedProducer tar hver sin AnsiString og skriver tilsvarende nøkkel til den innlastede /Info-ordboken, erstatter eksisterende verdi hvis nøkkelen finnes og oppretter den hvis den ikke gjør det. For å fjerne en nøkkel helt — for eksempel en /Creator som avslører intern toolnavnbruk — bruker du RemoveLoadedInfoKey med nøkkelnavnet alene. Ingen av disse metodene endrer XMP; de arbeider bare i /Info-objektet som LoadFromFile fant under parsing av filen
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile('contract-in.pdf', '') > 0 then
begin
Pdf.SetLoadedTitle('Master Services Agreement 2026');
Pdf.SetLoadedAuthor('Legal Department');
Pdf.SetLoadedSubject('Executed contract, retention 7 years');
Pdf.SetLoadedKeywords('contract; MSA; 2026; executed');
Pdf.SetLoadedProducer('Acme Document Pipeline');
Pdf.RemoveLoadedInfoKey('Creator'); // drop the originating tool name
Pdf.SaveLoadedDocument('contract-out.pdf');
end;
finally
Pdf.Free;
end;
end;
Et viktig punkt er at metodene bruker AnsiString. For rene ASCII-titler er dette ikke et problem, men PDF-tekstfelt med tegn utenfor Latin må kodes i henhold til spesifikasjonen, med UTF-16BE med byterekkefølge-merke eller PDFDocEncoding, før du sender dem inn. Biblioteket skriver de eksakte bytene du oppgir til et strengobjekt; det gjetter aldri tegnkoding. Hvis teksten er ren engelsk kan du hoppe over dette, men hvis den inneholder aksenttegn eller tegn fra CJK, må du kode dem bevisst og validere i en faktisk PDF-leser
Omskriving av XMP-pakken
SetLoadedXMPMetadata er andre delen i den doble skrivingen. Send inn hele XMP-pakken som AnsiString, så gjør metoden én av to ting: hvis Catalog allerede peker til en /Metadata-strøm, erstattes innholdet på stedet med samme objektnummer; hvis ingen metadata-strøm finnes, opprettes en ny med /Type /Metadata og /Subtype /XML, tildeler objektnummer og knytter den til Catalog. Begge veier gir et gyldig metadataobjekt som leses av klientene
Du leverer XML selv, så du styrer skjemaet fullt ut, for eksempel dc:title, dc:creator og xmp:CreatorTool. Det betyr frihet, men også ansvar: biblioteket parser eller validerer ikke pakken, og lagrer byte-strømmen ukomprimert uten streamfilter. En ugyldig XMP går lett gjennom API-kallet og dukker opp som metadatafeil senere. Bygg XML-en nøye og hold verdiene helt like dem du har skrevet til /Info, slik at de to bildene aldri kommer ut av synkronisering
const
XMP_TEMPLATE =
'<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>' +
'<x:xmpmeta xmlns:x="adobe:ns:meta/">' +
'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">' +
'<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/">' +
'<dc:title><rdf:Alt><rdf:li xml:lang="x-default">%s</rdf:li></rdf:Alt></dc:title>' +
'<dc:creator><rdf:Seq><rdf:li>%s</rdf:li></rdf:Seq></dc:creator>' +
'</rdf:Description></rdf:RDF></x:xmpmeta><?xpacket end="w"?>';
begin
// After setting the Info dictionary, mirror the same values into XMP:
Pdf.SetLoadedTitle('Master Services Agreement 2026');
Pdf.SetLoadedAuthor('Legal Department');
Pdf.SetLoadedXMPMetadata(
AnsiString(Format(XMP_TEMPLATE,
['Master Services Agreement 2026', 'Legal Department'])));
Pdf.SaveLoadedDocument('contract-out.pdf');
end;
Rekkefølgen er viktig: Info først, XMP etterpå, så lagring — denne modellen bør du ta på alvor. Metodene er uavhengige, men samstemtheten oppstår bare når de fylles med de samme verdiene. Hopper du over XMP for en fil som allerede har XMP-pakke, får du tilbake den tause utdatert-verdien som dette avsnittet handler om å forhindre

Styre hvordan PDF-leseren åpner dokumentet
Tre felt i Catalog avgjør hvordan filen ser ut med en gang leseren åpner den, og alle tre kan settes med én linje på den innlastede grafen. SetLoadedPageMode skriver /PageMode som et navnobjekt: bruk 'UseOutlines' for å åpne bokmerke-panelet, 'UseThumbs' for miniatyrbildet, 'FullScreen' for presentasjonsvisning, eller 'UseAttachments' for vedleggspanelet etter ISO 32000-1 §7.7.3.1 tabell 28. SetLoadedPageLayout skriver /PageLayout på samme måte med verdier som 'SinglePage', 'OneColumn' eller 'TwoColumnLeft' og de øvrige alternativene. Navnene sendes uten ledende skråstrek; biblioteket legger den til når det skriver ut
SetLoadedLanguage skriver Catalog-feltet /Lang, som angir naturlig språk for hele dokumentet i BCP 47, for eksempel 'en-US' eller 'de-DE'. Vær oppmerksom på typeforskjellen som ofte skaper feil: /PageMode og /PageLayout er PDF name-objekter, mens /Lang er en string. HotPDF håndterer dette riktig internt, men hvis du inspeiserer output kan du fortsatt se /PageMode /UseOutlines og /Lang (en-US) side om side og forstå hvorfor /Lang må ha korrekt syntax. /Lang er mer viktig enn det ser ut til, fordi det styrer uttalehåndtering i hjelpemiddeltechnologi og inngår i kravene for PDF/UA-tilgjengelighet
if Pdf.LoadFromFile('handbook.pdf', '') > 0 then
begin
Pdf.SetLoadedPageMode('UseOutlines'); // /PageMode, a name
Pdf.SetLoadedPageLayout('TwoColumnLeft'); // /PageLayout, a name
Pdf.SetLoadedLanguage('en-US'); // /Lang, a string
Pdf.SaveLoadedDocument('handbook-tagged.pdf');
end;
Gi bokmerker nytt navn uten å endre bokmerketreet
Bokmerketitler trenger ofte enkel opprydding, som en skrivefeil i en overskrift eller et kapittel som er endret etter at outline er bygget. SetLoadedOutlineTitle tar en nullbasert indeks for et toppnivå-outline-element og en ny tittel, går gjennom katalogkjeden Catalog → /Outlines → /First → /Next til rett posisjon og erstatter feltet /Title i den gitte posten. Bare tittelen endres; destinasjon, åpent/lukket-state og barne-struktur forblir urørt
if Pdf.LoadFromFile('report.pdf', '') > 0 then
begin
Pdf.SetLoadedOutlineTitle(0, 'Executive Summary');
Pdf.SetLoadedOutlineTitle(1, 'Financial Results');
Pdf.SaveLoadedDocument('report-renamed.pdf');
end;
Navnebytte er trygt fordi det ikke endrer noen strukturelle tellere. Det er sletting av outline-oppføringer som skaper de fleste overraskelser, og derfor nyttig å forstå selv når du bare skal endre navn, fordi det viser hva du ikke bør redigere manuelt. Hver outline-node har et /Count, og i henhold til ISO 32000-1 §12.3.3 er dette ikke antall direkte barn. Det er totalt antall synlige underordnede: et positivt /Count på N betyr N synlige etterfølgende noder, mens negativ verdi betyr at noden har undernoder som er kollapset. Når et toppnivå-element fjernes, kan ikke /Outlines-roten bare reduseres med én; den må beregnes på nytt ved å summere for hvert gjenværende toppnivå-element "én for noden pluss den positive /Count" og hoppe over undernoder under sammenlagte elementer med negativ count. Blir det feil, blir antallet som vises i bokmerkevisningen dratt ut av sync og hopper mer enn én for hver sletting. Navneendring unngår akkurat dette, og er derfor et godt argument for å bruke den målrettede hjelpemetoden i stedet for direkte ordbokhåndtering
Slik lagres endringen på stedet
Hver metode i denne listen endrer kun objektmodellen i minnet, og ingenting skrives før SaveLoadedDocument kjøres. Grunnen til at dette er effektivt er at lagring ikke regenererer hele dokumentet, men bevarer eksisterende objektnummer og den strukturen HotPDF fant da filen ble lastet inn, og skriver tilbake samme graf med et lite antall endrede og nylig opprettede objekter. Dette er grunnen til at metadataarbeid kan gjøres uten ombygging av hele filen, og det samme in-place-prinsippet brukes også i mekanismene for objektstrømmer og inkrementelle oppdateringer Når kildefiler kommer fra Word eller andre kontorpakker, har de egne layout-mønstre som det er verdt å kjenne til før redigering; artikkelen om hybride kryssreferansestrømmer i Office PDF går gjennom disse mønstrene og hva som overlever en rundtur
Det er to viktige grenser du må ta med. For det første er dette en in-place-modell, ikke en redaksjon- eller sanitiseringsfunksjon: fjerning av en Info-nøkkel fjerner bare den nøkkelen, men eldre verdier kan fortsatt ligge i en tidligere inkrementell oppdatering av samme fil. Hvis du trenger virkelig sletting av sensitiv metadata, må du bruke en tyngre prosess. For det andre lagres XMP helt bokstavelig, biblioteket bruker XML-en din direkte uten egen validering, så ved eksport mot PDF/A eller strenge validatorer må du bygge fra en kjent mal og verifisere resultatet etterpå. Brukt innenfor disse rammene er in-place-redigering av metadata riktig nivå på verktøy, fordi det retter de små feilene og lar de fleste andre deler av filen stå urørt slik originalprodusenten skrev den
The loaded-document write API shown here ships with the standard HotPDF Component for Delphi and C++Builder, alongside the full set of metadata, outline, and Catalog editing methods.