Tehnički članak

Dosljednost spot boja NChannel u Delphiju s HotPDF-om

Preša vraća posao: ista se spot boja odvojila na dvije ploče. HotPDF to sprječava već pri stvaranju: NChannel zapisuje kao ISO 32000-2 petoelementarni DeviceN oblik, a za svako spot ime drži jedan kanonski alternativni prostor i tint transformaciju za cijeli dokument, odbijajući drugu, proturječnu definiciju umjesto da je ispiše

NChannel nije ime porodice prostora boja

Prvo što treba zaboraviti jest samo ime. NChannel nije porodica prostora boja onako kako su Separation i DeviceN porodice. ISO 32000-2 §8.6.6.5 opisuje ga kao podtip DeviceN-a, pa sukladan NChannel prostor zapisuje se kao petoelementarni niz [/DeviceN names alternateSpace tintTransform attributes], a rječnik atributa nosi /Subtype /NChannel. Niza [/NChannel ...] u specifikaciji nema. Ako ste ga ikada ručno gradili i gledali kako ga RIP prešućuje, evo zašto

HotPDF zapisuje NChannel prostor kao petoelementarni DeviceN niz čiji rječnik atributa nosi Subtype NChannel zajedno s unosima Process, Colorants i MixingHints, jer niz s imenom porodice NChannel u specifikaciji uopće ne postoji
Sukladan NChannel prostor je DeviceN niz s rječnikom atributa, pa zapisivač emitira samo taj oblik dok čitač i dalje prihvaća zastarjeli token

HotPDF se tu jednom pogriješio i to je potom ispravio, što vrijedi reći jasno jer oblikuje kako se komponenta danas ponaša. Starija izdanja HotPDF-a emitirala su oblik s imenom porodice. THotPDF.RegisterNChannelColorSpace sada emitira isključivo standardni oblik DeviceN plus atributi, a budući da je NChannel podtip stigao s PDF 1.6, proizvodna ulazna točka vrata je na RequirePDFVersion(pdf16, ...) i jednostavno odbija starije ciljeve. Rendererska strana namjerno je popustljivija od zapisivača: HPDFResolveColorSpace i dalje prihvaća zastarjeli token /NChannel kao DeviceN porodicu, pa datoteke starog zapisivača i dalje renderiraju, ali sve što HotPDF ispisuje natrag koristi standardno kodiranje. Popustljivo na ulazu, strogo na izlazu prava je asimetrija ovdje, jer vaš čitač mora podnijeti datoteke koje nije stvorio, dok vaš zapisivač nema takvo opravdanje

Zašto jedno spot ime završi na dvije ploče?

Jer je ime spot bojila identitet ploče u mjerilu dokumenta, a ne lokalni argument. Dva poziva koji oba imenuju Orange, ali predaju drugačiji alternativni prostor, ili isti alternativni prostor s drugačijom tint transformacijom, opisuju dvije različite boje koje slučajno dijele oznaku. RIP koji gradi separacije nema načina da to pomiri, pa čini jedinu pošten stvar i daje vam dvije ploče. HotPDF stoga održava kanonski potpis po bojilu u mjerilu dokumenta. RegisterSpotColorantDefinition sastavlja taj potpis od alternativnog prostora boja i oblika tint funkcije, i kroz njega prolazi svaki RegisterSeparation, RegisterSeparationFunc, RegisterSeparationLUT i NChannel definicija spota. Kada se druga definicija ne slaže, poziv podiže iznimku umjesto da tiho registrira drugu varijantu, a poruka je namjerno konkretna o načinu pogreške, jer je alternativa otkriti je na probnoj ploči tri tjedna kasnije

Svaki poziv registracije spota u HotPDF-u prolazi kroz RegisterSpotColorantDefinition, koji bilježi jedan kanonski alternativni prostor i tint potpis po imenu bojila za dokument i podiže iznimku kada stigne druga, neslagajuća definicija istog imena
Jedno ime, jedan potpis: druga, proturječna definicija spota odbija se pri stvaranju umjesto da se otkrije na probnoj ploči
// Orange je već registriran na DeviceCMYK s tint
// transformacijom 0 / 0.55 / 1 / 0 pri punoj tinti.
Conflicting := Pdf.RegisterExponentialFunction(
  Domain1, NoInk, OtherOrangeCMYK, 1, []);
try
  Pdf.RegisterSeparationFunc('Orange', 'DeviceCMYK', Conflicting);
except
  on E: Exception do
    // 'Spot colourant "Orange" has inconsistent alternate colour
    //  space or tint definition in this document'
    LogPrepressWarning(E.Message);
end;

Razdvajanje glavnih imena na process i spot

