C # преобразовать значение RGB в CMYK, используя профиль ICC? - PullRequest
16 голосов
/ 08 марта 2011

этот вопрос, похоже, был опубликован во многих местах через паутину и SO, но я не смог найти удовлетворительного ответа: (

Как преобразовать значение RGB в значение CMYK с помощью профиля ICC?

Самый близкий ответ, который у меня есть, там, где объясняется, как конвертировать из CMYK в RGB, а не наоборот, и это то, что мне нужно. (/2657906/cmyk-dlya-rgb-formuly-photoshop#2657913)

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, но я не могу получить значения CMYK после этого System.Windows.Media.Color!

Большое спасибо

Ответы [ 4 ]

12 голосов
/ 09 марта 2011

Я не знаю ни одного C # API или библиотеки, которая могла бы достичь этого.Однако, если у вас достаточно знаний C / C ++ для создания оболочки для C #, я вижу два варианта:

Пространство имен System.Windows.Media очень ограничено.Возможно, за этим стоит мощный движок (WCS?), Но доступна только небольшая часть.

Обновление:

Вот код C #, который можно выполнить с помощью преобразованияWCS.Конечно, он может использовать оболочку, которая облегчит использование:

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 голосов
/ 22 августа 2011

Похоже, что ни один из ответов здесь удовлетворительно не говорит о необходимости использования профиля ICC.

Я обнаружил страницу с сообщением о проблеме MS Connect, содержащую пример кода с использованием компонентов обработки изображений Windows для преобразованияRBG JPEG в CMYK с использованием профиля ICC.

Если у вас есть ICC-файл и пример файла JPEG, вы можете настроить консольное приложение на использование этого кода очень быстро.

Я сохранил профиль ICC в папке с именем «Профили» и установил для параметра «Копировать в каталог вывода» значение «Всегда».

JPEG сохраняется в папке с именем «Изображения », и я установил его значение« 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();
        }
    }
}
0 голосов
/ 11 марта 2011

Вы могли бы взглянуть на это: Конвертировать цвет RGB в CMYK?

Хотя это преобразование является довольно субъективным, отсюда и необходимость в профиле ICC, возможно, вы можетеизвлечь этот «фактор» из ICC и скорректировать формулу?

В каком контексте вам нужно преобразовать значения RGB в CMYK?

0 голосов
/ 09 марта 2011

Согласно MVP, GDI + может читать CMYK, но не может его кодировать (Источник: http://www.pcreview.co.uk/forums/convert-rgb-image-cmyk-t1419911.html). Они продолжают говорить, что использование TIF в качестве промежуточного формата может быть правильным способом.

Кроме этого, вы можете попробовать SDK Graphics Mill для .NET на http://imaging.aurigma.com/ (я не связан с этой компанией).

Я знаю, что это не слишком хороший ответ, но, надеюсь, он проливает некоторый свет и направляет вас в правильном направлении.

...