Artykuł techniczny

Kolor urządzenia w PDF/A sądzony po tym, co maluje strona

veraPDF flaguje ISO 19005-1 6.2.3.3 na pliku, który nigdy nie rysuje RGB, nazywa gołe re f nieskalibrowanym albo zawala stronę 2, gdy identyczna strona 1 przechodzi. PDF/A rozsądza te reguły po tym, co każda strona maluje, więc walidator PDF/A w PDFium Component dla Delphi śledzi każdą stronę w głąb, do Form XObjectów, patternów, glifów i adnotacji, zanim orzeka o kolorze i przezroczystości

Czego 6.2.3.3 i 6.2.4.3 faktycznie wymagają

ISO 19005-1 6.2.3.3 pakuje trzy niezależne reguły w jeden akapit. Zgodny plik może użyć DeviceRGB albo DeviceCMYK, ale nie może użyć obu; jeśli użyto jakakolwiek nieskalibrowana przestrzeń kolorów, plik ma zawierać PDF/A-1 OutputIntent; a DeviceRGB jest dozwolony tylko z intencją, której profil to RGB, DeviceCMYK tylko z CMYK-ową. DeviceGray wypadł z tej listy, bo punkt ciągnie dalej objaśnienie konwersji szarości pod każdą z intencji. Sama intencja jest opcjonalna: 6.2.2 mówi, że plik może ją podać, i liczy tylko wpis OutputIntents z /S /GTS_PDFA1 i poprawnym strumieniem profilu ICC w /DestOutputProfile. Kontroler żądający intencji od każdego pliku odrzuca więc zgodne dokumenty, które nigdy nie malują kolorem urządzenia. Część 1 nie wspomina DefaultRGB ani DefaultCMYK, a jednak kolor przemapowany przez nie jest renderowany w przestrzeni opartej na CIE (ISO 32000-1 §8.6.5.6), co zaspokaja wymóg niezależności od urządzenia z 6.2.3.1; zestaw testowy veraPDF dla 6.2.3.3 traktuje to jako skalibrowane i PDFium Component czyta ten punkt tak samo. Zakaz mieszania stoi osobno: plik PDF/A-1, który maluje i RGB, i CMYK, zawodzi nawet, gdy wpisy Default kalibrują oba. ISO 19005-2 6.2.4.3 zrzuca ten zakaz i kalibruje każdą przestrzeń na własnych warunkach, jak pokazuje prawa kolumna niżej, więc PDFium Component robi jedno skanowanie na każdą część i stosuje kontrolę mieszania wyłącznie do deklaracji PDF/A-1

Namalowana przestrzeń urządzeniaPDF/A-1 (ISO 19005-1 6.2.3.3)PDF/A-2 i późniejsze (ISO 19005-2 6.2.4.3)
DeviceRGBDefaultRGB w zasobach albo intencja RGB; nie razem z DeviceCMYKDefaultRGB w zasobach, albo RGB OutputIntent
DeviceCMYKDefaultCMYK w zasobach albo intencja CMYK; nie razem z DeviceRGBDefaultCMYK w zasobach, albo CMYK OutputIntent
DeviceGrayDefaultGray w zasobach, albo jakikolwiek PDF/A-1 OutputIntentDefaultGray w zasobach, albo jakikolwiek PDF/A OutputIntent

Co liczy się jako użycie przestrzeni kolorów?

Użycie przestrzeni kolorów znaczy malowanie nią po ścieżce, którą czytnik wyrenderuje. Samo zadeklarowanie nie wystarcza. Zestaw veraPDF robi ten punkt plikiem pass dla 6.2.3.3: nazwany Form XObject ustawia CMYK przez K i k, siedzi w słowniku zasobów strony, nigdy nie jest referencjonowany z treści strony, a OutputIntent pliku to RGB. Poszukiwanie nazw kolorów urządzenia po całym pliku zawali ten plik, a przegapi inny, malujący tylko DeviceRGB pod intencją CMYK, gdzie żadne dwie nazwy nie kolidują. PDFium Component zamiast tego przechodzi graf rysowania, zbudowany na swoim skanerze preflight PDF/A poziomu bajtów. Od każdej strony przejście liczy kolor namalowany przez:

  • strumienie treści strony i każdy Form XObject, który wywołują przez Do, zagnieżdżone formy wliczone
  • pattern wybrany przez scn albo SCN, czytany z własnymi Resources patternu
  • CharProcs fontu Type 3 wybranego przez Tf
  • image XObjecty i obrazy inline, po przestrzeni kolorów, którą nazywa ich własny słownik
  • strumienie wyglądu adnotacji, malowane na wierzchu strony; gdy /AP /N widgeta jest słownikiem stanów, liczy się każdy stan, bo przełączenie pola maluje ten, którego /AS nie wybrało

