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

                if (this.displayProfile != null)
                {
                    this.displayProfile.Dispose();
                    this.displayProfile = null;
                }

                if (this.proofingProfile != null)
                {
                    this.proofingProfile.Dispose();
                    this.proofingProfile = null;
                }

                if (this.proofingTransform != null)
                {
                    this.proofingTransform.Dispose();
                    this.proofingTransform = null;
                }
                this.proofingTransformIsValid = false;
                this.disposed = true;
            }
        }
        private void Reset()
        {
            if (this.inputProfile != null)
            {
                this.inputProfile.Dispose();
                this.inputProfile = null;
            }

            if (this.displayProfile != null)
            {
                this.displayProfile.Dispose();
                this.displayProfile = null;
            }

            if (this.proofingProfile != null)
            {
                this.proofingProfile.Dispose();
                this.proofingProfile = null;
            }

            if (this.proofingTransform != null)
            {
                this.proofingTransform.Dispose();
                this.proofingTransform = null;
            }
            this.inputProfilePath         = null;
            this.displayProfilePath       = null;
            this.proofingProfilePath      = null;
            this.proofingTransformIsValid = false;
        }
        /// <summary>
        /// Changes the rendering intent of the color profile to the specified <see cref="RenderingIntent" /> and saves the profile to a new file.
        /// </summary>
        /// <param name="profilePath">The path of the color profile.</param>
        /// <param name="renderingIntent">The rendering intent to use for the color profile.</param>
        /// <param name="newProfileFileName">The path of the color profile with the new rendering intent.</param>
        /// <returns><c>true</c> if the rendering intent was changed; otherwise, <c>false</c>.</returns>
        /// <exception cref="LCMSException">
        /// The color profile could not be opened.
        /// -or-
        /// An error occurred saving the profile with the new rendering intent.
        /// </exception>
        internal static bool ChangeProfileRenderingIntent(string profilePath, RenderingIntent renderingIntent, out string newProfileFileName)
        {
            newProfileFileName = null;
            bool renderingIntentChanged = false;

            using (LCMSProfileHandle profile = LCMSHelper.OpenColorProfile(profilePath))
            {
                if (profile.IsInvalid)
                {
                    throw new LCMSException(Resources.OpenDestiniationProfileError);
                }

                RenderingIntent profileRenderingIntent = LCMSHelper.GetProfileRenderingIntent(profile);

                if (profileRenderingIntent != renderingIntent)
                {
                    LCMSHelper.SetProfileRenderingIntent(profile, renderingIntent);

                    newProfileFileName = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

                    if (!LCMSHelper.SaveColorProfile(profile, newProfileFileName))
                    {
                        throw new LCMSException(Resources.ChangeRenderingIntentError);
                    }

                    renderingIntentChanged = true;
                }
            }

            return(renderingIntentChanged);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ColorManagement"/> class.
 /// </summary>
 public ColorManagement()
 {
     this.inputProfile             = null;
     this.displayProfile           = null;
     this.proofingProfile          = null;
     this.proofingTransform        = null;
     this.inputProfilePath         = null;
     this.displayProfilePath       = null;
     this.proofingProfilePath      = null;
     this.proofingTransformIsValid = false;
     this.disposed = false;
 }
        /// <summary>
        /// Gets the description and color space from the specified color profile.
        /// </summary>
        /// <param name="fileName">The path of the color profile.</param>
        internal static void GetProfileInfo(string fileName, out string description, out ProfileColorSpace colorSpace)
        {
            description = "Unknown profile";
            colorSpace  = ProfileColorSpace.Unknown;

            using (LCMSProfileHandle hProfile = LCMSHelper.OpenColorProfile(fileName))
            {
                if (!hProfile.IsInvalid)
                {
                    colorSpace = LCMSHelper.GetProfileColorSpace(hProfile);

                    uint descriptionSize = LCMSHelper.GetProfileInfoSize(hProfile, LCMSEnums.ProfileInfoType.Description);

                    if (descriptionSize > 0U)
                    {
                        description = LCMSHelper.GetProfileInfo(hProfile, LCMSEnums.ProfileInfoType.Description, descriptionSize);
                    }
                }
            }
        }
        /// <summary>
        /// Initializes the color profiles.
        /// </summary>
        /// <param name="inputPath">The path of the input profile.</param>
        /// <param name="displayPath">The path of the display profile.</param>
        /// <param name="proofingPath">The path of the proofing profile.</param>
        /// <returns>
        ///     <c>true</c> if the color profiles were successfully initialized; otherwise, <c>false</c>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="inputPath"/> is null.
        /// or
        /// <paramref name="displayPath"/> is null.
        /// or
        /// <paramref name="proofingPath"/> is null.
        /// </exception>
        private bool InitializeColorProfiles(string inputPath, string displayPath, string proofingPath)
        {
            if (inputPath == null)
            {
                throw new ArgumentNullException("inputPath");
            }
            if (displayPath == null)
            {
                throw new ArgumentNullException("displayPath");
            }
            if (proofingPath == null)
            {
                throw new ArgumentNullException("proofingPath");
            }

            // If the profiles have not changed exit early.
            if (inputPath.Equals(this.inputProfilePath, StringComparison.OrdinalIgnoreCase) &&
                displayPath.Equals(this.displayProfilePath, StringComparison.OrdinalIgnoreCase) &&
                proofingPath.Equals(this.proofingProfilePath, StringComparison.OrdinalIgnoreCase))
            {
                return(true);
            }

            Reset();
            bool result = false;

            this.inputProfile    = LCMSHelper.OpenColorProfile(inputPath);
            this.displayProfile  = LCMSHelper.OpenColorProfile(displayPath);
            this.proofingProfile = LCMSHelper.OpenColorProfile(proofingPath);

            if (!this.inputProfile.IsInvalid && !this.displayProfile.IsInvalid && !this.proofingProfile.IsInvalid)
            {
                this.inputProfilePath    = inputPath;
                this.displayProfilePath  = displayPath;
                this.proofingProfilePath = proofingPath;
                result = true;
            }

            return(result);
        }
        /// <summary>
        /// Converts the image to the specified output color profile.
        /// </summary>
        /// <param name="inputProfilePath">The path of the input color profile.</param>
        /// <param name="outputProfilePath">The path of the output color profile.</param>
        /// <param name="intent">The rendering intent to use for the conversion.</param>
        /// <param name="blackPointCompensation"><c>true</c> if black point compensation should be used; otherwise, <c>false</c>.</param>
        /// <param name="source">The source image to convert.</param>
        /// <param name="destination">The destination image to place the converted pixels.</param>
        /// <exception cref="LCMSException">
        /// The input profile could not be opened.
        /// -or-
        /// The output profile could not be opened.
        /// -or-
        /// The color transform could not be created.
        /// -or-
        /// The source and destination images are not the same size.
        /// </exception>
        internal static void ConvertToColorProfile(
            string inputProfilePath,
            string outputProfilePath,
            RenderingIntent intent,
            bool blackPointCompensation,
            Surface source,
            WriteableBitmap destination
            )
        {
            using (LCMSProfileHandle inputProfile = LCMSHelper.OpenColorProfile(inputProfilePath))
            {
                if (inputProfile.IsInvalid)
                {
                    throw new LCMSException(Resources.OpenSourceProfileError);
                }

                using (LCMSProfileHandle outputProfile = LCMSHelper.OpenColorProfile(outputProfilePath))
                {
                    if (outputProfile.IsInvalid)
                    {
                        throw new LCMSException(Resources.OpenDestiniationProfileError);
                    }

                    LCMSStructs.BitmapData sourceBitmapData = new LCMSStructs.BitmapData
                    {
                        width  = (uint)source.Width,
                        height = (uint)source.Height,
                        format = LCMSEnums.BitmapFormat.Bgra8,
                        stride = (uint)source.Stride,
                        scan0  = source.Scan0.Pointer
                    };

                    LCMSStructs.BitmapData destinationBitmapData = new LCMSStructs.BitmapData
                    {
                        width  = (uint)destination.PixelWidth,
                        height = (uint)destination.PixelHeight,
                        format = BitmapFormatFromWICPixelFormat(destination.Format),
                        stride = (uint)destination.BackBufferStride,
                        scan0  = destination.BackBuffer
                    };

                    LCMSEnums.TransformFlags flags = LCMSEnums.TransformFlags.None;

                    if (LCMSHelper.UseBlackPointCompensation(blackPointCompensation, intent))
                    {
                        flags |= LCMSEnums.TransformFlags.BlackPointCompensation;
                    }

                    LCMSEnums.ConvertProfileStatus status = LCMSHelper.ConvertToProfile(
                        inputProfile,
                        outputProfile,
                        intent,
                        flags,
                        ref sourceBitmapData,
                        ref destinationBitmapData
                        );

                    if (status != LCMSEnums.ConvertProfileStatus.Ok)
                    {
                        switch (status)
                        {
                        case LCMSEnums.ConvertProfileStatus.InvalidParameter:
                            throw new LCMSException(Resources.ConvertProfileInvalidParameter);

                        case LCMSEnums.ConvertProfileStatus.DifferentImageDimensions:
                            throw new LCMSException(Resources.DifferentImageDimensions);

                        case LCMSEnums.ConvertProfileStatus.CreateTransformFailed:
                            throw new LCMSException(Resources.CreateTransformError);

                        default:
                            break;
                        }
                    }
                }
            }
        }