Potpuni NChannel mora za svako svoje glavno ime bojila odgovoriti točno jednom, kao procesna komponenta ili kao spot bojilo. Napredna varijanta RegisterNChannelColorSpace prima glavna ColorantNames, ProcessColorantNames, alternativni prostor, ukupnu tint transformaciju, polje zapisa THPDFNChannelSpotColorant i neobavezan redoslijed tiska. Svaki zapis spota nosi svoje ime, vlastitu Separation tint transformaciju s jednim ulazom, neobaveznu solidnost i neobaveznu dot-gain funkciju. Ukupna tint transformacija mora preslikavati N ulaza na broj komponenta alternativnog prostora; svaka spot tinta mora preslikavati jedan ulaz na isti broj

const
  Colorants: array[0..4] of AnsiString =
    ('Cyan', 'Magenta', 'Yellow', 'Black', 'Orange');
  ProcessNames: array[0..3] of AnsiString =
    ('Cyan', 'Magenta', 'Yellow', 'Black');
  Order: array[0..4] of AnsiString =
    ('Yellow', 'Magenta', 'Cyan', 'Orange', 'Black');
  Domain5: array[0..9] of Single = (0, 1, 0, 1, 0, 1, 0, 1, 0, 1);
  Range4: array[0..7] of Single = (0, 1, 0, 1, 0, 1, 0, 1);
  Domain1: array[0..1] of Single = (0, 1);
  NoInk: array[0..3] of Single = (0, 0, 0, 0);
  OrangeCMYK: array[0..3] of Single = (0, 0.55, 1, 0);
  GainC0: array[0..0] of Single = (0);
  GainC1: array[0..0] of Single = (1);
var
  Pdf: THotPDF;
  Spots: array[0..0] of THPDFNChannelSpotColorant;
  CSName: AnsiString;
begin
  Pdf.Version := pdf20;
  Pdf.BeginDoc;
  Spots[0].Name := 'Orange';
  Spots[0].TintTransform := Pdf.RegisterExponentialFunction(
    Domain1, NoInk, OrangeCMYK, 1, []);
  Spots[0].HasSolidity := True;
  Spots[0].Solidity := 0.82;
  Spots[0].DotGainFunction := Pdf.RegisterExponentialFunction(
    Domain1, GainC0, GainC1, 1, []);
  CSName := Pdf.RegisterNChannelColorSpace(Colorants, ProcessNames,
    'DeviceCMYK',
    Pdf.RegisterPostScriptFunction(Domain5, Range4,
      '{ pop pop pop pop pop 0 0 0 0 }'),
    Spots, Order);

Iz tog poziva HotPDF emitira rječnik atributa koji traži specifikacija: /Subtype /NChannel, rječnik /Process čiji je /ColorSpace procesni prostor a čiji /Components nabraja procesna imena u redoslijedu komponenta tog prostora, rječnik /Colorants koji drži pravi niz [/Separation name alternate tintfn] za svaki spot, i rječnik /MixingHints koji nosi /Solidities, /PrintingOrder i /DotGain kada ste ih dostavili. Vraćeno ime resursa ide u SetFillColorSpace ili SetStrokeColorSpace točno kao jednostavniji prostori obrađeni u članku o renderiranju spot boja Separation i DeviceN

HotPDF razdvaja glavna imena bojila NChannel prostora u rječnik Process za četiri CMYK komponente i rječnik Colorants koji drži po jedan Separation niz za svaki spot, uz provjeru svake arnosti prije pisanja
Svako glavno ime preuzeto je točno jednom, a ukupna tint transformacija, tinte po spotu i redoslijed tiska sve su ovjerene prije nego što se ijedan objekt emitira

Što provjera dosljednosti stvarno odbija?

Odbija strukturnu nekonzistentnost unutar prostora, i to prije nego što se ijedan objekt zapiše. Imena bojila moraju biti jedinstvena i ne smiju biti prazna, All ili None. Procesne i spot definicije zajedno moraju pokriti glavna imena točno, bez bojila koje se pojavljuje u obje uloge i bez onog koje ostaje nedefinirano. Kada je alternativni prostor DeviceCMYK, procesne komponente moraju biti Cyan, Magenta, Yellow, Black tim redom, a broj procesnih imena mora odgovarati broju komponenta alternativnog prostora. Svaka tint transformacija i dot-gain funkcija moraju biti indirektni funkcijski objekt s pravom arnosti ulaza i izlaza. Solidnost mora biti konačna vrijednost unutar 0..1. Redoslijed tiska mora biti prazan ili potpuna permutacija glavnih imena, nikada djelomičan popis. Ono što ne čini jest suditi boju: ništa ovdje ne provjerava da vaša tint transformacija za Orange stvarno liči na boju u kantici, da je njezina CMYK izvedba razumna zamjena ili da se solidnost koju ste dostavili poklapa s izmjerenim ponašanjem na podlozi. To su pitanja tiska i mjerenja, a komponenta nema mandat da ih odgovara. Jednostavnija varijanta samo za process po dizajnu je još stroža: proizvodi NChannel samo s procesom i namjerno odbija primati spot imena, jer bi upis spota u polje imena bez odgovarajućeg unosa /Colorants proizveo strukturno nesukladnu datoteku, a izmišljanje zadane definicije bilo bi gore od propasti