Subtelniejsza połowa osiągalności to kolor, którego treść nigdy nie nazwie. q 0 0 10 10 re f Q nie zawiera operatora koloru. Wciąż maluje. Początkowa przestrzeń kolorów stanu grafiki to DeviceGray (ISO 32000-1 tabela 52), więc wypełnienie to czarny DeviceGray, nieskalibrowany pod każdą część, chyba że istnieje PDF/A OutputIntent albo DefaultGray. Skan śledzi więc, czy cokolwiek wybrało już kolor: rg, k, g i ich odpowiedniki obrysu wybierają przestrzeń urządzenia, cs i CS wybierają to, co nazwą, a operator wypełnienia, obrysu albo tekstu dosięgnięty przed jakimkolwiek wyborem zapisuje DeviceGray. /CS0 cs 1 0 0 /P0 scn już wybrał przestrzeń, więc ten scn nie jest szary

Osiągalna ścieżka malowania, którą PDFium Component przechodzi w Delphi przed wyrokiem o kolorze urządzenia PDF/A: formy, patterny, glify Type 3, obrazy i strumienie wyglądu adnotacji
samo zadeklarowanie przestrzeni kolorów nie wystarcza — przejście liczy, co każda strona maluje, w tym szarość urządzenia, którą gołe re f podchwytuje ze stanu początkowego

Obrazy inline wnoszą swoją przestrzeń kolorów i surowe próbki prosto do strumienia treści, i skaner musi czytać jedno i drugie uważnie. /CS może być skrótem (G, RGB, CMYK, I) albo nazwą zasobu, taką jak rozwiązującą się do [/Indexed /DeviceRGB 255 13 0 R], której baza się liczy; a bajty między ID i EI są dowolnym binarium, więc EI kończy obraz tylko między białymi znakami, inaczej rg wewnątrz skompresowanych próbek zamienia się w operatora-widmo

% strona 1: DefaultRGB w zasobach i XObject, którego nic nie wywołuje
4 0 obj << /Type /Page /Parent 2 0 R /Contents 5 0 R
           /Resources << /ColorSpace << /DefaultRGB 9 0 R >>
                         /XObject << /Fm0 6 0 R >> >> >>
endobj
% strona 2: ten sam strumień treści, bez podsłownika ColorSpace
7 0 obj << /Type /Page /Parent 2 0 R /Contents 5 0 R /Resources << >> >>
endobj
5 0 obj << /Length 46 >> stream
1 0 0 rg 72 72 200 100 re f
q 0 0 10 10 re f Q
endstream
endobj
6 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 50 50] /Length 24 >> stream
0 0 0 1 k 0 0 50 50 re f
endstream
endobj
9 0 obj [/ICCBased 10 0 R]
endobj

Każdy objaw z otwarcia wypada z tego fragmentu. /Fm0 nigdy nie spotyka Do, więc jego k jest bez znaczenia. Gołe re f na obu stronach to DeviceGray bez niczego do skalibrowania. rg na stronie 1 jest przykryty DefaultRGB w zasobach, z którymi strona 1 maluje; strona 2 puszcza identyczny strumień przeciw zasobom bez tej mapy, więc te same bajty są tam nieskalibrowane. Oczekiwane dla deklaracji PDF/A-1b: pvaiMissingOutputIntent z pvaiMissingIccProfile, pchane przez RGB strony 2 i szarość obu stron. Forma nie wnosi nic; wywołana, jej CMYK dołożyłby zakaz mieszania PDF/A-1 na wierzch

Domyślne przestrzenie kolorów należą do słownika zasobów, który maluje

Mapy Default są szukane w podsłowniku ColorSpace bieżącego słownika zasobów (ISO 32000-1 §8.6.5.6), co czyni je dokładnie tak lokalnymi, jak same zasoby; dokument nie ma globalnego domyślnego. Image XObject nie ma własnych Resources, więc obraz, którego słownik mówi /ColorSpace /DeviceCMYK, jest skalibrowany DefaultCMYK strony albo formy, która go rysuje, i ten sam obraz rysowany z dwóch miejsc może być skalibrowany w jednym, a w drugim nie. Form XObjecty, patterny tilingowe i procedury glifów Type 3 niosą własne Resources, więc DefaultCMYK strony nie sięga do ich wnętrza, a mapa we własnym słowniku tak. PDFium Component zakresuje mapy tak samo. Werdykt wraca jako rekord TPdfAValidationResult: wykryte Conformance plus zbiór Issues. To dość, żeby przetrageować folder

uses
  System.SysUtils, System.Classes, System.TypInfo, FPdfPdfa;

procedure ReportColorFindings(const FileName: string; Log: TStrings);
const
  ColorRules: TPdfAValidationIssues = [pvaiMissingOutputIntent,
    pvaiMissingIccProfile, pvaiMixedDeviceColorSpaces, pvaiBlendSpaceUndefined];
