PDFlibPas vyrábí tiskové soubory PDF/X z Delphi jediným voláním TPDFlib.SetPDFXMode, které vybere PDF/X-1a:2003, PDF/X-3:2003 nebo PDF/X-4. Volání zapíše identifikaci XMP pdfxid, přidá výstupní záměr GTS_PDFX, deklaruje /Trapped /False, fixuje verzi PDF a od té chvíle odmítá kreslicí volání, kterým vybraný díl zakazuje. CheckFileCompliance s testem 3 zkontroluje uložený soubor
To je krátká odpověď. Ta delší má význam, protože tiskárny neodmítají soubory za to, že jsou ošklivé, odmítají je v preflightu, obvykle v pátek, obvykle kvůli něčemu, co generující kód mohl zachytit: RGB logo v zakázce X-1a, font odkázaný místo vloženého, stránka bez formátu ořezu. PDF/X existuje proto, aby z nich udělalo chyby strukturální, nikoli vizuální, a na straně knihovny jde o to, abyste je vůbec nevytvořili
Který díl PDF/X si má aplikace v Delphi vybrat?
Vyberte PDF/X-4, pokud příjemce říká něco jiného, a PDF/X-1a, když to říká. Tři díly se liší přesně ve třech osách — barva, průhlednost a základní verze PDF — a každá osa se promítne do jedné brány uvnitř PDFlibPas:
- PDF/X-1a:2003 (ISO 15930-4): syntaxe PDF 1.4, pouze barvy CMYK, šedá a spot, žádné barvy založené na ICC, žádná průhlednost. Soubor je už rozseknutý do tiskových barev, takže tiskárna neprovádí žádnou konverzi barev
- PDF/X-3:2003 (ISO 15930-6): stále PDF 1.4 a stále bez průhlednosti, ale barevně řízené prostory jsou povolené a device RGB se přijímá, když výstupní záměr sám popisuje RGB podmínku
- PDF/X-4 (ISO 15930-7): syntaxe PDF 1.6 s živou průhledností a volitelným obsahem (vrstvami). To je díl, pro který jsou moderní RIPy stavěné, protože zplošťování průhlednosti na výstupu bylo zdrojem velké části staré bolesti X-1a
X-1a je stále všude v reklamní produkci a ve starších tiskových tocích, které chtějí soubor, jenž vyexponují bez přemýšlení. X-4 je lepší inženýrská volba, kdykoli to tiskárna přijme: průhlednost zůstane nedotčená a barevná rozhodnutí se dějí na RIPu s reálným tiskovým profilem, ne ve vašem kódu. Čísla módů jsou 1, 2 a 3, a GetInformation(203) ohlásí aktivní mód zpět. PDFlibPas navíc definuje vyšší čísla módů pro rodinu PDF/X-6 na PDF 2.0, ta ale následují jiná pravidla pro verzi a výstupní záměr a tady jsou mimo rozsah
Co SetPDFXMode zapíše do souboru
TPDFlib.SetPDFXMode obstará identifikaci a pevnou kostru, kterou čtečka PDF/X kontroluje jako první, takže aplikační kód musí dodat jen reálný tiskový profil a obsah. Konkrétně úspěšné volání udělá čtyři věci:
- Zapíše řetězec edice do XMP jako
pdfxid:GTS_PDFXVersion(PDF/X-1a:2003,PDF/X-3:2003neboPDF/X-4). Edice 2003 identifikují díl tímto řetězcem úplně, takže se žádná samostatná vlastnost vyhovování nezapisuje - Přidá výstupní záměr, pokud ho dokument nemá, a nastaví jeho podtyp na
/S /GTS_PDFX, podtyp, který čtečky PDF/X hledají (slovník výstupního záměru definuje ISO 32000-1 §14.11.5) - Nastaví
/Trapped /Falsev informačním slovníku dokumentu, protože zapisovač nikdy netrapuje a PDF/X vyžaduje, aby stav trappingu byl deklarovaný, nikoli neznámý - Fixuje základnu verze: 1.4 pro X-1a a X-3, 1.6 pro X-4
Dvě další opravy se dějí při ukládání. Každá stránka bez TrimBox dostane jeden rovný svému MediaBox, protože PDF/X vyžaduje deklarovaný hotový formát na každé stránce (ISO 32000-1 §14.11.2 pokrývá hranice stránek), a anotace dostanou příznak tisku, který norma očekává. Fallback na TrimBox je pojistka, ne layoutové rozhodnutí. Zakázka do ořezu potřebuje skutečný trim box uvnitř většího media boxu a průvodce výchozími hodnotami TrimBox, BleedBox a CropBox v PDFlibPas rozebírá, jak tyto boxy nastavit a jak vás dědičnost může překvapit
uses
PDFlibrary;
procedure BuildX1aAd(const OutFile, PressProfile: string);
var
Pdf: TPDFlib;
begin
Pdf := TPDFlib.Create;
try
if Pdf.SetPDFXMode(1) <> 1 then // 1 = PDF/X-1a:2003
raise Exception.CreateFmt('PDF/X mode refused (error %d)',
[Pdf.LastErrorCode]);
// Nahraďte výchozí profil skutečnou tiskovou podmínkou
if Pdf.LoadOutputIntentProfile(PressProfile, 'DeviceCMYK') <> 1 then
raise Exception.Create('Could not load the CMYK output profile');
// Embed = 1 vloží celý fontový program; PDF/X nepřijme 0
if Pdf.AddTrueTypeFont('Arial {1252}', 1) = 0 then
raise Exception.Create('Font could not be loaded for embedding');
Pdf.SetTextSize(24);
Pdf.SetFillColorCMYK(0, 1, 1, 0); // procesová červeň, žádné RGB
Pdf.DrawText(72, 720, 'Spring catalog, page 1');
Pdf.SaveToFile(OutFile);
finally
Pdf.Free;
end;
end;
Pořadí v té skice je záměrné. LoadOutputIntentProfile nahrazuje profil výstupního záměru, který už existuje, takže musí běžet poté, co SetPDFXMode jeden vytvořil. Volání také neumí záměr vykouzlit z ničeho: na dokumentu bez výstupního záměru prostě vrátí 0
Proč je třeba výchozí výstupní záměr nahradit?
Výstupní záměr, který SetPDFXMode přidává pro módy 1 až 3, deklaruje DeviceCMYK, ale ICC bajty za ním jsou přibalený sRGB profil knihovny s přepsaným počtem komponent na 4. Ta výchozí hodnota tu je kvůli zpětné kompatibilitě a stačí, aby byl soubor strukturálně PDF/X, jenže vložený profil nepopisuje žádný tisk. Preflight nástroj, který koukne do hlavičky profilu, uvidí RGB profil v ceduli CMYK a tiskař, který se na záměr spoléhá při proofu, dostane nesmysl
Takže LoadOutputIntentProfile(FileName, 'DeviceCMYK') berte jako povinnost pro skutečnou tiskovou práci a předejte ICC profil, který váš tiskový dodavatel jmenuje pro papír a stroj. TPDFlib.LoadOutputIntentProfile vymění proud DestOutputProfile a aktualizuje /N, zbytek slovníku záměru nechá tak, jak byl zapsán. Konkrétně identifikátor výstupní podmínky a popisné řetězce výchozího záměru stále nesou hodnoty ve stylu sRGB, takže pokud vaše tiskárna páruje podle identifikátoru a ne podle vloženého profilu, ověřte si před odesláním, co kontrolují. To je skutečná mezera ve výchozích hodnotách z doby 2003, ne chyba vašeho kódu
Past číslo jedna: verze, kterou jste nevybrali
Nový dokument PDFlibPas startuje na zapisovačově výchozí verzi PDF 1.5, což je nad základnou 1.4, kterou PDF/X-1a a PDF/X-3 vyžadují. TPDFlib.SetPDFXMode to v běžném případě řeší potichu: pokud ukládací verze není uzamčená, sníží verzi dokumentu na základnu dílu a pokračuje. První implementace místo toho odmítala a každé SetPDFXMode(1) na čerstvém dokumentu vracelo 0 — dobrá ukázka pravidla, které je na papíře správné a v praxi k ničemu
Odmítnutí pořád existuje pro ten jediný případ, kdy je na místě. Pokud něco dřívějšího zavolalo LockSaveVersion s verzí nad základnou, vrátí SetPDFXMode 0 s LastErrorCode 601, protože volající verzi uzamkl záměrně a knihovna to nepřebije. Ve sdíleném kódu nastavení dokumentu, kde pomocník zamyká verzi z nesouvisejících důvodů, přesně tady zakázka X-1a umírá:
Pdf := TPDFlib.Create;
try
Pdf.LockSaveVersion('1.7'); // nastavil generický pomocník s firemními výchozími hodnotami
if Pdf.SetPDFXMode(1) = 0 then
// LastErrorCode = 601: 1.7 je uzamčeno, PDF/X-1a potřebuje 1.4.
// U tiskových zakázek zámek přeskočte. PDF/X-4 tady není útočiště:
// jeho základna 1.6 je také pod zámkem 1.7 a selhává stejně.
LogError('PDF/X refused, error %d', [Pdf.LastErrorCode]);
finally
Pdf.Free;
end;
Táž brána vysvětluje související omezení. Mód PDF/X je přepínač při tvorbě dokumentu: SetPDFXMode funguje na novém dokumentu a na dokumentu načteném ze souboru vrací 0, protože knihovna nemůže ručit za obsah, který nenapsala. Převod existujícího PDF na PDF/X je jiná práce, která potřebuje prohlídku a opravy, ne příznak
Past číslo dvě: brány, které odmítají potichu
Jakmile je mód PDF/X aktivní, PDFlibPas odmítá každé obsahové volání, kterému vybraný díl zakazuje, v okamžiku volání, místo aby nechal soubor později propadnout preflightem. Odmítnutí pokrývají plnění a tahy device RGB (celé X-1a; u X-3 a X-4, pokud výstupní záměr není RGB), ICC barvy v X-1a, průhlednost a blend módy v X-1a a X-3, volitelný obsah v X-1a a X-3, JavaScriptové akce, vložené přílohy, obrazový filtr LZW, fonty Standard 14, které by zůstaly nevložené, a šifrování veřejným klíčem. Heslové šifrování přes Encrypt se při tvorbě neguje, ale validátor označí jakýkoli zašifrovaný soubor, takže tiskové zakázky nechávejte nešifrované
Co odmítnutí nesdílejí, je chybový kód — a v tom je past. Brány barevných prostorů v SetFillColor, SetLineColor, u volání ICC barev a EncryptPublicKey nastaví LastErrorCode na 601, knihovní kód vyhovování, který používají i brány PDF/A. Brány průhlednosti, JavaScriptu, příloh, LZW a AddStandardFont jen vrátí 0 a LastErrorCode nechají netknuté, což znamená, že může stále držet hodnotu z dřívějšího volání. Kód, který po dávce kreslicích volání kontroluje jen LastErrorCode, přehlédne polovinu odmítnutí, takže kontrolujte každou návratovou hodnotu:
procedure Require(Ok: Integer; const What: string);
begin
if Ok = 0 then
raise EPrintConformance.CreateFmt('%s refused under PDF/X', [What]);
end;
Require(Pdf.SetFillColorCMYK(0, 0, 0, 1), 'CMYK fill');
Require(Pdf.SetTransparency(40), 'transparency'); // 0 v X-1a / X-3
Require(Pdf.AddLinkToJavaScript(72, 72, 120, 20,
'app.alert(1)', 0), 'JavaScript link'); // 0 v každém dílu
Fonty si zaslouží vlastní varování. AddStandardFont vrací 0 pod PDF/X, protože knihovna obrysy Standard 14 nedodává a nemůže je vložit. AddTrueTypeFont je jiný případ: v módu PDF/A povýší Embed = 0 na plné vložení za vás, ale v módu PDF/X ne, takže odkázaný systémový font se dostane do souboru a zachytí ho jen validátor. Předejte 1 (plně) nebo 2 (podmnožinu) sami, nebo zavolejte jednou při nastavení SetEmbedAllFonts(1), aby se náhodná 0 neprošla
Jak ověřit soubor PDF/X, než jde do tisku?
Spusťte CheckFileCompliance s ComplianceTest = 3 na uloženém souboru. TPDFlib.CheckFileCompliance vrací 0, když nezaznamenal žádné nálezy, jinak handle seznamu řetězců, jehož položky jsou řádky s prefixem PDFX-. Audit PDF/X čte soubor stejným streamovacím čtečkem jako preflight PDF/A a PDF/UA v PDFlibPas a kontroluje pravidla, která tiskový preflight kontroluje jako první:
- Soubor není zašifrovaný, XMP nese známé
GTS_PDFXVersiona verze PDF nepřekračuje základnu dílu - Existuje právě jeden výstupní záměr, jeho podtyp je
GTS_PDFXa nese cílový profil a identifikátor výstupní podmínky - Informační slovník deklaruje
/Trapped - Každá stránka má TrimBox ležící uvnitř MediaBox a BleedBox, je-li přítomen, obklopuje TrimBox
- Každý font použitý na stránce má vložený program, přičemž fonty Type0 se kontrolují přes jejich potomka
- Žádné zakázané typy anotací (RichMedia, Screen, 3D, Movie, Sound, FileAttachment), žádná otevírací akce JavaScript ani JavaScript na úrovni dokumentu, žádné vložené soubory a žádný filtr LZWDecode kdekoli v objektovém grafu
function PreflightPDFX(Pdf: TPDFlib; const FileName: string;
Report: TStrings): Boolean;
var
ListId, I: Integer;
begin
ListId := Pdf.CheckFileCompliance(FileName, '', 3, 0); // 3 = PDF/X
Result := ListId = 0;
if Result then
Exit;
try
for I := 1 to Pdf.GetStringListCount(ListId) do // položky jsou od 1
Report.Add(Pdf.GetStringListItem(ListId, I));
finally
Pdf.ReleaseStringList(ListId);
end;
end;
Mějte jasno v tom, co ten průchod znamená. Validátor PDFlibPas audituje strukturální pravidla uvedená výše a právě ta odchytají chyby generátoru. Není to barevně věrný preflight: nekontroluje celkové pokrytí barvou, rozlišení obrazů ani to, zda vložený profil odpovídá podmínce, kterou vaše tiskárna jede. Použijte ho jako bránu ve svém buildu nebo exportní pipeline a strojově specifické kontroly nechte na preflight profilu tiskárny — ten si stejně pustí
FAQ
Podporuje PDFlibPas průhlednost PDF/X-4?
Ano. V SetPDFXMode(3) dovoluje PDFlibPas průhlednost, blend módy a skupiny volitelného obsahu a zapíše soubor PDF 1.6. Táž sada volání vrací 0 pod PDF/X-1a a PDF/X-3
Umí PDFlibPas převést existující PDF na PDF/X?
Ne. SetPDFXMode se vztahuje jen na dokumenty vytvořené v aktuální relaci TPDFlib a pro načtený soubor vrací 0. Jakékoli existující PDF ale můžete auditovat pomocí CheckFileCompliance a testu 3
Jaký chybový kód vrátí odmítnuté volání PDF/X?
Odmítnutí barevných prostorů a šifrování veřejným klíčem nastaví LastErrorCode na 601. Ostatní brány, jako průhlednost, JavaScript a fonty Standard 14, jen vrátí 0, takže vždy testujte výsledek funkce
Výstup PDF/X, validátor PDF/X a zbytek tiskového a archivačního nářadí jsou součástí PDFlibPas, nativní Object Pascal PDF knihovny losLab pro Delphi. Na produktové stránce PDFlibPas Delphi PDF Library najdete edice, platformy a kompletní referenci API