Technisch artikel

CMYK-overprint-proofing en renderdevices in HotPDF

Een cyaan vlak ligt op een gele achtergrond, en de graphics state die hem tekent draagt /op true en /OPM 1. Op het scherm is de overlap vlak cyaan. Op het persvel komt dezelfde overlap groen uit, want de RIP liet de gele plaat met rust en legde er cyaan bovenop. Beide resultaten volgen het bestand tot op de letter; de schermrender vroeg alleen nooit wat een imaging-device met die vlag doet, dus een goedkeuring op het scherm dekt een kleur die nooit het papier bereikt

Waarom drukt een pagina anders dan hij previewt?

Overprint is een instructie aan het uitvoerapparaat over platen, en een RGB-scherm heeft geen platen. ISO 32000-1 §8.6.7 definieert wat er gebeurt wanneer de entry OP (stroke) of op (fill) van een ExtGState true is: de kleurstoffen die de huidige verf niet benoemt, houden wat er al op hun plaat stond, in plaats van gewist te worden naar nul. Een zo geschilderd cyaan object haalt niets van de gele plaat af. Een viewer die in RGB samenstelt, heeft nergens om de geel te bewaren, dus hij verft cyaan erbovenop en gaat door

Geen van beide uitkomsten is kapot. Het meningsverschil zit ingebouwd in de twee imaging-modellen, en hij blijft onzichtbaar totdat iemand een gedrukte proef naast de monitor legt. Dat is laat in de klus voor een ontwerper die zwarte tekst per ongeluk op knock-out had gezet, of die een wit logo op overprint had laten staan en verwachtte dat het zou tonen

CMYK-overprintvergelijking in HotPDF waarbij een gewone viewer het geel onder cyaan wegknockt terwijl de overprint-preview beide drukinkten prooft en per ongeluk overgedrukte witte tekst blootlegt
Een gewone viewer verft alleen de bovenste inkt terwijl de overprint-proof beide inkten samenvoegt, waardoor valkuilen zoals per ongeluk overgedrukte witte letters zichtbaar worden

De proof aanzetten met RenderOverprintPreview

HotPDF stelt de proof bloot als één Boolean op het document, THotPDF.RenderOverprintPreview, die standaard op False staat. Met hem aan, volgt de bitmaprender de procesplaten onder elke overdruckende verf en past de regels van §8.6.7 toe voordat de pixel wordt weggeschreven, dus overlappingen tonen de inktcombinatie die de pers zou opleveren. De standaard uit laten is juist voor gewoon bekijken, want lezers van een kantoor-PDF verwachten dat hij oogt zoals hun vaste viewer hem toont. Zet hem aan in de stap waarvan de uitvoer naar een prepress-partij gaat

var
  Pdf: THotPDF;
  Device: THPDFBitmapRenderDevice;
  Proof: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('cover-cmyk.pdf');
    Pdf.RenderOverprintPreview := True;    // de platen proofen, standaard is False
    Device := THPDFBitmapRenderDevice.Create;
    try
      if Pdf.RenderLoadedPageToDevice(0, 150, Device) then
      begin
        Proof := Device.TakeBitmap;        // de aanroeper wordt vanaf hier eigenaar van Proof
        try
          Image1.Picture.Assign(Proof);
        finally
          Proof.Free;
        end;
      end;
    finally
      Device.Free;
    end;
  finally
    Pdf.Free;
  end;
end;

