这个问题似乎在互联网上的很多地方都有发布,但我找不到满意的答案:(
如何使用 ICC 配置文件将 RGB 值转换为 CMYK 值?
我得到的最接近的答案就在那里,它解释了如何从 CMYK 转换为 RGB,而不是相反,这正是我所需要的。 (http://stackoverflow.com/questions/4920482/cmyk-to-rgb-formula-of-photoshop/5076731#5076731)
float[] colorValues = new float[4];
colorValues[0] = c / 255f;
colorValues[1] = m / 255f;
colorValues[2] = y / 255f;
colorValues[3] = k / 255f;
System.Windows.Media.Color color = Color.FromValues(colorValues,
new Uri(@"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc"));
System.Drawing.Color rgbColor = System.Drawing.Color.FromArgb(color.R, color.G, color.B);
我想我应该使用 System.Windows.Media 命名空间中的一些类/结构/方法。
System.Windows.Media.Color 结构包含一个 FromRgb 方法,但之后我无法从该 System.Windows.Media.Color 中获取 CMYK 值!
非常感谢
我不知道有任何 C# API 或库可以实现此目的。但是,如果您有足够的 C/C++ 知识来构建 C# 的包装器,我会看到两个选择:
System.Windows.Media命名空间非常有限。背后可能有一个强大的引擎(WCS?),但只提供了一小部分。
更新:
这里有一些使用 WCS 进行转换的 C# 代码。它当然可以使用一个包装器,使其更易于使用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ICM
{
public class WindowsColorSystem
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class ProfileFilename
{
public uint type;
[MarshalAs(UnmanagedType.LPTStr)]
public string profileData;
public uint dataSize;
public ProfileFilename(string filename)
{
type = ProfileFilenameType;
profileData = filename;
dataSize = (uint)filename.Length * 2 + 2;
}
};
public const uint ProfileFilenameType = 1;
public const uint ProfileMembufferType = 2;
public const uint ProfileRead = 1;
public const uint ProfileReadWrite = 2;
public enum FileShare : uint
{
Read = 1,
Write = 2,
Delete = 4
};
public enum CreateDisposition : uint
{
CreateNew = 1,
CreateAlways = 2,
OpenExisting = 3,
OpenAlways = 4,
TruncateExisting = 5
};
public enum LogicalColorSpace : uint
{
CalibratedRGB = 0x00000000,
sRGB = 0x73524742,
WindowsColorSpace = 0x57696E20
};
public enum ColorTransformMode : uint
{
ProofMode = 0x00000001,
NormalMode = 0x00000002,
BestMode = 0x00000003,
EnableGamutChecking = 0x00010000,
UseRelativeColorimetric = 0x00020000,
FastTranslate = 0x00040000,
PreserveBlack = 0x00100000,
WCSAlways = 0x00200000
};
enum ColorType : int
{
Gray = 1,
RGB = 2,
XYZ = 3,
Yxy = 4,
Lab = 5,
_3_Channel = 6,
CMYK = 7,
_5_Channel = 8,
_6_Channel = 9,
_7_Channel = 10,
_8_Channel = 11,
Named = 12
};
public const uint IntentPerceptual = 0;
public const uint IntentRelativeColorimetric = 1;
public const uint IntentSaturation = 2;
public const uint IntentAbsoluteColorimetric = 3;
public const uint IndexDontCare = 0;
[StructLayout(LayoutKind.Sequential)]
public struct RGBColor
{
public ushort red;
public ushort green;
public ushort blue;
public ushort pad;
};
[StructLayout(LayoutKind.Sequential)]
public struct CMYKColor
{
public ushort cyan;
public ushort magenta;
public ushort yellow;
public ushort black;
};
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "OpenColorProfileW", CallingConvention = CallingConvention.Winapi)]
static extern IntPtr OpenColorProfile(
[MarshalAs(UnmanagedType.LPStruct)] ProfileFilename profile,
uint desiredAccess,
FileShare shareMode,
CreateDisposition creationMode);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool CloseColorProfile(IntPtr hProfile);
[DllImport("mscms.dll", SetLastError = true, EntryPoint = "GetStandardColorSpaceProfileW", CallingConvention = CallingConvention.Winapi)]
static extern bool GetStandardColorSpaceProfile(
uint machineName,
LogicalColorSpace profileID,
[MarshalAs(UnmanagedType.LPTStr), In, Out] StringBuilder profileName,
ref uint size);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern IntPtr CreateMultiProfileTransform(
[In] IntPtr[] profiles,
uint nProfiles,
[In] uint[] intents,
uint nIntents,
ColorTransformMode flags,
uint indexPreferredCMM);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool DeleteColorTransform(IntPtr hTransform);
[DllImport("mscms.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
static extern bool TranslateColors(
IntPtr hColorTransform,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), In] RGBColor[] inputColors,
uint nColors,
ColorType ctInput,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2), Out] CMYKColor[] outputColors,
ColorType ctOutput);
public static void Test()
{
bool success;
StringBuilder profileName = new StringBuilder(256);
uint size = (uint)profileName.Capacity * 2;
success = GetStandardColorSpaceProfile(0, LogicalColorSpace.sRGB, profileName, ref size);
ProfileFilename sRGBFilename = new ProfileFilename(profileName.ToString());
IntPtr hSRGBProfile = OpenColorProfile(sRGBFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
ProfileFilename isoCoatedFilename = new ProfileFilename(@"C:\Users\me\Documents\ISOcoated_v2_300_eci.icc");
IntPtr hIsoCoatedProfile = OpenColorProfile(isoCoatedFilename, ProfileRead, FileShare.Read, CreateDisposition.OpenExisting);
IntPtr[] profiles = new IntPtr[] { hSRGBProfile, hIsoCoatedProfile };
uint[] intents = new uint[] { IntentPerceptual };
IntPtr transform = CreateMultiProfileTransform(profiles, 2, intents, 1, ColorTransformMode.BestMode, IndexDontCare);
RGBColor[] rgbColors = new RGBColor[1];
rgbColors[0] = new RGBColor();
CMYKColor[] cmykColors = new CMYKColor[1];
cmykColors[0] = new CMYKColor();
rgbColors[0].red = 30204;
rgbColors[0].green = 4420;
rgbColors[0].blue = 60300;
success = TranslateColors(transform, rgbColors, 1, ColorType.RGB, cmykColors, ColorType.CMYK);
success = DeleteColorTransform(transform);
success = CloseColorProfile(hSRGBProfile);
success = CloseColorProfile(hIsoCoatedProfile);
}
}
}
我发现一个 MS Connect 问题页面,其中包含一些
使用 Windows 成像组件的示例代码,以使用 ICC 配置文件将 RBG JPEG 转换为 CMYK。
如果您有 ICC 文件和示例 JPEG 文件,您可以设置控制台应用程序以非常快速地使用此代码。我已将 ICC 配置文件保存在名为“Profiles”的文件夹中,并将“复制到输出目录”值设置为“始终”。
JPEG 保存到名为“Images”的文件夹中,我已将其“Build Action”值设置为“Embedded Resource”。
控制台应用程序项目需要引用以下模块:
程序.cs:
using System;
namespace CMYKConversion
{
class Program
{
static void Main(string[] args)
{
Converter c = new Converter();
c.Convert();
Console.ReadKey();
}
}
}
转换器.cs:
using System;
using System.IO;
using System.Reflection;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace CMYKConversion
{
public class Converter
{
public void Convert()
{
var rgbJpeg = BitmapFrame.Create(GetStreamFromResource("CMYKConversion.Images.Desert.jpg"));
var iccCmykJpeg = new ColorConvertedBitmap(
rgbJpeg,
new ColorContext(PixelFormats.Default),
new ColorContext(GetProfilePath("Profiles/1010_ISO_Coated_39L.icc")),
PixelFormats.Cmyk32
);
var jpegBitmapEncoder = new JpegBitmapEncoder();
jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(iccCmykJpeg));
var iccCmykJpegStream = new MemoryStream();
jpegBitmapEncoder.Save(iccCmykJpegStream);
iccCmykJpegStream.Flush();
SaveMemoryStream(iccCmykJpegStream, "C:\\desertCMYK.jpg");
iccCmykJpegStream.Close();
}
private Stream GetStreamFromResource(string name)
{
return typeof(Program).Assembly.GetManifestResourceStream(name);
}
private Uri GetProfilePath(string name)
{
string folder = Path.GetDirectoryName(Assembly.GetAssembly(typeof(Program)).CodeBase);
return new Uri(Path.Combine(folder, name));
}
private void SaveMemoryStream(MemoryStream ms, string fileName)
{
FileStream outStream = File.OpenWrite(fileName);
ms.WriteTo(outStream);
outStream.Flush();
outStream.Close();
}
}
}
http://www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html)。他们接着说,使用 TIF 作为中介格式可能是正确的选择。
除此之外,您还可以在http://imaging.aurigma.com/ 尝试适用于 .NET 的 Graphics Mill 成像 SDK(我不隶属于该公司)。
我知道这不是一个很好的答案,但希望它能给您带来一些启发并为您指明正确的方向。
Unicolour .NET 库中使用 ICC 配置文件进行 RGB 到 CMYK 转换(或反向转换)。它是一个独立的跨平台库,不依赖于任何 CMS。
以下是如何使用 ICC 配置文件转换 sRGB 紫色的示例ISOcoated_v2_300_eci.icc
:
var isoCoated = new IccConfiguration("./ISOcoated_v2_300_eci.icc", Intent.RelativeColorimetric);
var config = new Configuration(iccConfiguration: isoCoated);
var purple = new Unicolour(config, ColourSpace.Rgb, 0.5, 0, 0.5);
Console.WriteLine(purple.Icc); // 0.6003 1.0000 0.0024 0.0114 CMYK