var
  Source: TFileStream;
  Res: TPdfAValidationResult;
  Found: TPdfAValidationIssues;
  Issue: TPdfAValidationIssue;
begin
  Source := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
  try
    Res := ValidatePdfACompliance(Source);   // czyta od pozycji 0
  finally
    Source.Free;
  end;
  Log.Add(ExtractFileName(FileName) + ': ' +
    GetEnumName(TypeInfo(TPdfAConformance), Ord(Res.Conformance)));
  Found := Res.Issues * ColorRules;
  for Issue in Found do
    case Issue of
      pvaiMissingOutputIntent:
        Log.Add('  reachable uncalibrated device color, no PDF/A OutputIntent');
      pvaiMissingIccProfile:
        Log.Add('  no OutputIntent with a DestOutputProfile ICC stream');
      pvaiMixedDeviceColorSpaces:
        Log.Add('  RGB/CMYK use disagrees with the intent, or PDF/A-1 paints both');
      pvaiBlendSpaceUndefined:
        Log.Add('  transparent page without a blending color space');
    end;
  if Found = [] then
    Log.Add('  device color and blending rules satisfied');
end;

pvaiMissingOutputIntent i pvaiMissingIccProfile pojawiają się razem, gdy przejście dosięga nieskalibrowanego koloru urządzenia, a żaden PDF/A OutputIntent nie istnieje. pvaiMissingIccProfile sam w sobie znaczy, że intencja istnieje, ale nie niesie profilu, czego 6.2.2 nie przyjmuje jako intencji PDF/A. pvaiMixedDeviceColorSpaces przykrywa i zakaz mieszania PDF/A-1, i niezgodność składowych: nieskalibrowany DeviceRGB pod intencją czteroskładnikową albo DeviceCMYK pod trójskładnikową. Zbiór nazywa regułę, nie stronę, więc w długim albo sklejanym dokumencie porównaj, które strony deklarują wpisy Default, a które nie

Jeden obraz DeviceCMYK rysowany z dwóch słowników zasobów w Delphi: skalibrowany DefaultCMYK na jednej stronie i nieskalibrowany na innej, jak raportuje PDFium Component
domyślne przestrzenie kolorów należą do słownika zasobów, który maluje, więc ten sam obraz może być skalibrowany tam, gdzie rysuje go jedna strona, i nieskalibrowany tam, gdzie forma

Kiedy przezroczysta strona potrzebuje własnej przestrzeni blendingu?

Przezroczysta strona potrzebuje własnej przestrzeni blendingu tylko wtedy, gdy dokument nie ma PDF/A OutputIntent. ISO 19005-2 6.2.10 (6.2.9 w PDF/A-4) czyni intencję domyślną przestrzenią blendingu w sensie ISO 32000-1 §11.3.4; bez intencji każda strona zawierająca przezroczystość ma nieść Group, którego słownik atrybutów (ISO 32000-1 tabela 147) zawiera CS. Tamto CS też podlega 6.2.4, więc grupa strony /DeviceCMYK pod intencją sRGB jest raportowana jak brakująca, a PDFium Component podnosi pvaiBlendSpaceUndefined dla obu; CalRGB albo grupowa przestrzeń ICCBased nie ma takiej zależności. PDF/A-1 nie dochodzi do tego pytania, bo ISO 19005-1 6.4 wyklucza przezroczystość całkowicie

Trudna jest fraza zawiera przezroczystość. Załącznik A ISO 19005-2 jest normatywny i testuje od strony na zewnątrz; plikowe liczenie kluczy /SMask albo wartości /ca odpowiada na inne pytanie. Szukanie bajtów koliduje też ze składnią przezroczystości gdzie indziej: /S /Trans, zakazana akcja przejścia, jest prefiksem każdej grupy /S /Transparency, a /Screen to jednocześnie zakazany podtyp adnotacji i standardowy tryb blendingu, więc nazwa nie znaczy nic, dopóki nie jest sparowana ze swoim kluczem. Za załącznikiem A PDFium Component uznaje stronę za przezroczystą, gdy z niej da się dosięgnąć czegokolwiek z tej listy:

  • ExtGState wybrany przez treść przez gs, który ma słownik maski miękkiej, ca albo CA poniżej 1, albo tryb blendingu inny niż Normal; zadeklarowany, ale nigdy niewybrany, się nie liczy
  • Form XObject wywołany przez Do, którego /Group ma /S /Transparency, albo którego własna treść spełnia jeden z tych warunków; pattern tilingowy jest sądzony jak forma
  • image XObject ze strumieniem SMask albo wartością SMaskInData powyżej 0
  • opis glifu fontu Type 3, którym strona pokazuje tekst, sądzony jak forma
  • strumień wyglądu adnotacji, ze każdym stanem widgeta wliczonym, i tryb blendingu na samym słowniku adnotacji

