C#使用ICC配置文件将RGB值转换为CMYK?

这个问题似乎发布在很多地方的interwebs和SO,但我找不到一个满意的答案:(

如何使用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#的包装器,我会看到两个选项:

  • Windows Color System(WCS) (Windows的一部分)
  • LittleCMS

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); } } } 

这里的答案似乎都没有令人满意地解决使用ICC配置文件的需要。

我找到了一个MS Connect问题页面,其中包含一些使用Windows Imaging Components的示例代码,可以使用ICC配置文件将RBG JPEG转换为CMYK。

如果您有ICC文件和示例JPEG文件,则可以设置控制台应用程序以非常快速地使用此代码。

我已将ICC配置文件保存在名为“配置文件”的文件夹中,并将“复制到输出目录”值设置为“始终”。

JPEG保存到名为“Images”的文件夹中,我将其“Build Action”值设置为“Embedded Resource”。

控制台应用程序项目需要对以下模块的引用:

  • PresentationCore
  • System.Xaml
  • WindowsBase

完整的控制台应用程序(名为CMYKConversion):

Program.cs中:

 using System; namespace CMYKConversion { class Program { static void Main(string[] args) { Converter c = new Converter(); c.Convert(); Console.ReadKey(); } } } 

Converter.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(); } } } 

根据MVP,GDI +可以读取CMYK但不能对其进行编码(来源: http : //www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html )。 他们继续说使用TIF作为中介格式可能是要走的路。

除此之外,您可以在http://imaging.aurigma.com/上尝试使用Graphics Mill Imaging for .NET(我不隶属于该公司)。

我知道这不是一个很好的答案,但希望它能够提供一些亮点并指出你正确的方向。

您可以看一下: 将RGB颜色转换为CMYK?

虽然这种转换是相当主观的,因此需要ICC配置文件,但您可以从ICC中提取“因子”并调整公式?

您需要将RGB值转换为CMYK的上下文是什么?