De platenregels hangen af van de kleurruimte van de overdruckende verf, en ze zijn het weten waard omdat elk ervan een andere verrassing op een proef verklaart:

  • DeviceCMYK onder /OPM 1: een component van nul laat zijn plaat onaangetast, een component ongelijk nul vervangt hem. Cyaan 100 / geel 0 over een gele achtergrond houdt het geel en wordt groen
  • DeviceGray: de verf benoemt alleen de zwarte plaat, dus cyaan, magenta en geel eronder overleven. Een wit DeviceGray-logo dat op overprint staat bovenop een CMY-achtergrond verdwijnt daarom
  • Separation en DeviceN: een kleurstof die Cyan, Magenta, Yellow of Black heet, vervangt die procesplaat direct, /None verft helemaal niets, en /All schrijft elke procesplaat
  • Spotkleurstoffen: elke andere naam wordt behandeld als spotinkt; zijn tinttransformatie geeft een alternatieve kleur, die over de procesplaten eronder wordt vermenigvuldigd, dus de spot donkert wat hij dekt in plaats van hem te vervangen

De proof geldt voor gevulde en omlijnde paden en voor tekst, inclusief tekst in stroke-rendermodus, waar de strokevlag OP beslist in plaats van op. Afbeeldingen, inline afbeeldingen en sh-shadingen lopen door hun volledige rasterkleurpijplijnen en verven met hun gewone dekking. In de praktijk dekt dat wat preflightrapporten het meest vlaggen: overprintregels, keylines, letters en vlakke tinten

Transparantie blijft live terwijl de proof aan staat. Een transparantiegroep met knockout aangezet knockt nog steeds uit, en de groep wordt in dezelfde doorgang samengesteld als de overprintregels, dus een drukklaar bestand met transparant artwork boven een overdruckende zwarte achtergrond prooft beide effecten samen. Er een goed en het ander fout krijgen levert alleen een ander verkeerde proof op

De instelling doet ook mee aan de identiteit van gecachte renders. RenderLoadedPageToBitmapCached onderbouwt zijn entries met pagina, DPI en een variant opgebouwd uit renderinstellingen waaronder RenderOverprintPreview, en de schijflaag gebruikt dezelfde variant. Een viewer die wisselt tussen normale en proof-preview krijgt twee aparte cache-entries en heeft nooit een aanroep van InvalidateRenderedPageCache nodig alleen omdat de schakelaar omging

De valkuil van /OPM 0 in DeviceCMYK-bestanden

Dit is het geval dat mensen op zoek laat gaan naar een bug. Een bestand zet /op true op een DeviceCMYK-cyaanvulling maar laat OPM op zijn standaard 0 staan, en de proof toont toch cyaan dat het geel wegknockt. De proof klopt. Onder overprintmodus 0 zegt §8.6.7 dat een DeviceCMYK-verf alle vier de proceskleurstoffen zet, nullen inbegrepen, dus de nulcomponent geel vervangt de gele plaat exact zoals een knock-out dat zou doen. Overprintmodus 0 beschermt alleen platen die de verf niet benoemt, wat voor een CMYK-kleur met vier componenten spotplaten betekent en niets anders

Op de procesplaten die een samengestelde proof toont, geven modus 0 en een kale knock-out dezelfde pixels, dus HotPDF tekent die DeviceCMYK-objecten als gewone knock-outs. Wil een CMYK-object andere procesinkten overprinten, dan heeft de ExtGState die /op true draagt ook /OPM 1 nodig. Wanneer een proof en de bedoeling van de ontwerper op een DeviceCMYK-object uiteenlopen, open dan die ExtGState en zoek naar de entry OPM voordat u iets anders verdenkt

De omgekeerde verrassing bestaat ook. Onder /OPM 1 is CMYK-wit vier nullen, en vier nullen onder overprint laten elke plaat zoals hij was. Witte letters die op overprint staan verdwijnen op het vel, en de proof toont dat verdwijnen, en dat is precies waarom je er een draait

Drie devices achter RenderLoadedPageToDevice

THotPDF.RenderLoadedPageToDevice(PageIndex, DPI, Device) is één toegangspunt waarvan het doel wordt bepaald door het device-object dat u doorgeeft. Hij gooit een exception voor een nil-device, behandelt een DPI onder 1 als 150, en geeft terug wat het device meldt vanuit zijn methode Execute. THPDFRenderDevice is de abstracte basis met twee virtuele leden: Kind, die rdkBitmap, rdkDeviceContext of rdkEnhancedMetafile teruggeeft, en Execute(Document, PageIndex, DPI)

