/// <summary>
 /// Initializes a new instance of the <see cref="ColorProfileConverter"/> class.
 /// </summary>
 public ColorProfileConverter()
 {
     documentProfile         = null;
     monitorProfile          = null;
     transform               = null;
     colorCorrectionRequired = false;
     disposed = false;
 }
Example #2
0
    public static unsafe RGBQUAD[] TransformColorsTo_sRGB(SafeProfileHandle source, RGBQUAD[] color, mscmsIntent dwIntent)
    {
        var colorSize = Environment.Is64BitProcess ? 16 : 8;
        var size      = colorSize * color.Length;

        // https://docs.microsoft.com/en-us/windows/win32/api/icm/nf-icm-translatecolors
        // https://docs.microsoft.com/en-us/windows/win32/api/icm/ns-icm-color

        IntPtr paInputColors  = Marshal.AllocHGlobal(size);
        IntPtr paOutputColors = Marshal.AllocHGlobal(size);

        const double cmax  = 255d;
        const double nmax  = 0xFFFF;
        const ushort nmask = 0xFFFF;

        try
        {
            var inputPtr = (byte *)paInputColors;
            foreach (var c in color)
            {
                var nclr = (long)(c.rgbRed / cmax * nmax) | ((long)(c.rgbGreen / cmax * nmax) << 16) | ((long)(c.rgbBlue / cmax * nmax) << 32);
                *((long *)inputPtr) = nclr;
                inputPtr           += colorSize;
            }

            using (var dest = OpenProfile_sRGB())
                using (var transform = CreateTransform(source, dest, dwIntent))
                {
                    var success = TranslateColors(transform, paInputColors, (uint)color.Length, COLOR_TYPE.COLOR_3_CHANNEL, paOutputColors, COLOR_TYPE.COLOR_3_CHANNEL);
                    if (!success)
                    {
                        throw new Win32Exception();
                    }

                    var outputPtr = (byte *)paOutputColors;
                    var output    = new RGBQUAD[color.Length];
                    for (int i = 0; i < color.Length; i++)
                    {
                        long nclr = *((long *)outputPtr);
                        output[i] = new RGBQUAD
                        {
                            rgbRed   = (byte)((nclr & nmask) / nmax * cmax),
                            rgbGreen = (byte)(((nclr >> 16) & nmask) / nmax * cmax),
                            rgbBlue  = (byte)(((nclr >> 32) & nmask) / nmax * cmax),
                        };
                        outputPtr += colorSize;
                    }

                    return(output);
                }
        }
        finally
        {
            Marshal.FreeHGlobal(paInputColors);
            Marshal.FreeHGlobal(paOutputColors);
        }
    }
Example #3
0
 public static unsafe void TransformPixelsTo_sRGB(SafeProfileHandle source, mscmsPxFormat pxFormat, void *data, int width, int height, uint stride, mscmsIntent dwIntent)
 {
     using (var dest = OpenProfile_sRGB())
         using (var transform = CreateTransform(source, dest, dwIntent))
         {
             var success = TranslateBitmapBits(transform, data, pxFormat, (uint)width, (uint)height, stride, data, pxFormat, stride, IntPtr.Zero, IntPtr.Zero);
             if (!success)
             {
                 throw new Win32Exception();
             }
         }
 }
