C#でCMYKを扱う方法|RGB変換と印刷向けカラー処理を解説

はじめに

C#でCMYKを扱う場面は、Webアプリや業務システムの開発だけをしていると多くありません。しかし、チラシ、カタログ、名刺、ラベル、帳票PDF、印刷用画像などを扱うシステムでは、「RGBの画面色をCMYKに変換したい」「印刷向けPDFでCMYKを指定したい」「CMYK画像を読み込むと色が変わる」といった問題が発生します。

C#には、CMYKを標準の色型として直接扱える汎用的な仕組みはほとんどありません。たとえば System.Drawing.Color は基本的にARGB/RGBを前提にしており、CMYK値をそのまま保持する型ではありません。そのため、C#でCMYKを扱う場合は、次のように目的を分けて考えることが重要です。

簡易的な色変換でよい場合は、RGBとCMYKの変換式を自前で実装します。印刷品質を重視する場合は、ICCプロファイルを使ったカラーマネジメントが必要です。さらに、PDFや画像ファイルにCMYK情報を正しく保持したい場合は、CMYKに対応した外部ライブラリや検証ツールを組み合わせる必要があります。

この記事では、C#でCMYKを扱うための基礎知識から、RGB変換、独自クラスの実装、画像処理、PDF作成、印刷向けの注意点までを実務目線で解説します。

1. C#でCMYKを扱う前に知っておきたい基礎知識

1-1. CMYKとは何か|印刷で使われる4色の仕組み

CMYKとは、Cyan、Magenta、Yellow、Key plateの4成分で色を表すカラーモデルです。一般的には、Cがシアン、Mがマゼンタ、Yがイエロー、Kがブラックを表します。

印刷では紙にインキを重ねて色を表現します。白い紙の上にインキを乗せるため、色を加えるほど暗くなる「減法混色」の考え方になります。たとえば、C、M、Yを多く重ねると理論上は黒に近づきますが、実際のインキでは完全な黒になりにくいため、K、つまり黒インキを使います。

CMYK値は、一般的に0〜100%で表されます。たとえば、黒は C=0, M=0, Y=0, K=100、シアンは C=100, M=0, Y=0, K=0 のように表現します。ただし、印刷会社やカラープロファイルによって、同じCMYK値でも実際の印刷結果は変わります。

1-2. RGBとCMYKの違い|画面表示と印刷色の考え方

RGBは、Red、Green、Blueの3成分で色を表すカラーモデルです。ディスプレイ、スマートフォン、Web画像、アプリ画面など、光を発する媒体で使われます。RGBは光を足すほど明るくなる「加法混色」です。

一方、CMYKは紙にインキを乗せる印刷向けのカラーモデルです。RGBでは鮮やかに見える青、緑、蛍光色に近い色などは、CMYK印刷では再現しにくい場合があります。そのため、C#でRGBからCMYKへ単純変換しても、画面で見た色と印刷結果が完全に一致するわけではありません。

C#で色を扱うときは、画面表示用のRGBなのか、印刷工程に渡すためのCMYKなのかを最初に分けて設計する必要があります。

1-3. C#標準機能だけでCMYKを扱う際の注意点

C#標準機能だけでCMYKを扱う場合、最初に注意すべき点は「CMYK専用の標準カラー型がない」ことです。System.Drawing.Color はARGB値を扱う型であり、CMYKのC、M、Y、Kをそのまま保持する型ではありません。

また、画像処理でよく使われる System.Drawing.Common は、.NET 6以降、Windows以外のOSではサポート対象外になっています。Microsoftのドキュメントでも、Windows以外で参照した場合の警告や、実行時に PlatformNotSupportedException が発生する可能性が説明されています。Microsoft Learn+1

そのため、Windowsデスクトップアプリだけで完結する処理なら System.Drawing を使えるケースもありますが、Linuxサーバー、Docker、macOS、クラウド環境で動かすWebアプリでは、ImageSharp、SkiaSharp、Magick.NETなどの外部ライブラリを検討するのが現実的です。

1-4. CMYK処理が必要になる主なケース

C#でCMYK処理が必要になるのは、主に印刷物や入稿データを扱うシステムです。

たとえば、ユーザーがアップロードしたRGB画像を印刷向けに変換する場合、帳票PDFをCMYKカラーで生成したい場合、デザイナーから指定されたCMYK値をPDF内の図形や文字に反映したい場合、印刷会社に渡すデータにRGBが混在していないか確認したい場合などです。

逆に、Web表示、アプリ画面、サムネイル生成、SNS用画像の作成が目的であれば、CMYKへ変換せずRGBのまま扱うほうが適しています。CMYKはあくまで印刷工程に近い領域で必要になるものと考えると、設計を誤りにくくなります。

2. C#でRGBからCMYKへ変換する基本方法

2-1. RGB値からCMYK値を計算する変換式

RGBからCMYKへ簡易変換する場合は、まずRGB値を0〜1の範囲に正規化します。

C#
R' = R / 255
G' = G / 255
B' = B / 255