Grupy też cofają się do reguły koloru urządzenia, i tu korpus nas skorygował. Zestaw veraPDF dla 6.2.4.3 trzyma pliki PDF/A-4 bez żadnego OutputIntent, które malują RGB urządzenia i mają przechodzić, bo /Group każdej strony nazywa skalibrowane CS. Założyliśmy, że kalibrować mogą tylko grupy izolowane, bo grupa nieizolowana kompozytuje się w swoje tło, i to było złe dla grup stron: tabela 147 notuje, że strona nałożona bezpośrednio na medium wyjściowe jest faktycznie izolowana niezależnie od I, więc jej CS jest honorowany. Na Form XObject albo wyglądzie adnotacji flaga faktycznie rozstrzyga; zestaw ma plik pass i plik fail różniące się tylko /I true. DeviceGray nie bierze kalibracji z grupy, bo 6.2.4.3 żąda DefaultGray albo intencji, a grupa, której CS to przestrzeń urządzenia, sama potrzebuje kalibracji. PDFium Component pozwala więc grupie strony kalibrować niezależnie od tego, co mówi jej /I, pozwala grupie formy albo wyglądu kalibrować tylko gdy izolowana, trzyma szarość poza kalibracją grupową i wciąż sprawdza przestrzeń urządzenia, którą grupa nazywa

Macierz PDF/A dla Delphi: kiedy przezroczysta strona potrzebuje własnego CS blendingu i jak PDFium Component sądzi kalibrację grup strony, formy i wyglądu
intencja wyjścia to domyślna przestrzeń blendingu, a grupa strony kalibruje kolor urządzenia niezależnie od swojej flagi izolacji, gdy grupa formy potrzebuje /I true

Jeden OutputIntent zamiast grupy na każdej stronie

Jeśli własny kod pisze archiwum, zacznij od dokumentowego PDF/A OutputIntent. Jeden wpis katalogu kalibruje DeviceGray wszędzie, przykrywa pasującą przestrzeń urządzenia na każdej stronie i jest domyślną przestrzenią blendingu dla każdej przezroczystej strony. Grupy stron i wpisy Default są zakresowane każde do jednego słownika zasobów, a strona, którą późniejszy merge doda bez nich, to ta, która zawiedzie. PDF 2.0 dodaje OutputIntents do obiektu strony (ISO 32000-2 §7.7.3.3 i §14.11.5); PDFium Component przyjmuje intencję poziomu strony dla PDF/A-4, gdy katalog nie ma żadnej, podczas gdy części 1–3, zbudowane na PDF 1.4–1.7, patrzą tylko w katalog. Dla treści RGB SaveAsPdfAToStream dodaje intencję katalogu zbudowaną na osadzonym profilu ICC sRGB pisarza PDF/A, a walidacja wyjścia pokazuje, czy treść naprawdę była tylko RGB

uses
  System.SysUtils, System.Classes, PDFium, FPdfPdfa;

function ArchiveWithSrgbIntent(const InFile, OutFile: string;
  out Remaining: TPdfAValidationIssues): Boolean;
var
  Pdf: TPdf;
  Opts: TPdfASaveOptions;
  Output: TMemoryStream;
  Check: TPdfAValidationResult;
begin
  Result := False;
  Remaining := [];
  Pdf := TPdf.Create(nil);
  Output := TMemoryStream.Create;
  try
    Pdf.FileName := InFile;
    Pdf.Active := True;
    if not Pdf.Active then
      Exit;                           // pliku nie dało się otworzyć
    Opts := TPdfASaveOptions.Default;
    Opts.Conformance := pac2b;        // PDF/A-1 zakazałby przezroczystości wprost
    // IccProfileData zostaje puste: użyty jest wbudowany profil sRGB IEC61966-2.1
    if not Pdf.SaveAsPdfAToStream(Output, Opts) then
      Exit;
    Check := ValidatePdfACompliance(Output);
    Remaining := Check.Issues;
    // Oczekiwane dla treści tylko RGB: pvaiMissingOutputIntent i
    // pvaiBlendSpaceUndefined znikają. pvaiMixedDeviceColorSpaces znaczy teraz,
    // że osiągalna ścieżka maluje DeviceCMYK, którego nie kalibruje DefaultCMYK.
    if Check.IsCompliant then
    begin
      Output.SaveToFile(OutFile);
      Result := True;
    end;
  finally
    Output.Free;
    Pdf.Free;
  end;
end;

pvaiMixedDeviceColorSpaces, które przeżywa intencję sRGB, to przejście raportujące DeviceCMYK na osiągalnej ścieżce, i ten dokument potrzebuje mapy DefaultCMYK na stronach, które go malują, albo profilu wyjścia CMYK, zanim PDFium Component przyjmie go jako PDF/A-2b