/// <summary> /// Initializes a new instance of the <see cref="ColorProfileConverter"/> class. /// </summary> public ColorProfileConverter() { documentProfile = null; monitorProfile = null; transform = null; colorCorrectionRequired = false; disposed = false; }
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); } }
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(); } } }
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); }
/// <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); }