Example #4
0
    public static SafeTransformHandle CreateTransform(SafeProfileHandle sourceProfile, SafeProfileHandle destinationProfile, mscmsIntent dwIntent)
    {
        if (sourceProfile == null || sourceProfile.IsInvalid)
        {
            throw new ArgumentNullException("sourceProfile");
        }

        if (destinationProfile == null || destinationProfile.IsInvalid)
        {
            throw new ArgumentNullException("destinationProfile");
        }

        IntPtr[] handles = new IntPtr[2];
        bool     success = true;

        sourceProfile.DangerousAddRef(ref success);
        destinationProfile.DangerousAddRef(ref success);

        try
        {
            handles[0] = sourceProfile.DangerousGetHandle();
            handles[1] = destinationProfile.DangerousGetHandle();

            uint[] dwIntents = new uint[2] {
                (uint)dwIntent, (uint)dwIntent
            };

            var htransform = CreateMultiProfileTransform(
                handles, (uint)handles.Length,
                dwIntents, (uint)dwIntents.Length,
                BEST_MODE | USE_RELATIVE_COLORIMETRIC, 0);

            if (htransform.IsInvalid)
            {
                throw new Win32Exception();
            }

            return(htransform);
        }
        finally
        {
            sourceProfile.DangerousRelease();
            destinationProfile.DangerousRelease();
        }
    }
        /// <summary>
        /// Initializes the color profile converter.
        /// </summary>
        /// <param name="colorProfiles">The <see cref="HostColorManagement"/> containing the document and monitor profiles.</param>
        /// <exception cref="ArgumentNullException"><paramref name="colorProfiles"/> is null.</exception>
        public void Initialize(HostColorManagement colorProfiles)
        {
            if (colorProfiles == null)
            {
                throw new ArgumentNullException(nameof(colorProfiles));
            }

            int result = OpenColorProfile(colorProfiles.GetDocumentProfileReadOnly(), out documentProfile);

            if (result != NativeConstants.ERROR_SUCCESS)
            {
                HandleError(result, Resources.OpenDocumentColorProfileError);
            }

            result = OpenColorProfile(colorProfiles.GetMonitorProfileReadOnly(), out monitorProfile);
            if (result != NativeConstants.ERROR_SUCCESS)
            {
                HandleError(result, Resources.OpenMonitorColorProfileError);
            }

            colorCorrectionRequired = ColorProfilesAreDifferent();
            if (colorCorrectionRequired)
            {
                result = CreateColorTransform(documentProfile, monitorProfile, out transform);
                if (result != NativeConstants.ERROR_SUCCESS)
                {
                    HandleError(result, Resources.CreateTransformError);
                }
            }
            else
            {
                documentProfile.Dispose();
                documentProfile = null;

                monitorProfile.Dispose();
                monitorProfile = null;
            }
        }
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!disposed)
            {
                if (documentProfile != null)
                {
                    documentProfile.Dispose();
                    documentProfile = null;
                }
                if (monitorProfile != null)
                {
                    monitorProfile.Dispose();
                    monitorProfile = null;
                }
                if (transform != null)
                {
                    transform.Dispose();
                    transform = null;
                }

                disposed = true;
            }
        }
        /// <summary>
        /// Opens a color profile from the specified byte array.
        /// </summary>
        /// <param name="profileBytes">The byte array containing the color profile.</param>
        /// <param name="handle">The <see cref="SafeProfileHandle"/> of the opened color profile.</param>
        /// <returns>A Win32 error code indicating if the profile was opened successfully.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="profileBytes" /> is null.</exception>
        private static int OpenColorProfile(byte[] profileBytes, out SafeProfileHandle handle)
        {
            if (profileBytes == null)
            {
                throw new ArgumentNullException(nameof(profileBytes));
            }

            handle = null;
            int error = NativeConstants.ERROR_SUCCESS;

            unsafe
            {
                fixed(byte *ptr = profileBytes)
                {
                    NativeStructs.Mscms.PROFILE profile = new NativeStructs.Mscms.PROFILE
                    {
                        dwType       = NativeEnums.Mscms.ProfileType.MemoryBuffer,
                        pProfileData = (void *)ptr,
                        cbDataSize   = (uint)profileBytes.Length
                    };

                    handle = UnsafeNativeMethods.Mscms.OpenColorProfileW(
                        ref profile,
                        NativeEnums.Mscms.ProfileAccess.Read,
                        NativeEnums.FileShare.Read,
                        NativeEnums.CreationDisposition.OpenExisting
                        );

                    if (handle == null || handle.IsInvalid)
                    {
                        error = Marshal.GetLastWin32Error();
                    }
                }
            }

            return(error);
        }
Example #8
0
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!disposed)
            {
                if (documentProfile != null)
                {
                    documentProfile.Dispose();
                    documentProfile = null;
                }

                if (monitorProfile != null)
                {
                    monitorProfile.Dispose();
                    monitorProfile = null;
                }

                if (transform != null)
                {
                    transform.Dispose();
                    transform = null;
                }

                if (interleavedCMYKSurface != null)
                {
                    interleavedCMYKSurface.Dispose();
                    interleavedCMYKSurface = null;
                }

                if (interleavedRGBSurface != null)
                {
                    interleavedRGBSurface.Dispose();
                    interleavedRGBSurface = null;
                }

                disposed = true;
            }
        }
        private static int CreateColorTransform(SafeProfileHandle input, SafeProfileHandle output, out SafeTransformHandle handle)
        {
            if (input == null)
            {
                throw new ArgumentNullException(nameof(input));
            }
            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }
#if DEBUG
            System.Diagnostics.Debug.Assert(!input.IsInvalid, "Input handle is invalid.");
            System.Diagnostics.Debug.Assert(!output.IsInvalid, "Output handle is invalid.");
#endif

            handle = null;

            int error = NativeConstants.ERROR_SUCCESS;

            bool inputNeedsRelease  = false;
            bool outputNeedsRelease = false;
            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                input.DangerousAddRef(ref inputNeedsRelease);
                output.DangerousAddRef(ref outputNeedsRelease);

                IntPtr[] profiles = new IntPtr[2] {
                    input.DangerousGetHandle(), output.DangerousGetHandle()
                };
                uint[] intents = new uint[2]
                {
                    (uint)NativeEnums.Mscms.RenderingIntent.Perceptual,
                    (uint)NativeEnums.Mscms.RenderingIntent.Perceptual
                };

                handle = UnsafeNativeMethods.Mscms.CreateMultiProfileTransform(
                    profiles,
                    (uint)profiles.Length,
                    intents,
                    (uint)intents.Length,
                    NativeEnums.Mscms.TransformFlags.BestMode,
                    NativeConstants.CMM_FROM_PROFILE
                    );

                if (handle == null || handle.IsInvalid)
                {
                    error = Marshal.GetLastWin32Error();
                }
            }
            finally
            {
                if (inputNeedsRelease)
                {
                    input.DangerousRelease();
                }
                if (outputNeedsRelease)
                {
                    output.DangerousRelease();
                }
            }

            return(error);
        }