De drie meegeleverde devices bezitten hun uitvoer op verschillende manieren:

  • THPDFBitmapRenderDevice houdt een TBitmap in zijn property Bitmap en geeft hem vrij in zijn destructor, tenzij TakeBitmap hem eerst aan u heeft overgedragen
  • THPDFDeviceContextRenderDevice.Create(ADC, AWidth, AHeight) tekent in een HDC die u al heeft en bezit niets; de constructor gooit bij een DC van nul of een niet-positieve grootte, en er wordt geen achtergrond gevet, dus een scherm-DC heeft zijn eigen witte vulling nodig
  • THPDFMetafileRenderDevice houdt een TMetafile vast tot TakeMetafile hem overdraagt. Tekst en vectorpaden blijven schaalbaar in de enhanced metafile, terwijl image XObjects gerasterd aankomen
HotPDF-renderarchitectuur die één RenderLoadedPageToDevice-aanroep uitsplitst naar bitmap-, printer-device-context- en enhanced-metafile-renderdevices met hun Kind-waarden en eigendomsregels
Eén renderte claimt uit naar bitmap-, device-context- en metafile-devices waarvan Kind het doel meldt en waarvan de Take-methoden het eigendom overdragen

Eigendom volgt de gewone Delphi-regels. Lees de property Bitmap of Metafile wanneer het object maar zo lang hoeft te leven als het device; roep de Take-methode aan wanneer hij langer moet leven. Neem de bitmap, geef het device vrij, vergeet de bitmap, en het lek groeit met het aantal pagina's: onzichtbaar op een voorbeeld van vijf pagina's, duidelijk op een batch van vijfhonderd pagina's. Geef elk object zijn eigen try/finally en de vraag wie wat vrijgeeft beantwoordt zichzelf

Dispatch op Kind in applicatiecode in plaats van te testen op is THPDFBitmapRenderDevice. Omdat Execute en Kind publieke virtuele methoden zijn, kunt u uw eigen deviceklasse schrijven, en code die op het soort controleert blijft werken wanneer een van uw eigen klassen invult voor een meegeleverd device

Waarom belandt een printerrender in een hoek?

Het device-contextpad bepaalt de paginagrootte vanuit het DPI-argument, niet vanuit de breedte en hoogte die u doorgeeft. De renderer schaalt PDF-units met DPI / 72 en gebruikt de hoogte alleen om de pagina-oorsprong onderaan het oppervlak te verankeren. 300 hardkoden en de taak naar een printer van 600 dpi sturen, en de pagina komt op de helft van de grootte uit, geduwd naar de linkerbenedenhoek van het vel. Printerresolutie is een eigenschap van de driver, dus vraag het aan de driver:

procedure PrintPage(Pdf: THotPDF; PageIndex: Integer);
var
  Device: THPDFDeviceContextRenderDevice;
  PrinterDPI, W, H, Tmp: Integer;
  L, B, R, T: Single;
begin
  if not Pdf.GetLoadedPageVisibleBox(PageIndex, L, B, R, T) then
    Exit;
  Printer.BeginDoc;
  try
    // vraag de driver; 300, 600 en 1200 dpi komen allemaal voor
    PrinterDPI := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
    W := Round((R - L) * PrinterDPI / 72);
    H := Round((T - B) * PrinterDPI / 72);
    if (Pdf.GetLoadedPageRotation(PageIndex) mod 180) = 90 then
    begin
      Tmp := W; W := H; H := Tmp;            // wisselen voor 90 / 270-pagina's
    end;
    Device := THPDFDeviceContextRenderDevice.Create(
      Printer.Canvas.Handle, W, H);
    try
      Pdf.RenderLoadedPageToDevice(PageIndex, PrinterDPI, Device);
    finally
      Device.Free;
    end;
  finally
    Printer.EndDoc;
  end;
