-
-
Notifications
You must be signed in to change notification settings - Fork 29
device-cmyk() の DeviceCMYK 変換: CSS パターン別の調査結果 #774
Description
概要
まずは、本件の概要は、Vivliostyle CLI の CMYK 変換パイプライン(device-cmyk() → color(srgb) → Chromium PDF → 後処理で rg/RG → k/K)について、CSS パターン別に変換の成否を調査いたしました。
CSS device-cmyk() to /DeviceCMYK conversion works correctly for most patterns (text, background, border, shadow, outline, opacity), but CSS gradients (linear-gradient, radial-gradient) remain as /DeviceRGB in Shading objects. This is a structural limitation of Chromium's PDF backend (Skia), not a bug in Vivliostyle's post-processing.
調査環境
- vivliostyle-cli 10.3.1(ローカルビルド)
- Chromium 146.0.7680.153
- 検証方法:
qpdf --qdfで PDF をQDF形式に変換し、content stream 内のカラーオペレータを確認いたしました。
再現例:テスト HTMLとビルドされたPDF
- cmyk-conversion-audit.html: 10種類の CSS パターンを含む最小テストファイル
- cmyk-conversion-audit.pdf: ビルドしたPDFファイル
vivliostyle.config.js
export default {
entry: 'cmyk-conversion-audit.html',
output: [
{
path: 'cmyk-conversion-audit.pdf',
pdfPostprocess: {
cmyk: {
warnUnmapped: true,
},
},
},
],
};結果
変換成功(DeviceCMYK に変換された)
| # | CSS パターン | PDF 内のオペレータ |
|---|---|---|
| 1 | color: device-cmyk(1 0 0 0) |
1 0 0 0 k ✓ |
| 2 | background-color: device-cmyk(0 1 0 0) |
0 1 0 0 k ✓ |
| 3 | border: 3px solid device-cmyk(0 0 1 0) |
0 0 1 0 k ✓ |
| 5 | text-shadow: 2px 2px 4px device-cmyk(1 0 0 0) |
✓ |
| 6 | box-shadow: 4px 4px 8px device-cmyk(0 0 0 0.5) |
0 0 0 0.5 k ✓ |
| 7 | color: device-cmyk(1 0 0 0); opacity: 0.5 |
1 0 0 0 k + ExtGState ✓ |
| 8 | outline: 3px solid device-cmyk(0 0.8 0.8 0) |
0 0.8 0.8 0 k ✓ |
| 9 | 複数背景 | ✓ |
変換漏れ(DeviceRGB のまま残った)
| # | CSS パターン | PDF 内の状態 | 原因 |
|---|---|---|---|
| 4 | linear-gradient(device-cmyk(...), device-cmyk(...)) |
Shading オブジェクト /ColorSpace /DeviceRGB |
Chromium が Shading dict に RGB を凍結 |
| 10 | radial-gradient(device-cmyk(...), device-cmyk(...)) |
同上 | 同上 |
原因の分析
gradient の変換漏れ:Chromium (Skia) の構造的制約
Chromium の PDF バックエンド(Skia)は、CSS gradient を PDF の Shading オブジェクトとして出力します。
Shading オブジェクトでは、色情報が PDF ストリームではなく、辞書内の関数オブジェクトに凍結されます。
%% Shading object (from qpdf --qdf output)
/Shading <<
/ColorSpace /DeviceRGB ← ここが問題!!!!!
/Coords [ 0 0 5140 0 ]
/Function <<
/C0 [ 0 1 1 ] ← RGB に変換済み(元は device-cmyk(1 0 0 0) = Cyan)
/C1 [ 1 0 1 ] ← RGB に変換済み(元は device-cmyk(0 1 0 0) = Magenta)
/Domain [ 0 1 ]
/FunctionType 2
/N 1
>>
/ShadingType 2
>>
現在の Vivliostyle CLI の後処理は、content stream の rg/RG オペレータを k/K に書き換える方式のため、Shading オブジェクト内部の色には到達できません。
これは、最近、わたし自身がLaTeXパッケージとして開発いたしました spotxcolor パッケージ で指摘している「Shading は色が PDF オブジェクトに凍結されるため、content stream レベルでのインターセプトが不可能」という問題と、基本的に同型です(に見えます)。
対応案
現状、対応する方法を考えていますが、
- Shading オブジェクト内の
/ColorSpace /DeviceRGB→/DeviceCMYKの変換と、 - Function オブジェクト内の RGB → CMYK 値の書き換えを
後処理に追加することで、本件を対応可能だと考えています。
ちょっと、こちらで修正を考えてみたいと思います。
具体的には、
- PDF 内の Shading オブジェクトを走査し、
/ColorSpace /DeviceRGBを検出 - Function 内の
/C0,/C1等の RGB 値を CmykMap で CMYK に変換 /ColorSpaceを/DeviceCMYKに書き換え
ただし、gradient の中間色(ブラウザが RGB 空間で補間した値)は、CmykMap に登録されていないため、
RGB → CMYK の直接変換式が必要になりそうと思っています。
この点について、設計上の検討が必要そうです。