次に、Kを求めます。

C#
K = 1 - Max(R', G', B')

Kが1、つまり完全な黒の場合は、C、M、Yを0として扱います。

C#
C = 0
M = 0
Y = 0
K = 1

それ以外の場合は、次の式でC、M、Yを求めます。

C#
C = (1 - R' - K) / (1 - K)
M = (1 - G' - K) / (1 - K)
Y = (1 - B' - K) / (1 - K)

この計算結果は0〜1の小数です。パーセントで表示したい場合は、それぞれ100を掛けます。

たとえば、RGBの赤 R=255, G=0, B=0 は、簡易計算ではおおむね C=0%, M=100%, Y=100%, K=0% になります。

2-2. C#でRGBをCMYKに変換するサンプルコード

以下は、RGB値をCMYK値に変換するシンプルなC#コードです。

C#
public readonly record struct Cmyk(double C, double M, double Y, double K)
{
public double CyanPercent => C * 100;
public double MagentaPercent => M * 100;
public double YellowPercent => Y * 100;
public double BlackPercent => K * 100;
}

public static class ColorConverter
{
public static Cmyk RgbToCmyk(byte r, byte g, byte b)
{
double rd = r / 255.0;
double gd = g / 255.0;
double bd = b / 255.0;

double k = 1.0 - Math.Max(rd, Math.Max(gd, bd));

if (k >= 1.0)
{
return new Cmyk(0, 0, 0, 1);
}

double c = (1.0 - rd - k) / (1.0 - k);
double m = (1.0 - gd - k) / (1.0 - k);
double y = (1.0 - bd - k) / (1.0 - k);

return new Cmyk(c, m, y, k);
}
}

使用例は次のとおりです。

C#
var cmyk = ColorConverter.RgbToCmyk(255, 128, 0);

Console.WriteLine($"C: {cmyk.CyanPercent:F1}%");
Console.WriteLine($"M: {cmyk.MagentaPercent:F1}%");
Console.WriteLine($"Y: {cmyk.YellowPercent:F1}%");
Console.WriteLine($"K: {cmyk.BlackPercent:F1}%");

この方法は、画面上のRGB値を大まかなCMYK値に変換したい場合に使えます。ただし、印刷会社に入稿する最終データの色変換としては不十分です。

2-3. CMYKからRGBへ戻す変換方法

CMYKからRGBへ戻す場合は、次の式を使います。

C#
R = 255 × (1 - C) × (1 - K)
G = 255 × (1 - M) × (1 - K)
B = 255 × (1 - Y) × (1 - K)

C#で実装すると、次のようになります。

C#
public static (byte R, byte G, byte B) CmykToRgb(double c, double m, double y, double k)
{
c = Clamp01(c);
m = Clamp01(m);
y = Clamp01(y);
k = Clamp01(k);

byte r = ToByte(255.0 * (1.0 - c) * (1.0 - k));
byte g = ToByte(255.0 * (1.0 - m) * (1.0 - k));
byte b = ToByte(255.0 * (1.0 - y) * (1.0 - k));

return (r, g, b);
}

private static double Clamp01(double value)
{
return Math.Min(1.0, Math.Max(0.0, value));
}

private static byte ToByte(double value)
{
return (byte)Math.Round(Math.Min(255.0, Math.Max(0.0, value)));
}

この変換も、あくまで数式上の近似です。ICCプロファイルを考慮した変換ではないため、「元のRGBに完全に戻る」「印刷結果と一致する」とは考えないようにしましょう。

2-4. 黒成分Kの扱いと計算時の注意点

RGBからCMYKへ変換する際に特に重要なのが、Kの扱いです。Kは黒成分を表しますが、単にC、M、Yを減らすための値ではありません。印刷では、黒インキの量、グレーの安定性、インキ総量、紙質、乾燥、にじみなどに影響します。

簡易変換式では、RGBの最大成分からKを求めます。しかし実際の印刷用プロファイルでは、GCR、UCR、TACなどの考え方が関係します。GCRはグレー成分を黒版に置き換える考え方、UCRは暗部のCMYを減らして黒に置き換える考え方、TACはインキ総量の上限です。

たとえば、濃い黒を表現するために C=60, M=40, Y=40, K=100 のようなリッチブラックを使うことがあります。しかし、小さな文字や細線でリッチブラックを使うと、版ズレによってにじんで見えることがあります。そのため、本文文字や細い罫線は K=100 のスミベタにするのが一般的です。

2-5. 変換結果が印刷色と完全一致しない理由

RGBからCMYKへの変換結果が印刷色と完全一致しない理由は、RGBとCMYKの色域が違うからです。RGBはディスプレイ上の発光色であり、CMYKは紙とインキによる反射色です。表現できる色の範囲が異なるため、RGBで鮮やかに見える色がCMYKではくすんで見えることがあります。

また、印刷結果は使用するICCプロファイル、印刷方式、インキ、紙、印刷機、乾燥条件、表面加工によって変わります。つまり、同じCMYK値でも、コート紙と上質紙では見え方が変わります。

そのため、C#で計算したCMYK値は「目安」として扱い、印刷品質が重要な案件では、印刷会社指定のICCプロファイルやPDF設定に従う必要があります。

3. C#でCMYKカラークラスを実装する方法

3-1. CMYK値を保持する独自クラスの作成

C#でCMYKを安全に扱うには、C、M、Y、Kを保持する独自クラス、または構造体を作るのが扱いやすいです。

C#
public readonly record struct CmykColor
{
public double C { get; }
public double M { get; }
public double Y { get; }
public double K { get; }

public CmykColor(double c, double m, double y, double k)
{
C = Clamp01(c);
M = Clamp01(m);
Y = Clamp01(y);
K = Clamp01(k);
}

public double CPercent => C * 100;
public double MPercent => M * 100;
public double YPercent => Y * 100;
public double KPercent => K * 100;

private static double Clamp01(double value)
{
if (double.IsNaN(value)) return 0;
return Math.Min(1.0, Math.Max(0.0, value));
}

public override string ToString()
{
return $"C={CPercent:F1}%, M={MPercent:F1}%, Y={YPercent:F1}%, K={KPercent:F1}%";
}
}

このようにクラス化しておくと、CMYK値の範囲チェックや表示形式を一元管理できます。実務では、0〜1で保持するか、0〜100で保持するかをプロジェクト内で統一しておくことが重要です。

3-2. RGB・CMYK変換メソッドの実装

独自クラスにRGB変換メソッドを追加すると、使い回しやすくなります。

C#
public readonly record struct RgbColor(byte R, byte G, byte B);

public readonly record struct CmykColor
{
public double C { get; }
public double M { get; }
public double Y { get; }
public double K { get; }

public CmykColor(double c, double m, double y, double k)
{
C = Clamp01(c);
M = Clamp01(m);
Y = Clamp01(y);
K = Clamp01(k);
}

public static CmykColor FromRgb(byte r, byte g, byte b)
{
double rd = r / 255.0;
double gd = g / 255.0;
double bd = b / 255.0;

double k = 1.0 - Math.Max(rd, Math.Max(gd, bd));

if (k >= 1.0)
{
return new CmykColor(0, 0, 0, 1);
}

double c = (1.0 - rd - k) / (1.0 - k);
double m = (1.0 - gd - k) / (1.0 - k);
double y = (1.0 - bd - k) / (1.0 - k);

return new CmykColor(c, m, y, k);
}

public RgbColor ToRgb()
{
byte r = ToByte(255.0 * (1.0 - C) * (1.0 - K));
byte g = ToByte(255.0 * (1.0 - M) * (1.0 - K));
byte b = ToByte(255.0 * (1.0 - Y) * (1.0 - K));

return new RgbColor(r, g, b);
}

private static double Clamp01(double value)
{
if (double.IsNaN(value)) return 0;
return Math.Min(1.0, Math.Max(0.0, value));
}

private static byte ToByte(double value)
{
return (byte)Math.Round(Math.Min(255.0, Math.Max(0.0, value)));
}
}

この実装で、C#内ではCMYKを型として扱えるようになります。

C#
var cmyk = CmykColor.FromRgb(30, 120, 200);
var rgb = cmyk.ToRgb();

Console.WriteLine(cmyk);
Console.WriteLine($"RGB = {rgb.R}, {rgb.G}, {rgb.B}");

3-3. 値の範囲チェックと丸め処理

CMYK値は、0〜1または0〜100の範囲で管理する必要があります。ユーザー入力や外部ファイルから値を受け取る場合は、範囲外の値が入る可能性があります。

たとえば、C=120%K=-10% のような値をそのまま使うと、変換結果がおかしくなります。そのため、コンストラクタやファクトリメソッドで必ず範囲チェックを行いましょう。

C#
public static CmykColor FromPercent(double c, double m, double y, double k)
{
return new CmykColor(c / 100.0, m / 100.0, y / 100.0, k / 100.0);
}

表示時には、小数点以下を何桁まで扱うかも決めておくとよいです。印刷現場では整数%で指定することも多いですが、システム内部では小数を保持しておき、表示や出力時に丸めるほうが柔軟です。

3-4. 実務で使いやすい拡張メソッド化の例

既存コードでRGB値を多く扱っている場合は、拡張メソッドにすると便利です。

C#
public static class RgbExtensions
{
public static CmykColor ToCmyk(this RgbColor rgb)
{
return CmykColor.FromRgb(rgb.R, rgb.G, rgb.B);
}
}

使用例です。

C#
var rgb = new RgbColor(255, 200, 50);
var cmyk = rgb.ToCmyk();

Console.WriteLine(cmyk);

System.Drawing.Color を使うWindowsアプリであれば、次のような拡張メソッドも作れます。

C#
using System.Drawing;

public static class DrawingColorExtensions
{
public static CmykColor ToCmyk(this Color color)
{
return CmykColor.FromRgb(color.R, color.G, color.B);
}
}

ただし、クロスプラットフォーム環境では System.Drawing.Common の利用に制約があるため、WebアプリやLinuxサーバーでは独自の RgbColor 型や外部ライブラリの色型を使うほうが安全です。Microsoft Learn+1

4. C#で画像のCMYK変換を行う方法

4-1. BitmapやImageを使った画像処理の基本

Windows環境のC#では、BitmapImage を使って画像を読み込み、ピクセル単位でRGB値を取得できます。

C#
using System.Drawing;

using var bitmap = new Bitmap("input.jpg");

for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
{
Color color = bitmap.GetPixel(x, y);
CmykColor cmyk = color.ToCmyk();

// 必要に応じてCMYK値を利用する
}
}

ただし、GetPixel は処理が遅いため、大きな画像を扱う場合は LockBits を使うか、ImageSharpやMagick.NETなどのライブラリを使うほうが実務向きです。

また、この方法で取得しているのは基本的にRGB値です。元画像がCMYK JPEGだったとしても、読み込み時点でRGBに変換されている場合があります。CMYKのICCプロファイルや元の色空間を維持したい場合は、画像ライブラリの対応状況を確認する必要があります。

4-2. System.Drawingで扱える色空間の制約

System.Drawing は手軽ですが、印刷向けのCMYK処理には向いていません。CMYK値を直接保持する専用型がなく、画像読み込み時の色空間変換やICCプロファイルの扱いも、印刷工程を前提とした高度な制御には不足しがちです。

さらに、.NET 6 以降の System.Drawing.Common は、Windows以外のOSでサポートされません。Microsoftは、Windows以外では警告や実行時例外が発生することを説明し、クロスプラットフォーム用途では別の画像ライブラリを推奨しています。Microsoft Learn+1

そのため、C#でCMYK画像処理を行う場合は、次のように使い分けるのが現実的です。

Windows専用の簡易処理なら System.Drawing。クロスプラットフォームで画像処理を行うならImageSharp。ICCプロファイル変換や多形式対応を重視するならMagick.NET。PDFや印刷データ生成まで含むなら、PDFライブラリやプリフライトツールと組み合わせる、という考え方です。

4-3. ImageSharpなど外部ライブラリを使う選択肢

ImageSharpは、マネージド.NETで動作する画像処理ライブラリです。公式ドキュメントでは、JPEG、PNG、WebP、TIFF、GIFなどの形式に対応する画像処理モデルが説明されており、SixLabors.ImageSharp.ColorSpaces.Cmyk というCMYK色空間を表す構造体も用意されています。Six Labors Documentation+2Six Labors Documentation+2

ただし、ImageSharpでCMYKを扱う場合も、「CMYK値を表す型がある」ことと「すべての画像処理や保存で印刷向けCMYKを完全に維持できる」ことは同じではありません。画像ファイルの形式、ICCプロファイル、エンコーダー、デコーダーの対応を確認する必要があります。

CMYK画像の読み込み、ICCプロファイル変換、多数の画像形式への対応を重視する場合は、Magick.NETも選択肢になります。Magick.NETはImageMagickの.NETライブラリで、公式リポジトリではC#、VB.NET、.NET CoreアプリケーションからImageMagickを利用できることが説明されています。GitHub

Magick.NETでは、ICCプロファイルを使った色空間変換のサンプルも公開されています。たとえば、CMYKプロファイルを入力側に指定し、sRGBプロファイルへ変換してPNGとして保存する例が示されています。GitHub

4-4. 画像ファイルのCMYK情報を確認する方法

C#側で画像ファイルのCMYK情報を確認したい場合は、画像のメタデータ、ICCプロファイル、色空間情報を読み取れるライブラリを使います。ImageSharpにはICCプロファイルを表す IccProfile クラスがあり、画像のメタデータとしてプロファイルを扱えます。Six Labors Documentation

ただし、アプリケーション内で確認できる情報だけで印刷入稿の品質を保証するのは危険です。最終的な確認では、Adobe Acrobat Proの出力プレビュー、プリフライト機能、Ghostscript、印刷会社指定のチェックツールなどを使うのが一般的です。

C#で自動チェックを行う場合は、次の項目を確認できる設計にします。

画像にICCプロファイルが埋め込まれているか。想定外のRGB画像が混在していないか。解像度が印刷に十分か。透明効果やオーバープリントが想定どおりか。PDF内のテキストや図形の色空間がCMYKか。これらは単純なRGB/CMYK変換だけでは判断できません。

4-5. JPEG・TIFF・PNGでのCMYK対応の違い

画像形式によって、CMYKへの対応は異なります。

JPEGはCMYK画像を保持できる場合がありますが、読み込みライブラリによってRGBへ変換されることがあります。TIFFは印刷・DTP分野で使われることがあり、CMYKやICCプロファイルを扱えるケースがあります。PNGは基本的にWebや画面表示向けの形式であり、一般的な印刷用CMYK画像の受け渡しには向きません。

そのため、C#で印刷用画像を扱う場合は、ファイル拡張子だけで判断しないことが重要です。JPEGだからCMYKである、TIFFだから安全、PNGだから必ずRGB、という単純な判定ではなく、実際の色空間、ICCプロファイル、エンコード形式を確認しましょう。

5. 印刷向けにCMYKを扱う際の重要ポイント

5-1. ICCプロファイルとは何か

ICCプロファイルとは、デバイスや印刷条件ごとの色の特性を記述したファイルです。ディスプレイ、プリンター、印刷機、紙、インキなどによって色の再現範囲が異なるため、それらを変換・管理するために使われます。

CMYK値は、プロファイルなしでは厳密な色を意味しません。同じ C=70, M=40, Y=0, K=0 でも、使用するプロファイルや紙によって見え方が変わります。そのため、印刷向けのC#システムでは、「CMYK値だけを保存する」のではなく、「どのICCプロファイルを前提にしたCMYKか」も管理することが重要です。

ICCのプロファイルレジストリでは、Japan Color 2011 CoatedなどのCMYKプロファイル情報が登録されています。JapanColor2011Coated.iccは、Japan Printing Machinery Association提供のプロファイルとして登録されています。カラー登録所+1

5-2. 単純な数式変換とカラーマネジメントの違い

RGBからCMYKへの単純な数式変換は、プログラム上で簡単に実装できます。しかし、それは「一般的なCMYK値の近似」を求めているだけです。

カラーマネジメントでは、入力側のRGBプロファイルと、出力側のCMYKプロファイルを使って変換します。たとえば、sRGBからJapan Color 2011 Coatedへ変換する場合、単なる数式ではなく、それぞれの色空間の特性を考慮します。

Ghostscriptのカラーマネジメント説明でも、ICCワークフローでは入力色空間から出力色空間へICCプロファイルを使って変換する考え方が説明されています。ghostscript.readthedocs.io

印刷品質を重視する場合、C#で自作したRGB/CMYK変換式だけに依存するのではなく、ICCプロファイル対応のライブラリや印刷会社指定の変換フローを使うべきです。

5-3. Japan ColorやAdobe CMYKプロファイルの考え方

日本国内の印刷では、Japan Color系のプロファイルが使われることがあります。JapanColor2011 ICCプロファイルは、日本印刷産業機械工業会が提供するプロファイルとして案内されており、利用時にはライセンス契約への同意が必要です。Japan Color

また、AdobeはICCプロファイルのダウンロードページを提供しており、エンドユーザー向け、バンドル向けなどの区分があります。Adobeのバンドルライセンス説明では、Japan Color 2001 Coated、Japan Color 2001 Uncoated、Japan Color 2002 Newspaper、Web Coated SWOPなど複数のCMYKプロファイルが挙げられています。Adobe+1

実務では、開発者が勝手にプロファイルを決めるのではなく、印刷会社、デザイナー、DTP担当者に確認することが重要です。特に、コート紙、上質紙、新聞、パッケージ、オンデマンド印刷では、求められるプロファイルやPDF条件が変わります。

5-4. 印刷会社に入稿するデータで確認すべき項目

印刷会社に入稿するデータをC#で生成する場合は、次の項目を確認しましょう。

まず、PDFのカラーモードです。RGBが許可されるのか、CMYK必須なのか、特色を使ってよいのかを確認します。次に、ICCプロファイルです。Japan Color 2011 Coatedなのか、Japan Color 2001 Coatedなのか、印刷会社独自のプロファイルなのかを確認します。

さらに、画像解像度、塗り足し、トンボ、フォント埋め込み、透明効果、オーバープリント、リッチブラック、総インキ量、PDF/X指定なども確認が必要です。

C#でPDFを生成する場合、画面上で見た目が正しくても、印刷用PDFとして正しいとは限りません。生成後に必ずプリフライトチェックを行い、印刷会社のチェック結果と照合する運用が必要です。

5-5. PDF出力時に注意すべきCMYK設定

PDF出力時は、文字、線、塗り、画像のすべてについて色空間を確認します。本文テキストを黒にしたつもりでも、RGBの黒 R=0, G=0, B=0 としてPDFに入っている場合があります。この場合、印刷工程でCMYKへ変換され、意図しない4色掛け合わせの黒になることがあります。

小さな文字や細線では、K=100 のみを使うのが安全です。一方、背景の大きな黒ベタでは、深みを出すためにリッチブラックを使う場合があります。ただし、リッチブラックのCMYK値は印刷会社の指定に従うべきです。

PDF/AやPDF/Xなどの規格を意識する場合は、Output Intent、ICCプロファイル、DeviceRGBとDeviceCMYKの混在制限なども関係します。iTextのPDF/A関連APIでは、DeviceCMYKの利用にCMYK Output IntentやDefaultCMYKが関係する旨の例外メッセージも定義されています。iText API

6. C#でCMYK対応PDFや印刷データを作成する方法

6-1. PDFライブラリでCMYKカラーを指定する方法

C#でPDFにCMYKカラーを指定したい場合は、PDFライブラリがDeviceCMYKに対応しているかを確認します。RGB指定しかできないライブラリでは、印刷用CMYK PDFを厳密に作るのは難しくなります。

iTextでは、DeviceCmyk クラスが用意されており、C、M、Y、Kの値からCMYKカラーを作成できます。iText 9.1.0のAPIドキュメントでは、DeviceCmyk がシアン、マゼンタ、イエロー、ブラックの強度から色を作成するクラスとして説明されています。値は0〜100の整数、または0〜1のfloatで扱えます。iText API

また、PDFsharpにもCMYKカラーのサンプルがあり、XColor.FromCmyk を使う例が公開されています。PDFsharp+1

6-2. iText・PDFsharp・QuestPDFなどの利用例

iTextでCMYKカラーを使う場合のイメージは次のようになります。

C#
using iText.Kernel.Colors;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;

using var writer = new PdfWriter("cmyk-sample.pdf");
using var pdf = new PdfDocument(writer);
using var document = new Document(pdf);

var cmykBlack = new DeviceCmyk(0, 0, 0, 100);
var cmykRed = new DeviceCmyk(0, 100, 100, 0);

document.Add(new Paragraph("K100の黒テキスト")
.SetFontColor(cmykBlack));

document.Add(new Paragraph("CMYKの赤テキスト")
.SetFontColor(cmykRed));

PDFsharpでは、CMYKカラーを使う場合に次のような書き方ができます。

C#
using PdfSharp.Drawing;
using PdfSharp.Pdf;

var document = new PdfDocument();
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);

var cmykColor = XColor.FromCmyk(0.0, 1.0, 1.0, 0.0);
var brush = new XSolidBrush(cmykColor);

gfx.DrawString(
"CMYK Red",
new XFont("Arial", 20),
brush,
new XPoint(50, 100)
);

document.Save("pdfsharp-cmyk.pdf");

QuestPDFは、帳票やドキュメント作成に便利なライブラリですが、公式の色指定ドキュメントでは #RRGGBB 形式のHEXカラー、つまりRGBベースの指定が中心に説明されています。QuestPDF そのため、厳密なCMYK出力が必須の印刷用PDFでは、事前にCMYK対応の可否や生成PDFの中身を検証する必要があります。

6-3. テキストや図形にCMYKカラーを適用する方法

テキストや図形にCMYKカラーを適用する場合は、PDFライブラリの色指定APIがDeviceCMYKを出力しているかを確認します。

iTextでは、DeviceCmyk をフォント色や塗り色に設定できます。

C#
var cyan = new DeviceCmyk(100, 0, 0, 0);

document.Add(new Paragraph("C100のテキスト")
.SetFontColor(cyan));

図形を描画する場合も、線色や塗り色にCMYKカラーを指定します。

C#
using iText.Kernel.Geom;
using iText.Kernel.Pdf.Canvas;

var canvas = new PdfCanvas(pdf.GetFirstPage());

canvas.SetFillColor(new DeviceCmyk(70, 0, 100, 0));
canvas.Rectangle(50, 500, 200, 100);
canvas.Fill();

重要なのは、C#コード上でCMYK値を指定しているだけで満足しないことです。生成されたPDFを確認し、実際にPDF内部でDeviceCMYKとして記録されているかをチェックします。

6-4. 印刷用PDFでRGB混在を避けるポイント

印刷用PDFでRGB混在を避けるには、PDF生成時の入力素材をすべて確認する必要があります。

まず、画像です。CMYK PDFを作っているつもりでも、貼り込んだJPEGやPNGがRGBであれば、PDF内にRGB画像が混在する可能性があります。次に、ロゴやSVGです。SVGは一般的にRGBやCSSカラー指定が中心であり、CMYK指定には向かない場合があります。さらに、ライブラリのデフォルトカラーも注意が必要です。BlackRed といった定数がRGBとして定義されていることがあります。

iTextのAPIドキュメントでも、定義済みの ColorConstants.BLACK はDeviceRgbの黒として説明されており、色空間を意識する場合はDeviceCmykなどの色空間別クラスを使う必要があります。iText API

印刷用PDFでは、便利な色定数やHTMLカラーをそのまま使うのではなく、CMYK値を明示的に指定する方針にしましょう。

6-5. 生成後のPDFをチェックする方法

C#でPDFを生成した後は、必ず検証します。確認方法としては、Adobe Acrobat Proの出力プレビュー、プリフライト、Ghostscript、印刷会社のオンライン入稿チェックなどがあります。

チェックすべき項目は、RGBオブジェクトが残っていないか、CMYK値が意図どおりか、ICCプロファイルやOutput Intentが設定されているか、画像解像度が十分か、フォントが埋め込まれているか、透明効果が印刷で問題にならないか、などです。

Ghostscriptのカラーマネジメント機能では、Gray、RGB、CMYKのソースカラーに対するプロファイル情報を扱うICC Managerの考え方が説明されています。ghostscript.readthedocs.io このようなツールを直接または間接的に使うことで、C#で生成したPDFの検証や変換フローを自動化できる場合があります。

7. C#でCMYKを扱うときによくあるエラーと対処法

7-1. 変換後の色がくすんで見える原因

RGBからCMYKへ変換すると、色がくすんで見えることがあります。これはエラーではなく、RGBとCMYKの色域差による自然な現象です。

特に、鮮やかな青、緑、オレンジ、蛍光色に近い色は、CMYKで再現しにくい場合があります。画面上のRGBでは発光によって明るく鮮やかに見えていても、紙とインキでは同じように再現できません。

対処法は、最初から印刷向けのカラープロファイルでデザインすることです。C#側では、単純変換ではなく、指定されたICCプロファイルを使った変換を採用します。また、重要な印刷物では本機校正や簡易校正で実際の見え方を確認します。

7-2. 黒がリッチブラックになる問題

C#でRGBの黒 R=0, G=0, B=0 をPDFに出力し、後工程でCMYK変換されると、C=100, M=100, Y=100, K=100 に近い4色黒になったり、印刷会社のプロファイルに応じたリッチブラックになったりすることがあります。

本文テキストや細線でリッチブラックが使われると、版ズレによってにじみや色ズレが目立つ場合があります。

対処法は、黒文字や細線には明示的に C=0, M=0, Y=0, K=100 を指定することです。PDFライブラリで Black などの定数を使うとRGB黒になる場合があるため、印刷用PDFではDeviceCMYKの黒を明示的に作成しましょう。

7-3. CMYK画像を読み込むと色が反転・変化する問題

CMYK JPEGをC#で読み込んだときに、色が反転したように見えたり、極端に色が変わったりすることがあります。これは、読み込みライブラリがCMYK JPEG、ICCプロファイル、Adobe CMYK JPEGの扱いを正しく処理できていない場合に発生します。

対処法は、CMYK画像に対応したライブラリを使うことです。ImageSharpやMagick.NETなどを検討し、対象の画像形式とプロファイルでテストします。Magick.NETでは、ICCプロファイルを指定して色空間を変換するサンプルが公開されています。GitHub

また、ユーザーアップロード画像を扱うWebサービスでは、変換結果を必ずサムネイルやプレビューで確認できるようにし、元画像のプロファイル情報をログに残すとトラブル調査がしやすくなります。

7-4. ライブラリごとのCMYK対応差によるトラブル

C#のライブラリは、それぞれCMYK対応の範囲が異なります。あるライブラリではCMYK値を指定できても、画像のICCプロファイル変換には対応していない場合があります。逆に、画像変換には強くても、PDF内のテキストやベクター図形をDeviceCMYKで出力できない場合もあります。

たとえば、iTextにはDeviceCmykクラスがありますが、QuestPDFの公式カラー指定はRGB系のHEX指定が中心です。iText API+1 このように、同じPDF生成ライブラリでも、印刷向けCMYKの扱いやすさは異なります。

対処法は、ライブラリ選定時に次の項目を確認することです。

CMYKカラーを直接指定できるか。画像のICCプロファイルを保持できるか。PDFのOutput Intentを設定できるか。RGBとCMYKの混在を検出できるか。PDF/XやPDF/Aに対応できるか。商用利用時のライセンス条件に問題がないか。これらを事前に確認すると、開発後半での作り直しを避けやすくなります。

7-5. Windows環境とクロスプラットフォーム環境の違い

Windows環境だけで動かすアプリと、LinuxやDockerで動かすアプリでは、画像処理の選択肢が変わります。

Windowsデスクトップアプリでは、System.Drawing を使った簡易処理が可能です。しかし、ASP.NET CoreをLinuxコンテナで動かす場合や、クラウド上で画像変換を行う場合は、System.Drawing.Common に依存しない設計が必要です。Microsoftは、System.Drawing.Common がWindows以外でサポートされないことを説明しています。Microsoft Learn+1

クロスプラットフォーム対応を重視するなら、最初からImageSharp、SkiaSharp、Magick.NETなどを候補に入れ、実行環境、ライセンス、対応形式、パフォーマンスを検証しましょう。

8. C#のCMYK処理でおすすめの実装方針

8-1. 簡易的な色変換だけでよいケース

簡易的な色変換だけでよいケースでは、自作のRGB/CMYK変換クラスで十分です。

たとえば、管理画面でRGB色に対応するCMYK目安値を表示したい場合、デザイナー向けに参考値を出したい場合、印刷品質を保証しない簡易プレビューを作る場合などです。

この場合は、この記事で紹介した CmykColor クラスを使い、0〜1または0〜100の範囲チェックを行えば実装できます。ただし、画面上に「印刷結果を保証するものではない」ことを明記しておくと、ユーザーとの認識違いを避けられます。

8-2. 印刷品質を重視する場合の実装方針

印刷品質を重視する場合は、単純な数式変換ではなく、ICCプロファイルを使った変換を採用します。

入力画像がsRGBなのかAdobe RGBなのかを確認し、出力先のCMYKプロファイルを印刷会社に確認します。日本国内の一般的な印刷条件ではJapan Color系のプロファイルが指定されることがありますが、案件によって異なります。JapanColor2011Coated.iccはICCプロファイルレジストリにも登録されています。カラー登録所+1

C#アプリ側では、ICCプロファイルファイルを設定として管理し、変換処理をライブラリに任せます。変換後のPDFや画像は、プリフライトで検証します。重要な案件では、実際の印刷会社のチェックを通したサンプルデータを用意し、開発時のテストケースに含めると安全です。

8-3. 外部ライブラリを使うべきケース

次のような場合は、外部ライブラリを使うべきです。

CMYK JPEGやTIFFを正しく読み込みたい場合。ICCプロファイルを使ってRGBからCMYKへ変換したい場合。印刷用PDFでDeviceCMYKを指定したい場合。LinuxやDockerで画像処理を行いたい場合。PDF内の色空間やプロファイルを制御したい場合。大量画像を高速に変換したい場合。

画像処理ではImageSharpやMagick.NET、PDF生成ではiTextやPDFsharpなどが候補になります。ImageSharpにはCMYK色空間を表す構造体やICCプロファイル関連のAPIがあり、Magick.NETにはImageMagickの機能をC#から利用できる利点があります。Six Labors Documentation+2Six Labors Documentation+2

ただし、外部ライブラリを導入すればすべて解決するわけではありません。CMYK対応の範囲、ライセンス、商用利用条件、実行環境、メモリ使用量、脆弱性対応、メンテナンス状況も確認しましょう。

8-4. 印刷会社やデザイナーと連携する際の確認事項

C#でCMYKを扱うシステムを作る場合、開発者だけで仕様を決めないことが大切です。印刷会社やデザイナーと、次の項目を事前に確認しましょう。

使用するCMYKプロファイル。RGB入稿が許可されるか。PDF/Xの指定があるか。黒文字はK100でよいか。リッチブラックの推奨値。特色の扱い。画像解像度。塗り足し。フォント埋め込み。透明効果。オーバープリント。総インキ量の上限。チェック用PDFの提出方法。

これらが曖昧なままC#側で変換処理を作ると、生成データは正しく見えても、入稿時にエラーになる可能性があります。特に、PDFの色空間、ICCプロファイル、フォント、画像解像度は後から修正すると手戻りが大きくなりがちです。

8-5. C#でCMYKを安全に扱うための実務チェックリスト

C#でCMYK処理を実装する際は、次のチェックリストを使うと安全です。

RGB表示用の処理とCMYK印刷用の処理を分離しているか。CMYK値の範囲を0〜1または0〜100に統一しているか。黒文字や細線にK100を指定しているか。RGB黒をそのまま印刷用PDFに使っていないか。ICCプロファイルを設定で管理しているか。印刷会社指定のプロファイルを確認しているか。CMYK画像を読み込むライブラリの対応状況を確認しているか。System.Drawing.Common に依存しすぎていないか。LinuxやDockerで動作確認しているか。生成PDFをプリフライトで確認しているか。画像、図形、テキストにRGBが混在していないか。PDFライブラリのライセンスを確認しているか。

このチェックを通しておくことで、C#でCMYKを扱う際の典型的なトラブルを大きく減らせます。

まとめ

C#でCMYKを扱うには、まず「簡易的な数値変換」と「印刷品質を前提にしたカラーマネジメント」を分けて考えることが重要です。

RGBからCMYKへの簡易変換は、C#の計算式で実装できます。K = 1 - Max(R, G, B) を基準にC、M、Yを求める方法を使えば、RGB値から大まかなCMYK値を算出できます。独自の CmykColor クラスを作れば、値の範囲チェックやRGB変換も管理しやすくなります。

一方で、印刷向けの正確な色変換にはICCプロファイルが必要です。同じCMYK値でも、Japan Color、Adobe系プロファイル、紙、印刷方式によって結果は変わります。C#で印刷用PDFや画像を生成する場合は、印刷会社指定のプロファイルやPDF条件を確認し、生成後にプリフライトチェックを行うべきです。

画像処理では、System.Drawing だけに依存するとクロスプラットフォーム環境で問題になることがあります。Microsoftも、.NET 6 以降の System.Drawing.Common はWindows以外でサポートされないことを説明しています。Microsoft Learn+1 そのため、ImageSharp、Magick.NET、SkiaSharpなどの利用を検討しましょう。

PDF生成では、iTextの DeviceCmyk やPDFsharpの XColor.FromCmyk のように、CMYKを明示的に指定できるライブラリを選ぶと安全です。iText API+1

C#でCMYKを扱うポイントは、単に変換コードを書くことではありません。RGBとCMYKの役割を理解し、ICCプロファイル、PDF設定、画像形式、印刷会社の入稿条件まで含めて設計することです。簡易表示なら自作変換、印刷品質を求めるならカラーマネジメント対応ライブラリと検証フローを組み合わせる、という方針で実装すると、実務でも安全にCMYKを扱えます。