end;

De breedte en hoogte komen uit de zichtbare box van de pagina, de CropBox ingeklemd tot de MediaBox, op de eigen resolutie van de printer, en de aanroeper wisselt ze voor gedraaide pagina's voordat hij het device aanmaakt. Dat sluit aan bij wat de renderer verwacht wanneer hij de oorsprong verankert

Overprint-proofing reist niet mee over dit pad. De device-context- en metafile-devices zenden GDI-aanroepen rechtstreeks in het doel uit, en de platenregels hebben de pixels nodig die al onder elke verf liggen, en die heeft alleen de bitmaprender. Voor een papieren proef: render de proof-bitmap en rek hem uit op het printercanvas. Een klein eigen device houdt dat achter hetzelfde toegangspunt:

type
  // een eigen device: proof-bitmap, daarna uitgerekt op de printer
  TPrinterProofDevice = class(THPDFRenderDevice)
  public
    function Kind: THPDFRenderDeviceKind; override;
    function Execute(Document: THotPDF; PageIndex, DPI: Integer): boolean;
      override;
  end;

function TPrinterProofDevice.Kind: THPDFRenderDeviceKind;
begin
  Result := rdkDeviceContext;
end;

function TPrinterProofDevice.Execute(Document: THotPDF;
  PageIndex, DPI: Integer): boolean;
var
  Proof: TBitmap;
  OldProof: Boolean;
begin
  OldProof := Document.RenderOverprintPreview;
  Document.RenderOverprintPreview := True;
  try
    Proof := Document.RenderLoadedPageToBitmap(PageIndex, DPI);
  finally
    Document.RenderOverprintPreview := OldProof;  // de instelling van de aanroeper laten zoals hij was
  end;
  Result := Proof <> nil;
  if Result then
  try
    Printer.Canvas.StretchDraw(
      Rect(0, 0, Printer.PageWidth, Printer.PageHeight), Proof);
  finally
    Proof.Free;
  end;
end;

Roep hem aan tussen Printer.BeginDoc en Printer.EndDoc met een DPI die de bitmap genoeg pixels voor het vel geeft, zo'n 200 tot 300 voor een proef op briefformaat. De uitrekbare rechthoek hierboven vult het afdrukbare gebied; houd daarin de beeldverhouding van de pagina vast als pagina en papier van vorm verschillen

Waar proofing past naast preflight

De proof beantwoordt één vraag: welke inkten overleven waar objecten overlappen. Hij wordt samengesteld op dezelfde 24-bits RGB-bitmap als elke andere render, dus zijn kleuren tonen de inktcombinatie in plaats van een gemeten velkleur. Perscondities zijn een kleurbeheervraag, en het document behandelt ze via ConfigureRenderICCWorkflow, die een proof-profiel, een uitvoerprofiel en een vlag voor black point compensation neemt, en ClearRenderICCWorkflow om ze weer te laten vallen

De productiefste plek voor een proofrender is naast de controles die u al draait. Een preflight-doorgang meldt dat zwarte tekst op overprint staat; de proofrender toont de operator wat dat op de pagina doet; beide belanden in hetzelfde rapport. Verpakkingswerk mengt overprint doorgaans met spotinkten, en de doorloop van rendering van Separation- en DeviceN-spotkleuren dekt de kleurstofkant van dezelfde pagina, inclusief weergaven van één plaat via RenderLoadedPageSeparationPlate. De artikelen over een PDF-pagina naar een bitmap renderen en een geladen PDF afdrukken via TPrinter dekken de twee device-doelen in hun kale vorm

Dit alles draait in native Delphi- en C++Builder-code zonder rendering-DLL naast de executable. De HotPDF Delphi-componentpagina lijst de render- en prepress-features op en heeft een proefbuild om deze voorbeelden tegen uw eigen drukbestanden te draaien