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

问题描述 投票:0回答:5

这个问题似乎在互联网上的很多地方都有发布,但我找不到满意的答案:(

如何使用 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# printing colors rgb cmyk
5个回答
12
投票

我不知道有任何 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); } } }
    

2
投票
这里的答案似乎都不能令人满意地解决使用 ICC 配置文件的需要。

我发现一个 MS Connect 问题页面,其中包含一些

使用 Windows 成像组件的示例代码,以使用 ICC 配置文件将 RBG JPEG 转换为 CMYK。

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

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

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

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

    演示核心
  • 系统.Xaml
  • WindowsBase
完整的控制台应用程序(名为 CMYKConversion):

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

1
投票
根据 MVP,GDI+ 可以读取 CMYK,但无法对其进行编码(来源:

http://www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html)。他们接着说,使用 TIF 作为中介格式可能是正确的选择。

除此之外,您还可以在

http://imaging.aurigma.com/ 尝试适用于 .NET 的 Graphics Mill 成像 SDK(我不隶属于该公司)。

我知道这不是一个很好的答案,但希望它能给您带来一些启发并为您指明正确的方向。


1
投票
您可以看看这个:

将 RGB 颜色转换为 CMYK?

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

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


0
投票
对于未来的访问者:如果您不想为颜色管理系统构建包装器或解析 ICC 文件本身,可以在我的

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
    
© www.soinside.com 2019 - 2024. All rights reserved.