Když je PDFXCompliance nastavené na 'X-1a', kontroluje HotPDF barvy obsahu úplně na konci jobu: EndDoc zavolá THotPDF.EnsurePDFX1aContentColorSpaces, které odmítne jakýkoli obsah DeviceRGB, CalRGB nebo ICCBased RGB kdekoliv na jakékoli stránce a vyhodí výjimku pojmenující problematický zdroj. Soubor se nikdy nezapíše jako PDF/X-1a dokument, který by tiskárna odmítla
Ta poslední část je to podstatné. PDF/X-1a soubor s jedním zatoulaným RGB logem vypadá na obrazovce naprosto v pořádku, projde letmou revizí a pak selže v preflightu u tiskárny dva dny před tiskovým slotem. Chytit to ve vašem buildu v Delphi, se zprávou, která řekne, která stránka a který obrázek, je o dost levnější než se to dovědět od naštvaného prepress operátora
Proč PDF/X-1a odmítá RGB obsah?
PDF/X-1a odmítá RGB, protože formát slibuje, že každá barva už je finální pro jednu konkrétní CMYK tiskovou podmínku. ISO 15930-1:2001 §6.2.3 omezuje barvy obsahu na DeviceCMYK, DeviceGray a spot colorants, to je Separation a DeviceN prostory, jejichž alternates jsou CMYK nebo Gray. GTS_PDFX OutputIntent vložený do souboru tu tiskovou podmínku pojmenovává, třeba FOGRA39 coated offset, a přijímající workflow má právo poslat čísla rovnou na desky bez jakékoli konverze barev
RGB tu smlouvu láme. Hodnota RGB popisuje barvu relativně k displeji nebo pracovnímu prostoru, ne recept na inkoust, takže někdo po proudu by se musel rozhodnout, jak ji oddělit, a X-1a existuje přesně proto, aby tohle rozhodnutí přijímající straně vzala. ISO 32000-1 §8.6 člení PDF barevné prostory na rodiny device, CIE-based a special a členové RGB se objevují ve více rodinách: DeviceRGB je device prostor, CalRGB a ICCBased se třemi komponentami jsou CIE-based a Indexed nebo Separation prostor může pod sebou schovat RGB base nebo alternate. Kontrola, která hledá jen operátor rg, jich většinu minula. Pozdější vydání PDF/X-1a:2003 (ISO 15930-4) drží totéž pravidlo barev; HotPDF hodnota 'X-1a' zapisuje do XMP paketu identifikaci PDF/X-1a:2001
Pokud váš obsah doopravdy je RGB a má tak zůstat, X-1a je špatný cíl. HotPDF tahle kontrola platí jen pro 'X-1a', takže 'X-3' a 'X-4', které dovolují ICC-based a kalibrované barvy, se nedotkne
Co EnsurePDFX1aContentColorSpaces doopravdy kontroluje
EnsurePDFX1aContentColorSpaces kombinuje příznak zaznamenaný při kreslení s rekurzivním průchodem zdroji každé stránky a v bráně PDF/X běží poslední. EndDoc nejdřív vynucuje obecné požadavky PDF/X: Title musí být nastavený, Trapped musí být 'True', 'False' nebo 'Unknown', musí existovat GTS_PDFX OutputIntent (EnsurePDFXOutputIntent) a každá stránka potřebuje TrimBox nebo ArtBox (EnsurePDFXPageBoxes). Teprve když tyhle kontroly projdou, běží kontrola barev
První cesta je příznak na úrovni dokumentu. RGB color settery HotPDF, vkládání bitmapových obrázků a barevné položky anotací si zaznamenávají použití DeviceRGB už při kreslení, čímž pokrývají inline operátory rg a RG, které se ve zdrojovém slovníku vůbec neobjeví. Druhá cesta projde /Resources každé stránky a prohlédne:
- Pojmenované barevné prostory v
/ColorSpace, včetně zkráceného zápisu inline obrázkůRGBjako synonyma pro DeviceRGB /ColorSpacekaždého Image XObject- Form XObjects a tiling Patterns, rekurzí do jejich vlastních vnořených
/Resources - Shading Patterns a položky ve slovníku
/Shadingstránky, přes/ColorSpacedaného shadingu - Indexed base prostory, Separation a DeviceN alternates a Pattern base prostory, sledované do hloubky zanoření 8
Odmítají se tři věci: DeviceRGB, CalRGB a ICCBased prostory, jejichž profilový stream deklaruje N = 3. Zdrojové slovníky sdílené mezi Form XObjects a patterns navštíví průchod jen jednou, takže si vzájemně odkazující sada formulářů nezacyklí průchod. Metoda je veřejná na THotPDF, ale při běžném použití ji sami nikdy nevoláte, protože to za vás udělá EndDoc
Nakreslení X-1a stránky v Delphi, která kontrolou projde
Souladný HotPDF X-1a dokument potřebuje CMYK OutputIntent, TrimBox na každé stránce a barvy nastavované jen přes CMYK, Gray a spot API. Kostra níže používá profil FOGRA39; AddPDFXOutputIntent bere identifikátor výstupní podmínky, informační řetězec, stream ICC profilu, počet jeho komponent a alternate prostor
var
Pdf: THotPDF;
Profile: TFileStream;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'brochure-x1a.pdf';
Pdf.Title := 'Spring brochure, press edition';
Pdf.Trapped := 'False';
Pdf.PDFXCompliance := 'X-1a';
Pdf.BeginDoc;
Profile := TFileStream.Create('CoatedFOGRA39.icc', fmOpenRead or fmShareDenyWrite);
try
Pdf.AddPDFXOutputIntent('FOGRA39 (ISO 12647-2:2004)',
'Coated FOGRA39 offset', Profile, 4, 'DeviceCMYK');
finally
Profile.Free;
end;
Pdf.CurrentPage.SetTrimBox(0, 0, 612, 792); // povinné na každé stránce
Pdf.CurrentPage.SetCMYKFillColor(0, 0.5, 0.8, 0.1);
Pdf.CurrentPage.Rectangle(72, 600, 468, 120);
Pdf.CurrentPage.Fill;
Pdf.CurrentPage.SetGrayFillColor(0.2); // DeviceGray text
Pdf.CurrentPage.SetFont('Arial', [], 14);
Pdf.CurrentPage.TextOut(72, 560, 0, 'Spring catalog, press edition');
Pdf.EndDoc; // kontrola barev běží tady
finally
Pdf.Free;
end;
end;
Každé volání založené na TColor je v tomhle kontextu past. SetRGBFillColor, SetRGBStrokeColor a SetRGBColor všechny berou GDI barvu a emitují DeviceRGB, takže pomocná rutina napsaná před lety pro reporty orientované na obrazovku zamoří tiskový job v okamžiku, kdy se znovu použije. Používejte SetCMYKFillColor, SetCMYKStrokeColor nebo SetCMYKColor s komponentami v rozsahu 0 až 1, případně Gray ekvivalenty
Spot barvy a CMYK gradienty
Spot colorants jsou v X-1a povolené, dokud je jejich alternate CMYK nebo Gray. RegisterSeparation postaví Separation prostor a vrátí jeho zdrojový název a RegisterAxialGradient vybere barevný prostor shadingu podle počtu komponent, které předáte, přičemž čtyři komponenty znamenají DeviceCMYK
var
SpotCS, Ramp: AnsiString;
begin
// Spot inkoust s přibližným CMYK buildem jako alternatou
SpotCS := Pdf.RegisterSeparation('Corporate Red', 'DeviceCMYK',
[0, 1, 0.8, 0.05]);
Pdf.CurrentPage.SetFillColorSpace(SpotCS);
Pdf.CurrentPage.SetFillColor([1.0]); // tint 100 %
Pdf.CurrentPage.Rectangle(72, 420, 200, 80);
Pdf.CurrentPage.Fill;
// 4 komponenty na stop: shading je DeviceCMYK, ne DeviceRGB
Ramp := Pdf.RegisterAxialGradient(72, 300, 540, 300,
[0, 0, 0, 0], [1, 0.6, 0, 0.2]);
Pdf.CurrentPage.SetFillPattern(Ramp);
Pdf.CurrentPage.Rectangle(72, 260, 468, 80);
Pdf.CurrentPage.Fill;
end;
Týmuž gradientnímu volání dáte tři komponenty a dostanete DeviceRGB shading, který průchod zdroji odmítne pod názvem shading patternu. Totéž platí pro Separation registrovaný s 'DeviceRGB' jako alternatou: spot název vypadá neškodně, ale průchod sleduje alternatu a pod ní najde RGB. Jak se takové spot inkousty skládají, když se prohlížeč nebo RIP vrátí k alternatě, popisuje článek o renderování Separation a DeviceN spot barev v Delphi
Rastrové obrázky potřebují tutéž disciplínu. HotPDF připne Flate komprimované bitmapy k DeviceRGB, zatímco JPEG vložený s icJpeg si drží vlastní počet komponent, takže čtyřkomponentový CMYK JPEG nebo grayscale JPEG je v pořádku a obyčejný RGB JPEG ne. Převádějte podklady na tiskový profil ve vaší imaging pipeline, ještě než se dostanou do PDF
Proč /DefaultRGB nezachrání soubor PDF/X-1a?
/DefaultRGB X-1a nepomůže, protože pravidlo se týká toho, co tisk dostane, ne toho, jestli je RGB charakterizované. Pro PDF/A HotPDF nechá RegisterDefaultColorSpace('DefaultRGB', ...) pohltit použití DeviceRGB: jakmile Default barevný prostor namapuje DeviceRGB na ICC profil, obsah je nezávislý na zařízení a kontrola konzistence PDF/A ho přijme. Vývojáři, kteří tím workflow prošli, tu mívají chuť zkusit stejnou opravu
EnsurePDFX1aContentColorSpaces tohle mapování záměrně ignoruje. Charakterizovaná hodnota RGB je pořád RGB a X-1a OutputIntent je CMYK tisková podmínka, takže někdo by ji stejně musel konvertovat. Pokud si z obou archivačních a tiskových profilů máte zapamatovat jeden rozdíl, ať je to tenhle: PDF/A se ptá, jestli je barva jednoznačná, PDF/X-1a se ptá, jestli už je inkoust
Pořadí kreslení a page setup, který se nepočítá
Protože kontrola běží v EndDoc nad už zapsaným obsahem, nezáleží na pořadí, v jakém věci nastavujete. RGB nakreslené před přiřazením PDFXCompliance nebo před registrací OutputIntent se stejně chytí. To má význam pro kód, který staví stránky ve sdílených rutinách a o výstupním profilu rozhoduje pozdě, někdy podle uživatelského nastavení zvoleného poté, co už polovina dokumentu existuje
Pdf.BeginDoc;
// ... OutputIntent a TrimBox jako dřív ...
Pdf.CurrentPage.SetRGBFillColor(clRed); // legacy helper, emituje DeviceRGB
Pdf.CurrentPage.Rectangle(72, 72, 200, 100);
Pdf.CurrentPage.Fill;
Pdf.PDFXCompliance := 'X-1a'; // rozhodnuto po kreslení
Pdf.EndDoc; // stejně vyhodí: DeviceRGB zaznamenáno
Příznak z doby kreslení má jednu past, kterou stojí za to znát, když si podobnou kontrolu stavíte sami. Každá nová stránka se inicializuje černým graphics state přes SetRGBColor(0), což emituje pár 0 0 0 rg a 0 0 0 RG a kdyby tenhle page-setup boilerplate směl příznak DeviceRGB nastavit, vypadal by každý dokument jako zamořený RGB, a to jak pro tahle kontrolu, tak pro kontrolu konzistence barev PDF/A. HotPDF kolem té inicializace příznak uloží a obnoví, takže se počítá jen barva, kterou skutečně nakreslíte
Jak najít RGB obsah, když EndDoc selže?
Čtěte umístění na začátku zprávy výjimky, protože řekne, která z obou cest problém našla. Zpráva má tvar PDFXCompliance 'X-1a': <where> uses <what>, následuje odkaz na ISO 15930-1 a rada převést do CMYK nebo Gray, případně přepnout na X-3 nebo X-4. Validátor vyhazuje obyčejný Exception při prvním porušení, takže matchujte na text, ne na třídu výjimky
document content uses DeviceRGB (rg/RG operators, RGB images or annotation colours recorded during drawing)znamená, že se spustil příznak z doby kreslení. Číslo stránky není, protože příznak je na úrovni dokumentu a kontroluje se před průchodem. Prohledejte kreslicí kód po voláníchSetRGB*, Flate komprimovaných bitmapách, RGB JPEGech a anotačních barváchTColorpage 3 image XObject /Im2 uses DeviceRGB contentnebopage 1 shading Pattern /P1 uses DeviceRGB contentpřichází z průchodu zdroji a ukazuje na přesný zdrojový klíčuses an ICCBased RGB colour space (N=3)po umístěníColorSpace /...je typický výsledek registrace sRGB profilu přesRegisterICCProfilea výběru přesSetFillColorSpace, cesty, kterou příznak z doby kreslení nevidí- Vnořená umístění se řetězí, třeba
page 2 Form XObject /Fm1 ColorSpace /CS1, takže cestu ze stránky dolů ke zdroji nesoucímu RGB prostor můžete sledovat
try
Pdf.EndDoc;
except
on E: Exception do
begin
if Pos('X-1a', E.Message) > 0 then
LogPrepressFailure(Pdf.FileName, E.Message); // váš vlastní logger
raise;
end;
end;
Protože se hlásí jen první porušení, oprava jobu s několika RGB zdroji je iterativní: opravte, rebuildujte, přečtěte další zprávu. U dávkových jobů se vyplatí logovat celou zprávu pro každý soubor a držet si krátký seznam známých pachatelů, třeba logo bitmapu nebo chart helper, který pořád bere TColor
Kam RGB brána patří ve vašem preflightu
EnsurePDFX1aContentColorSpaces je cílená RGB brána běžící uvnitř vašeho buildu a spáruje se s plným PDF/X-1a preflightem, nikoli ho nahrazuje. Pokrývá rodiny RGB, přes průchod zdroji z /Resources každé stránky i přes příznak z doby kreslení, který si udržují color settery HotPDF pro inline operátory rg a RG; vnořené barevné prostory se sledují do hloubky 8 jako pojistka proti deformovaným cyklům a hlásí se první porušení na EndDoc. Ostatní barevné rodiny jako Lab nebo CalGray jsou věc plného preflightu, takže hotový soubor pusťte jako součást buildu externím validátorem, abyste dostali kompletní verdikt souladu. Širší souvislost výstupu conformance popisuje průvodce výstupem PDF/A, PDF/X a PDF/UA s HotPDF a napojení validátoru do nehlídané pipeline pokrývá automatizace PDF preflight kontrol v Delphi
HotPDF je nativní VCL PDF component pro Delphi a C++Builder s výstupem PDF/X, PDF/A a PDF/UA, s CMYK a spot barevnými API a s podporou ICC OutputIntent. Detaily, licence a trial ke stažení najdete na produktové stránce HotPDF Delphi PDF component