Drukarnia przygotowalni odsyła zlecenie: ta sama farba spot rozseparowana na dwie płyty. HotPDF zapobiega temu w czasie tworzenia, zapisując NChannel jako pięcioelementową postać DeviceN z ISO 32000-2 i trzymając jedną kanoniczną przestrzeń alternatywną i transformację tinty na nazwę spot dla całego dokumentu, odrzucając drugą, sprzeczną definicję zamiast jej emitować
NChannel nie jest nazwą rodziny przestrzeni barw
Pierwszą rzeczą do odwykania jest sama nazwa. NChannel nie jest rodziną przestrzeni barw tak, jak rodzinami są Separation i DeviceN. ISO 32000-2 §8.6.6.5 opisuje go jako podtyp DeviceN, więc zgodna przestrzeń NChannel jest zapisywana jako pięcioelementowa tablica [/DeviceN names alternateSpace tintTransform attributes], a słownik atrybutów niesie /Subtype /NChannel. Tablicy [/NChannel ...] nie ma w specyfikacji. Jeśli kiedykolwiek zbudowałeś jedną ręcznie i patrzyłeś, jak RIP wzrusza ramionami, to dlatego
HotPDF popełnił tu kiedyś błąd i potem go naprawił, co warto powiedzieć wprost, bo kształtuje to, jak komponent zachowuje się dziś. Starsze wydania HotPDF emitowały postać z nazwą rodziny. THotPDF.RegisterNChannelColorSpace emituje teraz wyłącznie standardową postać DeviceN-plus-atrybuty, a ponieważ podtyp NChannel przyszedł w PDF 1.6, punkt wejścia producenta strzeże RequirePDFVersion(pdf16, ...) i po prostu odmawia na starszych celach. Strona renderująca jest celowo wyrozumialsza niż zapisująca: HPDFResolveColorSpace nadal przyjmuje stary token /NChannel jako rodzinę DeviceN, więc pliki ze starego zapisu renderują się dalej, ale cokolwiek HotPDF wypisuje z powrotem używa standardowego kodowania. Pobłażliwie na wejściu, surowo na wyjściu to właściwa asymetria, bo twój czytnik musi radzić sobie z plikami, których nie tworzył, a twój zapis nie ma takiej wymówki
Dlaczego jedna nazwa spot ląduje na dwóch płytach?
Bo nazwa coloranta spot to tożsamość płyty w skali dokumentu, nie lokalny argument. Dwa wywołania, które obie nazywają Orange, ale przekazują inną przestrzeń alternatywną albo tę samą przestrzeń z inną transformacją tinty, opisują dwie różne farby, które przypadkiem dzielą etykietę. RIP budujący separacje nie ma jak tego pogodzić, więc robi jedyną uczciwą rzecz i daje ci dwie płyty. HotPDF prowadzi więc kanoniczną sygnaturę per nazwa coloranta w skali dokumentu. RegisterSpotColorantDefinition składa tę sygnaturę z alternatywnej przestrzeni barw i kształtu funkcji tinty, a każde RegisterSeparation, RegisterSeparationFunc, RegisterSeparationLUT i definicja spot NChannel przez nią przechodzi. Gdy druga definicja się nie zgadza, wywołanie rzuca wyjątek zamiast po cichu rejestrować drugi wariant, a komunikat jest celowo konkretny co do trybu awarii, bo alternatywą jest odkrycie tego na dowodzie płyty trzy tygodnie później
// Orange był już zarejestrowany względem DeviceCMYK
// z transformacją tinty 0 / 0.55 / 1 / 0 przy pełnej tintie.
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;
Rozdział nazw głównych na process i spot
Kompletny NChannel musi rozliczyć każdą ze swoich głównych nazw colorantów dokładnie raz, jako komponent process albo colorant spot. Zaawansowany przeciążony RegisterNChannelColorSpace bierze główne ColorantNames, ProcessColorantNames, przestrzeń alternatywną, ogólną transformację tinty, tablicę rekordów THPDFNChannelSpotColorant i opcjonalną kolejność druku. Każdy rekord spot niesie własną nazwę, własną jedno-wejściową transformację tinty Separation, opcjonalną solidność i opcjonalną funkcję rozrostu punktu. Ogólna transformacja tinty musi mapować N wejść na liczbę komponentów przestrzeni alternatywnej; każda tinta spot musi mapować jedno wejście na tę samą liczbę
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);
Z tego wywołania HotPDF emituje słownik atrybutów, o który prosi specyfikacja: /Subtype /NChannel, słownik /Process, którego /ColorSpace to przestrzeń process i którego /Components wymienia nazwy process w kolejności komponentów tej przestrzeni, słownik /Colorants trzymający prawdziwą tablicę [/Separation name alternate tintfn] dla każdego spot oraz słownik /MixingHints niosący /Solidities, /PrintingOrder i /DotGain, jeśli je podałeś. Zwrócona nazwa zasobu idzie do SetFillColorSpace albo SetStrokeColorSpace dokładnie jak prostsze przestrzenie omówione w artykule o renderowaniu barw spot Separation i DeviceN
Co tak naprawdę odrzuca kontrola spójności?
Odrzuca strukturalną niespójność wewnątrz przestrzeni i robi to, zanim jakikolwiek obiekt zostanie zapisany. Nazwy colorantów muszą być unikalne i nie mogą być puste, All ani None. Definicje process i spot razem muszą pokrywać nazwy główne dokładnie, bez coloranta w obu rolach i bez żadnego niezdefiniowanego. Gdy przestrzeń alternatywna to DeviceCMYK, komponenty process muszą być Cyan, Magenta, Yellow, Black w tej kolejności, a liczba nazw process musi zgadzać się z liczbą komponentów alternatywnej. Każda transformacja tinty i funkcja rozrostu punktu musi być pośrednim obiektem funkcji o właściwej arity wejścia i wyjścia. Solidność musi być skończoną wartością w 0..1. Kolejność druku musi być pusta albo pełną permutacją nazw głównych, nigdy listą częściową. Czego nie robi, to osądzania barwy: nic tutaj nie sprawdza, czy twoja transformacja tinty Orange faktycznie przypomina farbę w puszce, czy jej budowa CMYK jest znośnym przybliżeniem albo czy podana solidność zgadza się ze zmierzonym zachowaniem na podłożu. To pytania maszyny drukarskiej i pomiaru, a komponent nie ma mandatu, by na nie odpowiadać. Prostsze przeciążenie tylko-process jest z designu jeszcze surowsze: produkuje NChannel wyłącznie process i celowo odmawia przyjęcia nazw spot, bo zapisanie spot w tablicy nazw bez pasującego wpisu /Colorants wyprodukowałoby strukturalnie niezgodny plik, a fabrykowanie domyślnej definicji byłoby gorsze niż porażka
Output intenty PDF/X-6n muszą pokrywać każdy zarejestrowany spot
Plik PDF/X-6n z N colorantami deklaruje swoje coloranty dwukrotnie i obie deklaracje muszą się zgadzać. AddPDFX6ExternalOutputIntent zapisuje referencję zewnętrznego profilu ICC z jego ColorantTable, a zanim to zrobi, ValidateRegisteredSpotOutputColorants przechodzi każdy spot zarejestrowany przez dokument i rzuca wyjątek, jeśli któregoś brakuje w tabeli. Kontrola działa w obie strony: gdy output intent opublikuje już swoją listę colorantów, późniejsza rejestracja spot dla nazwy spoza tej listy jest także odrzucana. AddPDFX6ExternalOutputIntentSpotData dokłada na to metadane per farba i egzekwuje własne reguły, w szczególności że colorant niesie albo wartość solidności, albo dane spektralne CxF/X-4, nigdy oba. To ta sama powierzchnia zgodności omówiona w tekście o walidacji PDF/A, PDF/X i PDF/UA
Spectral := TMemoryStream.Create;
try
LoadCxFForInk('Orange', Spectral); // ładunek ISO 17972-4
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], // solidność dla jednego coloranta
Order,
['Orange'], [Spectral]); // dane spektralne dla innego
finally
Spectral.Free;
end;
Dwa operacyjne detale łatwo przegapić. Rejestr, który to wszystko podpiera, jest per dokument i jest czyszczony na granicach dokumentów, więc wczytanie nowego pliku do tej samej instancji THotPDF nie dziedziczy tożsamości spot poprzedniego dokumentu; ta izolacja jest sensem, bo przeciekła sygnatura odrzuciłaby całkiem poprawną pracę w kolejnym zleceniu. A strona profili ma własne twarde limity: zewnętrzny output intent wymaga celu PDF 2.0, absolutnego URL profilu HTTP albo HTTPS, czterobajtowej sygnatury przestrzeni barw ICC, a dla PDF/X-6n od 2 do 15 colorantów z pasującą sygnaturą od 2CLR do FCLR
Gdzie kontrola się kończy
Obsługa CxF/X-4 to część, o której trzeba mówić uczciwie. HotPDF nakłada ograniczone strukturalne kontrole bezpieczeństwa na strumień spektralny i potwierdza, że tożsamość farby wewnątrz niego zgadza się z nazwanym przez ciebie colorantem. Zasuwa rozmiar ładunku, odrzuca wbudowane bajty null, odmawia każdego strumienia zawierającego deklarację DOCTYPE albo ENTITY, wymaga rozpoznawalnego korzenia CxF i wymaga dokładnie jednego elementu SpotInkCharacterisation niosącego dokładnie jedno SpotInkName równe nazwie twojego coloranta. To brama przeciw zniekształconemu i wrogemu wejściu, nie walidator schematu. Nie jest pełną implementacją ISO 17972-4, nie weryfikuje twoich pomiarów spektralnych i nie audytuje wstecz dowolnych wcześniej istniejących grafów obiektów stron trzecich ani wewnętrznych tabel colorantów wewnątrz osadzonego profilu ICC. Jeśli twój przepływ pracy zależy od pełnej zgodności CxF, zwaliduj plik dedykowanym narzędziem, zanim oddasz go komponentowi
Jedno sąsiednie ograniczenie kąsi ludzi, którzy nigdy nie spodziewali się go spotkać. Miękka maska luminacyjna nie może używać Separation, DeviceN ani NChannel jako /CS swojej grupy przezroczystości; przestrzeń mieszania grupy musi być urządzeniowa albo oparta na CIE, więc farba spot wewnątrz grupy jest rozwiązywana przez swoją transformację tinty do przestrzeni alternatywnej, zanim zostanie policzona luminancja. RegisterLuminositySoftMaskState buduje grupę DeviceGray dokładnie po to, żeby to nie poszło źle przypadkiem. Praktyczna konsekwencja: projekt bogaty w spot maskowany w ten sposób jest oceniany przez swoje przybliżenie CMYK, nie przez swoją farbę, co ma znaczenie, gdy porównujesz go z dowodem separacji, jak opisano w notkach o proofingu overprint i urządzeniach renderujących
Nic z tego nie usuwa potrzeby dowodu płyty, ale przenosi całą klasę odrzuceń przygotowalni z sali maszyn z powrotem do budowania. API NChannel, Separation i output intentów PDF/X-6n opisane tutaj przychodzą w standardowym HotPDF Delphi Component dla Delphi i C++Builder, gdzie referencja dokumentuje pełne układy rekordów i dokładne warunki, w których każde wywołanie zawodzi bezpiecznie