PDF/X-6n output intenti moraju pokriti svaki registrirani spot

Datoteka PDF/X-6n s N bojila deklarira svoja bojila dvaput, i te dvije deklaracije moraju se slagati. AddPDFX6ExternalOutputIntent zapisuje referencu vanjskog ICC profila sa svojim ColorantTable-om, a prije toga ValidateRegisteredSpotOutputColorants prođe kroz svaki spot koji je dokument registrirao i podigne iznimku ako nekoga nema u tablici. Provjera ide u oba smjera: nakon što je output intent objavio svoj popis bojila, i kasnija registracija spota za ime izvan tog popisa odbija se. AddPDFX6ExternalOutputIntentSpotData dodaje metapodatke po boji na to, i nameće vlastita pravila, ponajprije da bojilo nosi ili vrijednost solidnosti ili CxF/X-4 spektralne podatke, nikada oboje. To je ista sukladnosna površina o kojoj piše tekst o validaciji PDF/A, PDF/X i PDF/UA

Spectral := TMemoryStream.Create;
try
  LoadCxFForInk('Orange', Spectral);   // ISO 17972-4 sadržaj
  Pdf.AddPDFX6ExternalOutputIntentSpotData(
    'ECG-5', 'Five-colour output condition',
    'https://profiles.example.com/ecg-5.icc', '5CLR',
    Colorants,
    '00112233445566778899AABBCCDDEEFF', #4#3#0#0,
    ['Cyan'], [0.70],                  // solidnost za jedno bojilo
    Order,
    ['Orange'], [Spectral]);           // spektralni podaci za drugo
finally
  Spectral.Free;
end;

Dvije operativne pojedinosti lako je promašiti. Registarski mehanizam koji sve ovo nosi jest po dokumentu i čisti se na granicama dokumenta, pa učitavanje nove datoteke u istu instancu THotPDF ne nasljeđuje spot identitete prethodnog dokumenta; ta izolacija je poanta, jer bi procurjeli potpis odbio sasvim valjani rad u sljedećem poslu. A strana profila ima vlastite tvrde granice: vanjski output intent zahtijeva PDF 2.0 cilj, apsolutni HTTP ili HTTPS URL profila, četverobajtni ICC potpis prostora boja, a za PDF/X-6n između 2 i 15 bojila s odgovarajućim potpisom od 2CLR do FCLR

Gdje provjera staje

Rukovanje CxF/X-4 dio je oko kojeg treba biti iskren. HotPDF primjenjuje ograničene strukturne sigurnosne provjere na spektralni tok i potvrđuje da identitet boje unutra odgovara bojilu koje ste imenovali. Ograničava veličinu sadržaja, odbija ugrađene null bajtove, ne prima nijedan tok koji sadrži DOCTYPE ili ENTITY deklaraciju, zahtijeva prepoznatljiv CxF korijen i zahtijeva točno jedan element SpotInkCharacterisation koji nosi točno jedan SpotInkName jednak vašem imenu bojila. To je vrata protiv neispravnog i neprijateljskog ulaza, a ne validator sheme. Nije potpuna implementacija ISO 17972-4, ne ovjerava vaša spektralna mjerenja i ne provodi obrnuti audit proizvoljnih već postojećih objektnih grafova trećih strana ni internih tablica bojila unutar ugrađenog ICC profila. Ako vaš tok rada ovisi o potpunoj CxF sukladnosti, ovjerite datoteku namenskim alatom prije nego je predate komponenti

Jedno susjedno ograničenje ugrize ljude koji nikada nisu očekivali da će ga sresti. Luminosity soft mask ne može koristiti Separation, DeviceN ni NChannel kao /CS svoje grupe prozirnosti; prostor miješanja grupe mora biti device ili CIE prostor, pa se spot boja unutar grupe rješava kroz njezinu tint transformaciju u alternativni prostor prije nego se izračuna luminozitet. RegisterLuminositySoftMaskState gradi DeviceGray grupu upravo da ovo ne pođe krivo slučajno. Praktična posljedica jest da se dizajn bogat spotovima, maskiran ovako, vrednuje kroz svoj CMYK zamjenski prostor, a ne kroz boju, što je važno kada ga uspoređujete sa separiranom probom kako opisuju bilješke o overprint probama i render uređajima

Ništa od ovoga ne uklanja potrebu za probnom pločom, ali cijelu klasu prepress odbijanja selje iz tiskare natrag u gradnju. API-ji za NChannel, Separation i PDF/X-6n output intent opisani ovdje isporučuju se sa standardnom HotPDF Delphi Component komponentom za Delphi i C++Builder, gdje referenca dokumentira potpune rasporede zapisa i točne uvjete pod kojima svaki poziv propada na siguran način