/// <summary>
        /// Apply the proofing transform to the specified 8 bit-per-channel BGRA image data.
        /// </summary>
        /// <param name="source">The source surface.</param>
        /// <param name="destination">The destination surface.</param>
        /// <param name="rois">The array of rectangles describing the region to be processed.</param>
        /// <param name="startIndex">The start index in the rectangle array.</param>
        /// <param name="length">The number of rectangles to process.</param>
        /// <exception cref="ObjectDisposedException">The object has been disposed.</exception>
        /// <exception cref="InvalidOperationException">The proofing transform is not valid.</exception>
        public void ApplyProofingTransformBGRA8(Surface source, Surface destination, Rectangle[] rois, int startIndex, int length)
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException("ColorManagement");
            }

            if (!this.proofingTransformIsValid)
            {
                throw new InvalidOperationException("This method must only be called with a valid proofing transform.");
            }

            if (length == 0)
            {
                return;
            }

            LCMSStructs.BitmapData sourceData = 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 destData = new LCMSStructs.BitmapData
            {
                width  = (uint)destination.Width,
                height = (uint)destination.Height,
                format = LCMSEnums.BitmapFormat.Bgra8,
                stride = (uint)destination.Stride,
                scan0  = destination.Scan0.Pointer
            };

            unsafe
            {
                fixed(Rectangle *pROIS = &rois[startIndex])
                {
                    if (IntPtr.Size == 8)
                    {
                        LCMS_64.ApplyProofingTransform(this.proofingTransform, ref sourceData, ref destData, pROIS, length);
                    }
                    else
                    {
                        LCMS_86.ApplyProofingTransform(this.proofingTransform, ref sourceData, ref destData, pROIS, length);
                    }
                }
            }
        }
        /// <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;
                        }
                    }
                }
            }
        }