首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

GDI+ 進階議題:ICM 2.0 / WCS 1.0 色彩管理與 ICC 設定檔轉換

     編輯:關於.NET

非線性色彩轉換需求

ColorMatrix 僅支援仿射(線性)色彩變換。若需非線性轉換(如裝置色域對應、色調映射),須使用系統級色彩管理 API。Windows 早期提供 ICM 2.0 (Image Color Management),Vista 後升級為 WCS 1.0 (Windows Color System),實作 ICC 標準演算法,涵蓋顯示、裝置、色域映射等。詳細文件見 MSDN。

C# 封裝 ICM 2.0 API 實作 ICC 設定檔轉換

以下為完整封裝代碼,可直接呼叫 ICM.Convert(profilePath, imageFilePath, outputPath) 套用 ICC 設定檔轉換影像:

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace ICCConverter
{
    public class ICM
    {
        #region Constants
        const uint PROFILE_FILENAME = 1;
        const uint PROFILE_READ = 1;
        const uint FILE_SHARE_READ = 0x00000001;
        const uint OPEN_EXISTING = 3;
        const uint PROOF_MODE = 0x00000001;
        const uint NORMAL_MODE = 0x00000002;
        const uint BEST_MODE = 0x00000003;
        const uint ENABLE_GAMUT_CHECKING = 0x00010000;
        const uint USE_RELATIVE_COLORIMETRIC = 0x00020000;
        const uint FAST_TRANSLATE = 0x00040000;
        const int LCS_SIGNATURE = 0x50534F43; // "PSOC"
        #endregion

        #region Types
        public enum BMFORMAT
        {
            BM_x555RGB = 0x0000, BM_x555XYZ = 0x0101, BM_x555Yxy, BM_x555Lab, BM_x555G3CH,
            BM_RGBTRIPLETS = 0x0002, BM_BGRTRIPLETS = 0x0004, BM_XYZTRIPLETS = 0x0201, BM_YxyTRIPLETS,
            BM_LabTRIPLETS, BM_G3CHTRIPLETS, BM_5CHANNEL, BM_6CHANNEL, BM_7CHANNEL, BM_8CHANNEL,
            BM_GRAY, BM_xRGBQUADS = 0x0008, BM_xBGRQUADS = 0x0010, BM_xG3CHQUADS = 0x0304,
            BM_KYMCQUADS, BM_CMYKQUADS = 0x0020, BM_10b_RGB = 0x0009, BM_10b_XYZ = 0x0401,
            BM_10b_Yxy, BM_10b_Lab, BM_10b_G3CH, BM_NAMED_INDEX,
            BM_16b_RGB = 0x000A, BM_16b_XYZ = 0x0501, BM_16b_Yxy, BM_16b_Lab, BM_16b_G3CH,
            BM_16b_GRAY, BM_565RGB = 0x0001,
            BM_32b_scRGB = 0x0601, BM_32b_scARGB = 0x0602, BM_S2DOT13FIXED_scRGB = 0x0603,
            BM_S2DOT13FIXED_scARGB = 0x0604
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct CIEXYZ { public int ciexyzX, ciexyzY, ciexyzZ; }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct tagPROFILE { public uint dwType; public string pProfileData; public uint cbDataSize; }

        [StructLayout(LayoutKind.Sequential)]
        public struct CIEXYZTRIPLE { public CIEXYZ ciexyzRed, ciexyzGreen, ciexyBlue; }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        struct LOGCOLORSPACE
        {
            public uint Signature, Version, Size;
            public int CSType, Intent, GammaRed, GammaGreen, GammaBlue;
            public CIEXYZTRIPLE Endpoints;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
            public string Filename;
        }

        public enum GamutMappingIntent
        {
            LCS_GM_ABS_COLORIMETRIC = 0x00000008,
            LCS_GM_BUSINESS = 0x00000001,
            LCS_GM_GRAPHICS = 0x00000002,
            LCS_GM_IMAGES = 0x00000004
        }

        public enum LogicalColorSpace
        {
            LCS_CALIBRATED_RGB = 0x00000000,
            LCS_sRGB = 0x73524742,
            LCS_WINDOWS_COLOR_SPACE = 0x57696E20
        }
        #endregion

        public delegate bool ICMProgressProcCallback(uint ulMax, uint ulCurrent, int ulCallbackData);

        [DllImport("mscms.dll", SetLastError = true)]
        static extern IntPtr OpenColorProfile(ref tagPROFILE pProfile, uint AccessMode, uint ShareMode, uint CreateMode);

        [DllImport("mscms.dll", SetLastError = true)]
        static extern bool TranslateBitmapBits(IntPtr pTransform, IntPtr inBuffer, BMFORMAT inFormat, uint width, uint height, uint stride, IntPtr outBuffer, BMFORMAT outFormat, uint outStride, ICMProgressProcCallback pfCallback, int CallBackParam);

        [DllImport("mscms.dll", SetLastError = true)]
        static extern bool CloseColorProfile(IntPtr profile);

        [DllImport("mscms.dll", SetLastError = true)]
        static extern bool DeleteColorTransform(IntPtr transform);

        [DllImport("mscms.dll", SetLastError = true)]
        static extern IntPtr CreateColorTransform(ref LOGCOLORSPACE pLogColorSpace, IntPtr hDestProfile, IntPtr hTargetProfile, uint dwFlags);

        public void Convert(string profilePath, string imageFilePath, string outputPath)
        {
            LOGCOLORSPACE logColorSpace = new LOGCOLORSPACE();
            logColorSpace.Signature = LCS_SIGNATURE;
            logColorSpace.Intent = (int)GamutMappingIntent.LCS_GM_IMAGES;
            logColorSpace.Version = 0x0400;
            logColorSpace.Size = (uint)Marshal.SizeOf(logColorSpace);
            logColorSpace.CSType = (int)LogicalColorSpace.LCS_sRGB;

            IntPtr destProfile;
            tagPROFILE profile = new tagPROFILE();
            profile.dwType = PROFILE_FILENAME;
            profile.pProfileData = profilePath;
            profile.cbDataSize = (uint)profile.pProfileData.Length + 1;
            destProfile = OpenColorProfile(ref profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);

            IntPtr pTransforms = CreateColorTransform(ref logColorSpace, destProfile, IntPtr.Zero, BEST_MODE);

            if (pTransforms != IntPtr.Zero)
            {
                FileStream fs = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read);
                Bitmap bmpTemp = (Bitmap)Image.FromStream(fs, false, false);
                Bitmap bmp = new Bitmap(bmpTemp);
                fs.Close();
                bmpTemp.Dispose();

                BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                bool success = TranslateBitmapBits(
                    pTransforms,
                    bmData.Scan0,
                    BMFORMAT.BM_RGBTRIPLETS,
                    (uint)bmData.Width,
                    (uint)bmData.Height,
                    (uint)bmData.Stride,
                    bmData.Scan0,
                    BMFORMAT.BM_RGBTRIPLETS,
                    (uint)bmData.Stride, null, 0);

                bmp.UnlockBits(bmData);
                bmp.Save(outputPath, ImageFormat.Jpeg);
                CloseColorProfile(destProfile);
                DeleteColorTransform(pTransforms);
            }
            else
            {
                int errorCode = Marshal.GetLastWin32Error();
                throw new System.Runtime.InteropServices.COMException("Error", errorCode);
            }
        }
    }
}

此功能屬系統級色彩管理,尚未內建於 .NET Framework,期待未來版本原生支援以簡化開發。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved