技術記事

HotPDFのCMYKオーバープリントプルーフとレンダーデバイス

HotPDFは読み込んだPDFページを単一のエントリポイントRenderLoadedPageToDevice経由でレンダリングし、渡されたデバイスが結果をビットマップにするか、プリンターキャンバスのような外部デバイスコンテキストへの描画にするか、ベクターの拡張メタファイルにするかを決める。RenderOverprintPreviewをTrueにすれば同じ呼び出しがCMYKプロセスインクのオーバープリントをシミュレートし、本来なら刷版の上にしか現れないインクの相互作用を、オペレーターが画面で見られるようにする

これら2つの機能は、たまたま同じコードパスで出会う、異なる問題を解決する。デバイス抽象化は、プレビュー、印刷、エクスポートがそれぞれ独自のレンダリング呼び出しと独自のドリフトを持っていた分岐を取り除く。オーバープリントプルーフは、ドキュメントがすべてのビューアで正しく見え、プレスから間違って出てくる種類の生産エラーを取り除く

なぜプレビューと印刷でページが違って見えるのか

オーバープリントはペイント操作ではなく、イメージングデバイスへの指示だからだ。ページがグラフィックス状態で/OP/opを真に設定したとき、それはRIPに対して下にあるインクをノックアウトしないよう命じている。シアンのオブジェクトがイエローの上に描かれればイエローはそのまま残り、用紙はグリーンを示す。オーバープリントを無視するビューアは通常どおりノックアウトし、シアンを示す。どちらもそれ自体の基準では間違っていない。それこそが問題だ。画面とプレスが食い違い、プルーフが戻るまで誰も気づかない

RenderOverprintPreviewは、HotPDFに/OP/op/OPM 1が支配するDeviceCMYKの塗りに対する指示を真剣に取らせる。結果はビューアのプレビューではなく、プルーフのプレビューだ。濃淡をオーバープリントするブラックは穴を開ける代わりに豊かなオーバーレイとして留まり、白いテキストに対するデザイナーの誤ったオーバープリントは、本来そうなるはずの消失テキストとして可視化される

var
  Pdf: THotPDF;
  Device: THPDFBitmapRenderDevice;
  Proof: TBitmap;
begin
  Pdf := THotPDF.Create(nil);
  try
    Pdf.LoadFromFile('cover-cmyk.pdf');
    Pdf.RenderOverprintPreview := True;    // proof, not plain preview
    Device := THPDFBitmapRenderDevice.Create;
    try
      if Pdf.RenderLoadedPageToDevice(0, 150, Device) then
      begin
        Proof := Device.TakeBitmap;        // ownership moves to the caller
        try
          Image1.Picture.Assign(Proof);
        finally
          Proof.Free;
        end;
      end;
    finally
      Device.Free;
    end;
  finally
    Pdf.Free;
  end;
end;

この設定はメモリとディスクの両方でレンダーキャッシュの同一性に参加するので、通常のプレビューとプルーフのプレビューがビットマップを共有することはない。プロパティを切り替えても、手作業で何かを無効化する必要はない。この2つのうち間違ったほうを返すキャッシュは、キャッシュがないより悪いからだ

3つのデバイス、1つのレンダリング呼び出し

THPDFRenderDeviceは、意味を持つ2つのメンバを持つ抽象クラスだ。対象をrdkBitmaprdkDeviceContextrdkEnhancedMetafileのいずれかとして報告するKindと、ライブラリが呼び出すExecuteだ。3つの具象デバイスがHotPDFに同梱され、それぞれが出力を異なる形で所有する

THPDFBitmapRenderDeviceTakeBitmapが所有権を呼び出し側に移すまでTBitmapを所有する。THPDFDeviceContextRenderDeviceは既存のHDCと幅・高さを受け取り、そのまま直接描画する。これがビットマップの往復なしにプリンターキャンバスへレンダリングする方法だ。THPDFMetafileRenderDeviceTakeMetafileが移すまでTMetafileを所有し、ベクターコンテンツをベクターのまま必要とする消費者のために保つ

var
  Device: THPDFDeviceContextRenderDevice;
begin
  Printer.BeginDoc;
  try
    Device := THPDFDeviceContextRenderDevice.Create(
      Printer.Canvas.Handle, Printer.PageWidth, Printer.PageHeight);
    try
      Pdf.RenderLoadedPageToDevice(PageIndex, 300, Device);
    finally
      Device.Free;
    end;
  finally
    Printer.EndDoc;
  end;
end;

実行時クラスをテストするのではなくKindを読むのは意図的だ。デバイス種別でディスパッチするアプリケーションコードは、デバイスが包まれ、装飾され、置き換えられても動き続ける。is THPDFBitmapRenderDeviceをテストするコードはそうならない

所有権の移動が実地で意味するもの

TakeBitmapTakeMetafileの前は、デバイスがオブジェクトを所有し、デストラクタで解放する。呼び出しの後は、あなたがそれを所有し、デバイスはもう所有しない。両方のパターンは正当だ。オブジェクトがレンダリング呼び出しより長く生きる必要がないときはBitmapMetafileプロパティを使い、オブジェクトがデバイスより長く生きるときは所有権を取る

失敗のモードは通常のDelphiのそれだ。ビットマップを取り、デバイスを解放し、ビットマップを解放し忘れると、ページ数とともに大きくなるリークができる。5ページのテストでは見えず、500ページのバッチでは明白なものだ。両方のオブジェクトを1つのtry/finallyではなく、それぞれ独自のtry/finallyで包めば、所有権の問いは自分で答えを出す

同じページ内でのオーバープリントプルーフと透明度

オーバープリントプレビューがオンでも透明度グループのノックアウトは活動を続け、両者は同じ境界付きペイントスナップショットパスの中で合成される。これは重要だ。実際の印刷向けファイルは2つを絶えず混ぜるからだ。アートワークを保持する透明度グループが、ブラックをオーバープリントに設定した背景の上に乗り、片方だけをシミュレートすれば、新しい形で間違ったプルーフを生む

限界は視野に入れておくこと。オーバープリントプレビューは、上記のオーバープリント制御の下にあるDeviceCMYK塗りに対するプロセスインクの挙動をシミュレートする。これはインクの相互作用のプルーフであり、カラーマネジメントされた契約プルーフではない。ICCワークフローを置き換えず、特定のプレスと用紙が何を生み出すかも教えない。プロのビューアでのオーバープリントプレビューを、プレスオペレーターが扱うのと同じように扱うこと。通常のプレビューを見るだけでは誰も気づかないエラーを捕捉するチェックとして

プレフライトステップにプルーフを組み込む

これが役立つ場所は、すでに実行しているチェックの隣だ。プレフライトパスがブラックテキストがオーバープリントに設定されていると報告し、プルーフレンダーがそれがページ上で何を意味するかをオペレーターに示し、両者が同じレポートに入る。パッケージ作業でオーバープリントに頻繁に付随するスポットカラーについては、SeparationとDeviceNのスポットカラー描画の解説が同じページの色材側を扱う。一方、PDFページをビットマップへレンダリングするTPrinter経由で読み込んだPDFを印刷するのノートは、プレーンで非プルーフな形の2つのデバイス対象を扱う

HotPDFはDelphiとC++Builder向けのネイティブVCLコードから、読み込んだPDFページのレンダリング、プルーフ、印刷を行う。アプリケーションの隣に配置する外部レンダリングDLLはない。HotPDFコンポーネントページにレンダリング機能一覧とトライアルビルドがある