VintaSoft Imaging .NET SDK 12.4: Documentation for .NET developer
In This Topic
    Color management
    In This Topic

    1. Color management, basic notions

    Color management, in digital imaging, is the controlled conversion of image colors for achieving identical image display on all devices.

    Since different devices have different characteristics and capabilities, there arise a need in some open and coherent model of color management, supported by the majority of devices and software systems. At the moment, the most recognized model is the model for color management elaborated by the International Color Consortium (ICC).

    ICC model, alongside with generally used color spaces (RGB, CMYK, Grayscale, etc), introduces the concept of color space PCS (Profile Connection Space), which may be one of the two color spaces:

    The main way to store information about the color transformation in ICC model is the ICC color profile. ICC profile defines color transformations necessary for color conversion from certain color space to PCS, or vice versa. Thus, for transferring colors of one device to colors of another suffice a color profile which defines the transfer of color from the first device color space into PCS (this profile is so called source profile) and a color profile which defines the translation of PCS into the color space of the second device (this profile is so called destination profile).

    The general scheme of color translation from one color space into another looks like this:




    For example, the scheme of color conversion from CMYK space to RGB may look like this:





    2. Color management architecture of VintaSoft Imaging .NET SDK

    Vintasoft Imaging .NET SDK has built-in color management system which allows to:

    The key classes allowing the usage of color management are:


    2.1. ColorTransform class - single color transformation

    Terms:

    ColorTransform is the base class for all color transformations. The class provides the ability to work with colors and color vectors which have real (double) or integer (8 or 16-bit) representation of color channel.
    An instance of color transformation can be:

    Each color transformation defines input and output color format.
    Color format is defined using ColorSpaceFormat class, which defines the color space, using ColorSpaceType enumeration, and the order of color channels, using ColorChannelsOrder class.
    Input and output color format is defined in constructor of color transformation and cannot be changed later. The input color format can be obtained using the ColorTransform.SourceColorFormat property, and the output format using the ColorTransform.DestColorFormat property.


    ColorTransform class has a set of methods, which define algorithm of color transformation for different representations of input and output color values:

    These methods takes 2 parameters: the first parameter - an array defining the initial color or color vector; the second parameter - an array to which will be written the transformed color or color vector. The values of arrays define the values for color channels in accordance with defined color format. The values of color channels can be represented as follows:

    From the listed methods of ColorTransform class only the ColorTransform.TransformVector method is the abstract one and must be defined in derived classes, the rest of methods in basic implementation use ColorTransform.TransformVector method for performing the transformation, if necessary integer values are converted into real values and vice versa. However any of the methods can be overriden in an derivative class to improve the performance or implement some additional transformation algorithms.


    The class has abstract ColorTransform.IsThreadSafe property, which provides the ability to determine if the color transformation is thread-safe or not.


    2.2. ColorTransforms class - standard color transformations

    Static class ColorTransforms contains predefined standard color transformations as static instances.
    The following standard color transformations are available:

    As RGB space is used standard sRGB space.

    Here is the diagram that shows standard color transformations available in static ColorTransforms class. Green ovals indicate device-independent spaces, blue rectangles indicate device-dependent spaces. Arrows indicate available color transforms in specified directions.




    The following example demonstrates how to convert a color in RGB format to a color in XYZ format, using standard transformation from sRGB to PCSXYZ:
    /// <summary>
    /// Returns a XYZ color converted from specified RGB color
    /// using standard color transform.
    /// </summary>
    public static Vintasoft.Imaging.ImageColors.XyzColor TransformRgbToXyz(
        Vintasoft.Imaging.ImageColors.Rgb24Color rgbColor)
    {
        // fill buffer of RGB color
        byte[] sourceColor = new byte[3];
        sourceColor[0] = rgbColor.Red;
        sourceColor[1] = rgbColor.Green;
        sourceColor[2] = rgbColor.Blue;
    
        // create buffer for XYZ color
        double[] destColor = new double[3];
        // perform color transform from byte values to double values
        Vintasoft.Imaging.ColorManagement.ColorTransforms.SRgbToPcsXyzD50.TransformFrom8bitVector(
            sourceColor, 0, 1, destColor, 0);
    
        // return XYZ color
        return new Vintasoft.Imaging.ImageColors.XyzColor(destColor[0], destColor[1], destColor[2]);
    }
    
    ''' <summary>
    ''' Returns a XYZ color converted from specified RGB color
    ''' using standard color transform.
    ''' </summary>
    Public Shared Function TransformRgbToXyz(rgbColor As Vintasoft.Imaging.ImageColors.Rgb24Color) As Vintasoft.Imaging.ImageColors.XyzColor
        ' fill buffer of RGB color
        Dim sourceColor As Byte() = New Byte(2) {}
        sourceColor(0) = rgbColor.Red
        sourceColor(1) = rgbColor.Green
        sourceColor(2) = rgbColor.Blue
    
        ' create buffer for XYZ color
        Dim destColor As Double() = New Double(2) {}
        ' perform color transform from byte values to double values
        Vintasoft.Imaging.ColorManagement.ColorTransforms.SRgbToPcsXyzD50.TransformFrom8bitVector(sourceColor, 0, 1, destColor, 0)
    
        ' return XYZ color
        Return New Vintasoft.Imaging.ImageColors.XyzColor(destColor(0), destColor(1), destColor(2))
    End Function
    



    2.3. CompositeColorTransform class - composite color transformations

    Terms:

    CompositeColorTransform class is the base class for composite color transformations. SDK contains two implementations of composite transformations - SimpleCompositeColorTransform and FastCompositeColorTransform.
    SimpleCompositeColorTransform class has the following feature: if all color transformations included in instance of SimpleCompositeColorTransform class are thread-safe, then the transformation itself is thread-safe.
    FastCompositeColorTransform class is not thread-safe, but has better performance than SimpleCompositeColorTransform because it uses internal memory buffers for intermediate transformations.

    The instances of classes can be created using static methods SimpleCompositeColorTransform.Create and FastCompositeColorTransform.Create. Each method takes as a parameter an array of merged transformations.

    When creating composite transformations is necessary to take into account that in transformation chain each couple of neighbouring color transforms must be compatible, i.e. the output color format of the first transformation must equal to the input color format of the second transformation.

    The following example demonstrates how to create a composite color transformation consisting from specified color transforms:
    /// <summary>
    /// Creates composite color transform that converts color from BGR format to RGB format
    /// and then converts to XYZ format using standard color transform.
    /// </summary>
    public static Vintasoft.Imaging.ColorManagement.ColorTransform CreateCompositeColorTransform()
    {
        // channels order for BGR format
        Vintasoft.Imaging.ColorChannelsOrder bgrOrder = 
            new Vintasoft.Imaging.ColorChannelsOrder(new int[] { 2, 1, 0 });
        // channels order for RGB format
        Vintasoft.Imaging.ColorChannelsOrder rgbOrder = 
            new Vintasoft.Imaging.ColorChannelsOrder(new int[] { 0, 1, 2 });
        // create the channels order conversion transform
        Vintasoft.Imaging.ColorManagement.ColorTransform bgrToRgbTransform = 
            new Vintasoft.Imaging.ColorManagement.ChannelsOrderConverterTransform(
                Vintasoft.Imaging.ColorSpaceType.sRGB, bgrOrder, rgbOrder);
        // create the composite transform using channels order conversion transform and standard transform
        return Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(
            bgrToRgbTransform, Vintasoft.Imaging.ColorManagement.ColorTransforms.SRgbToPcsXyzD50);
    }
    
    ''' <summary>
    ''' Creates composite color transform that converts color from BGR format to RGB format
    ''' and then converts to XYZ format using standard color transform.
    ''' </summary>
    Public Shared Function CreateCompositeColorTransform() As Vintasoft.Imaging.ColorManagement.ColorTransform
        ' channels order for BGR format
        Dim bgrOrder As New Vintasoft.Imaging.ColorChannelsOrder(New Integer() {2, 1, 0})
        ' channels order for RGB format
        Dim rgbOrder As New Vintasoft.Imaging.ColorChannelsOrder(New Integer() {0, 1, 2})
        ' create the channels order conversion transform
        Dim bgrToRgbTransform As Vintasoft.Imaging.ColorManagement.ColorTransform = New Vintasoft.Imaging.ColorManagement.ChannelsOrderConverterTransform(Vintasoft.Imaging.ColorSpaceType.sRGB, bgrOrder, rgbOrder)
        ' create the composite transform using channels order conversion transform and standard transform
        Return Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(bgrToRgbTransform, Vintasoft.Imaging.ColorManagement.ColorTransforms.SRgbToPcsXyzD50)
    End Function
    



    2.4. ColorTransformSet class - a set of color transformations

    Terms:

    ColorTransformSet provides the ability to work with color transformations like with a set. The set supports the following operations:

    ColorTransformSet provides the uniqueness of its elements by combination of input and output format of color space.

    ColorTransformSet class allows to obtain the color transformation necessary to transform a color from the source color format to the destination color format. There are two ways to obtain a color transformation from a set:


    2.5. IccProfile class - ICC profile

    Terms:

    IccProfile class provides the ability to obtain the following color transformations:

    Both methods allow to specify the order of color channels in color transformation and/or the rendering intent.


    The following properties of IccProfile class provide the ability to obtain the additional information:

    The following example demonstrates how to get transformation from the Device color space to the PCS color space from ICC profile:
    /// <summary>
    /// Returns a color transform, which transforms colors from the device to PCS color space,
    /// from specified ICC profile.
    /// </summary>
    public static Vintasoft.Imaging.ColorManagement.ColorTransform GetDeviceToPcsTransform(string iccProfileFilename)
    {
        using (Vintasoft.Imaging.ColorManagement.Icc.IccProfile profile = 
            new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(iccProfileFilename))
        {
            return profile.GetDeviceToPcsTransform();
        }
    }
    
    ''' <summary>
    ''' Returns a color transform, which transforms colors from the device to PCS color space,
    ''' from specified ICC profile.
    ''' </summary>
    Public Shared Function GetDeviceToPcsTransform(iccProfileFilename As String) As Vintasoft.Imaging.ColorManagement.ColorTransform
        Using profile As New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(iccProfileFilename)
            Return profile.GetDeviceToPcsTransform()
        End Using
    End Function
    



    2.6. ColorManagementDecodeSettings class

    ColorManagementDecodeSettings class is designed to simplify the color management when decoding images.


    ColorManagementDecodeSettings.ColorSpaceTransforms property contains a set of color transformations which is used for converting colors of image. By default ColorManagementDecodeSettings.ColorSpaceTransforms property contains the following standard color transformations:

    If ICC profiles must be used for image color conversion, the necessary ICC profiles can be specified using the following properties:

    Changing the value of ColorManagementDecodeSettings.InputCmykProfile, ColorManagementDecodeSettings.InputRgbProfile, ColorManagementDecodeSettings.InputGrayscaleProfile, ColorManagementDecodeSettings.OutputRgbProfile or ColorManagementDecodeSettings.OutputGrayscaleProfile property leads to the changes in the set of color transformations, which is defined by the ColorManagementDecodeSettings.ColorSpaceTransforms property.


    ColorManagementDecodeSettings.GetColorTransform, ColorManagementDecodeSettings.GetColorTransformUsingEmbeddedProfile and ColorManagementDecodeSettings.GetColorTransformUsingEmbeddedProfileMetadata methods allow to obtain the color transformation which is necessary for converting the image colors.

    Additional parameters of color management can be set using the following properties:

    The following example demonstrates how to get the color management settings:
    /// <summary>
    /// Returns a ColorManagementDecodeSettings object
    /// with specified ICC profiles for CMYK and RGB color spaces.
    /// </summary>
    public static Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings GetColorManagementDecodeSettings(
        string cmykProfileFilename, string rgbProfileFilename)
    {
        // create new ColorManagementDecodeSettings object
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings settings = 
            new Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings();
        // use black point compensation
        settings.UseBlackPointCompensation = true;
        // set input CMYK profile
        settings.InputCmykProfile = new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(cmykProfileFilename);
        Vintasoft.Imaging.ColorManagement.Icc.IccProfile rgbProfile = 
            new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(rgbProfileFilename);
        // set input RGB profile
        settings.InputRgbProfile = rgbProfile;
        // set output RGB profile
        settings.OutputRgbProfile = rgbProfile;
    
        return settings;
    }
    
    ''' <summary>
    ''' Returns a ColorManagementDecodeSettings object
    ''' with specified ICC profiles for CMYK and RGB color spaces.
    ''' </summary>
    Public Shared Function GetColorManagementDecodeSettings(cmykProfileFilename As String, rgbProfileFilename As String) As Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings
        ' create new ColorManagementDecodeSettings object
        Dim settings As New Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings()
        ' use black point compensation
        settings.UseBlackPointCompensation = True
        ' set input CMYK profile
        settings.InputCmykProfile = New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(cmykProfileFilename)
        Dim rgbProfile As New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(rgbProfileFilename)
        ' set input RGB profile
        settings.InputRgbProfile = rgbProfile
        ' set output RGB profile
        settings.OutputRgbProfile = rgbProfile
    
        Return settings
    End Function
    



    2.7. Transform image colors

    The color transformation of VintasoftImage object can be performed using the ColorTransformCommand class. For doing this it is necessary to set the appropriate color transformation using the ColorTransformCommand.ColorTransform property and apply the command to the image.

    The following example demonstrates how to accomplish the image color transformation:
    /// <summary>
    /// Applies a color transform command to specified VintasoftImage
    /// using specified output RGB profile.
    /// </summary>
    public static void ApplyColorTransformCommand(
        Vintasoft.Imaging.VintasoftImage image,
        Vintasoft.Imaging.ColorManagement.Icc.IccProfile outputRgbProfile)
    {
        // create new color management decoding settings
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings colorManagement =
            new Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings();
        // set output RGB profile
        colorManagement.OutputRgbProfile = outputRgbProfile;
        // get color transform
        Vintasoft.Imaging.ColorManagement.ColorTransform colorTransform =
            colorManagement.GetColorTransform(
                Vintasoft.Imaging.ColorSpaceFormats.Bgr,
                Vintasoft.Imaging.ColorSpaceFormats.Bgr
            );
        // create a color transform command
        Vintasoft.Imaging.ImageProcessing.Color.ColorTransformCommand colorTransformCommand =
            new Vintasoft.Imaging.ImageProcessing.Color.ColorTransformCommand();
        // set color transform
        colorTransformCommand.ColorTransform = colorTransform;
        // apply color transform command
        colorTransformCommand.ExecuteInPlace(image);
    }
    
    ''' <summary>
    ''' Applies a color transform command to specified VintasoftImage
    ''' using specified output RGB profile.
    ''' </summary>
    Public Shared Sub ApplyColorTransformCommand(image As Vintasoft.Imaging.VintasoftImage, outputRgbProfile As Vintasoft.Imaging.ColorManagement.Icc.IccProfile)
        ' create new color management decoding settings
        Dim colorManagement As New Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings()
        ' set output RGB profile
        colorManagement.OutputRgbProfile = outputRgbProfile
        ' get color transform
        Dim colorTransform As Vintasoft.Imaging.ColorManagement.ColorTransform = colorManagement.GetColorTransform(Vintasoft.Imaging.ColorSpaceFormats.Bgr, Vintasoft.Imaging.ColorSpaceFormats.Bgr)
        ' create a color transform command
        Dim colorTransformCommand As New Vintasoft.Imaging.ImageProcessing.Color.ColorTransformCommand()
        ' set color transform
        colorTransformCommand.ColorTransform = colorTransform
        ' apply color transform command
        colorTransformCommand.ExecuteInPlace(image)
    End Sub
    



    2.8. Enable color management when decoding image

    The VintasoftImage.DecodingSettings property defines settings of image decoding. DecodingSettings.ColorManagement property defines settings of image color management.

    Important: The color management cannot be applied to the image based on a Bitmap object (VintasoftImage.HasBitmapData property is set to True).

    The following example demonstrates how to enable the color management while getting a copy of VintasoftImage object:
    /// <summary>
    /// Returns a copy of specified RGB VintasoftImage with enabled color management
    /// using specified input and output profiles.
    /// </summary>
    public static Vintasoft.Imaging.VintasoftImage GetImageCopy(
        Vintasoft.Imaging.VintasoftImage image, 
        Vintasoft.Imaging.ColorManagement.Icc.IccProfile inputCmykProfile, 
        Vintasoft.Imaging.ColorManagement.Icc.IccProfile inputRgbProfile,
        Vintasoft.Imaging.ColorManagement.Icc.IccProfile outputRgbProfile)
    {
        // create new color management decoding settings
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings colorManagement = 
            new Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings();
        // set input CMYK profile
        colorManagement.InputCmykProfile = inputCmykProfile;
        // set input RGB profile
        colorManagement.InputRgbProfile = inputRgbProfile;
        // set output RGB profile
        colorManagement.OutputRgbProfile = outputRgbProfile;
    
        // create decoding settings
        if (image.DecodingSettings == null)
            image.DecodingSettings = new Vintasoft.Imaging.Codecs.Decoders.DecodingSettings();
        // set color management settings
        image.DecodingSettings.ColorManagement = colorManagement;
        // copy image with specified color management
        return (Vintasoft.Imaging.VintasoftImage)image.Clone();
    }
    
    ''' <summary>
    ''' Returns a copy of specified RGB VintasoftImage with enabled color management
    ''' using specified input and output profiles.
    ''' </summary>
    Public Shared Function GetImageCopy(image As Vintasoft.Imaging.VintasoftImage, inputCmykProfile As Vintasoft.Imaging.ColorManagement.Icc.IccProfile, inputRgbProfile As Vintasoft.Imaging.ColorManagement.Icc.IccProfile, outputRgbProfile As Vintasoft.Imaging.ColorManagement.Icc.IccProfile) As Vintasoft.Imaging.VintasoftImage
        ' create new color management decoding settings
        Dim colorManagement As New Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings()
        ' set input CMYK profile
        colorManagement.InputCmykProfile = inputCmykProfile
        ' set input RGB profile
        colorManagement.InputRgbProfile = inputRgbProfile
        ' set output RGB profile
        colorManagement.OutputRgbProfile = outputRgbProfile
    
        ' create decoding settings
        If image.DecodingSettings Is Nothing Then
            image.DecodingSettings = New Vintasoft.Imaging.Codecs.Decoders.DecodingSettings()
        End If
        ' set color management settings
        image.DecodingSettings.ColorManagement = colorManagement
        ' copy image with specified color management
        Return DirectCast(image.Clone(), Vintasoft.Imaging.VintasoftImage)
    End Function
    



    If there is a need to use different color management settings while decoding the same image, it is necessary to create a new image as a "shallow" copy of source image using the VintasoftImage.CreateImageBasedOnSourceImageDecoder method and assign new decoding and color management settings for the new image.

    The following example demonstrates how to get the bitmap, from VintasoftImage object, with the decoding settings different from the decoding settings of VintasoftImage object:

    /// <summary>
    /// Returns a bitmap from image with specified color management settings.
    /// </summary>
    public Vintasoft.Imaging.VintasoftBitmap GetVintasoftBitmap(
        Vintasoft.Imaging.VintasoftImage image,
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings colorManagement)
    {
        using (Vintasoft.Imaging.VintasoftImage tempImage = 
            Vintasoft.Imaging.VintasoftImage.CreateImageBasedOnSourceImageDecoder(image))
        {
            tempImage.DecodingSettings = 
                new Vintasoft.Imaging.Codecs.Decoders.DecodingSettings();
            tempImage.DecodingSettings.ColorManagement = colorManagement;
            return tempImage.GetAsVintasoftBitmap();
        }
    }
    
    ''' <summary>
    ''' Returns a bitmap from image with specified color management settings.
    ''' </summary>
    Public Function GetVintasoftBitmap(image As Vintasoft.Imaging.VintasoftImage, colorManagement As Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings) As Vintasoft.Imaging.VintasoftBitmap
        Using tempImage As Vintasoft.Imaging.VintasoftImage = Vintasoft.Imaging.VintasoftImage.CreateImageBasedOnSourceImageDecoder(image)
            tempImage.DecodingSettings = New Vintasoft.Imaging.Codecs.Decoders.DecodingSettings()
            tempImage.DecodingSettings.ColorManagement = colorManagement
            Return tempImage.GetAsVintasoftBitmap()
        End Using
    End Function
    



    2.9. Enable color management in image/thumbnail viewer

    All controls for viewing images and thumbnails (ImageViewer, WpfImageViewer, ThumbnailViewer, WpfThumbnailViewer, AnnotationViewer, WpfAnnotationViewer, etc) have built in support for color management. The ImageViewerBase.ImageDecodingSettings property defines settings of image decoding. DecodingSettings.ColorManagement property defines settings of image color management.

    Important: The color management cannot be applied to the image based on a Bitmap object (VintasoftImage.HasBitmapData property is set to True).

    The following example demonstrates how to enable or disable color management in image viewer:
    /// <summary>
    /// Enables the color management in image or thumbnail viewer.
    /// </summary>
    /// <param name="viewer">An image/thumbnail viewer.</param>
    /// <param name="inputCmykProfile">The input CMYK profile.</param>
    /// <param name="inputRgbProfile">The input RGB profile.</param>
    /// <param name="outputRgbProfile">The output RGB profile.</param>
    public static void EnableViewerColorManagement(
        Vintasoft.Imaging.UI.ImageViewerBase viewer,
        string inputCmykProfile,
        string inputRgbProfile,
        string outputRgbProfile)
    {
        // if all profiles are empty
        if (string.IsNullOrEmpty(inputCmykProfile) &&
            string.IsNullOrEmpty(inputRgbProfile) &&
            string.IsNullOrEmpty(outputRgbProfile))
            return;
    
        // get current image decoding settings from the viewer
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingImageSettings = viewer.ImageDecodingSettings;
        // if viewer does not have image decoding settings
        if (decodingImageSettings == null)
            // create new image decoding settings
            decodingImageSettings = new Vintasoft.Imaging.Codecs.Decoders.DecodingSettings();
    
        // init the image decoding settings
        InitDecodingSettings(decodingImageSettings, inputCmykProfile, inputRgbProfile, outputRgbProfile);
     
        // set decoding settings to the viewer
        viewer.ImageDecodingSettings = decodingImageSettings;
        // reload images in viewer
        ReloadViewerImages(viewer);
    }
    
    /// <summary>
    /// Disables the color management in image/thumbnail viewer.
    /// </summary>
    /// <param name="viewer">An image/thumbnail viewer.</param>
    public static void DisableViewerColorManagement(Vintasoft.Imaging.UI.ImageViewerBase viewer)
    {
        // get decoding settings from image/thumbnail viewer
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings imageDecodingSettings = viewer.ImageDecodingSettings;
        if (imageDecodingSettings == null)
            return;
    
        // destroy the image decoding settings
        DestroyColorManagementDecodeSettings(imageDecodingSettings.ColorManagement);
        imageDecodingSettings.ColorManagement = null;
    
        // set decoding settings to the image/thumbnail viewer
        viewer.ImageDecodingSettings = imageDecodingSettings;
        // reload images in image/thumbnail viewer
        ReloadViewerImages(viewer);
    }
    
    
    /// <summary>
    /// Initializes the decoding settings.
    /// </summary>
    /// <param name="decodingSettings">Image decoding settings.</param>
    /// <param name="inputCmykProfile">The input CMYK profile.</param>
    /// <param name="inputRgbProfile">The input RGB profile.</param>
    /// <param name="outputRgbProfile">The output RGB profile.</param>
    static void InitDecodingSettings(
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings,
        string inputCmykProfile,
        string inputRgbProfile,
        string outputRgbProfile)
    {
        DestroyColorManagementDecodeSettings(decodingSettings.ColorManagement);
        decodingSettings.ColorManagement = null;
    
        decodingSettings.ColorManagement = new Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings();
    
        InitColorManagementDecodeSettings(decodingSettings.ColorManagement, inputCmykProfile, inputRgbProfile, outputRgbProfile);
    }
    
    /// <summary>
    /// Destroys the color management decode settings.
    /// </summary>
    /// <param name="colorManagementDecodeSettings">Color management decode settings.</param>
    static void DestroyColorManagementDecodeSettings(
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings colorManagementDecodeSettings)
    {
        if (colorManagementDecodeSettings != null)
        {
            // if input CMYK profile is not empty
            if (colorManagementDecodeSettings.InputCmykProfile != null)
            {
                // remove input CMYK profile
                colorManagementDecodeSettings.InputCmykProfile.Dispose();
            }
    
            // if input RGB profile is not empty
            if (colorManagementDecodeSettings.InputRgbProfile != null)
            {
                // remove input RGB profile
                colorManagementDecodeSettings.InputRgbProfile.Dispose();
            }
    
            // if output RGB profile is not empty
            if (colorManagementDecodeSettings.OutputRgbProfile != null)
            {
                // remove output RGB profile
                colorManagementDecodeSettings.OutputRgbProfile.Dispose();
            }
        }
    }
    
    /// <summary>
    /// Initializes the color management decode settings.
    /// </summary>
    /// <param name="colorManagementDecodeSettings">Color management decode settings.</param>
    /// <param name="inputCmykProfile">The input CMYK profile.</param>
    /// <param name="inputRgbProfile">The input RGB profile.</param>
    /// <param name="outputRgbProfile">The output RGB profile.</param>
    static void InitColorManagementDecodeSettings(
        Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings colorManagementDecodeSettings,
        string inputCmykProfile,
        string inputRgbProfile,
        string outputRgbProfile)
    {
        // if input CMYK profile is not empty
        if (!string.IsNullOrEmpty(inputCmykProfile))
        {
            // set input CMYK profile
            colorManagementDecodeSettings.InputCmykProfile =
                new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(inputCmykProfile);
        }
        // if input RGB profile is not empty
        if (!string.IsNullOrEmpty(inputRgbProfile))
        {
            // set input RGB profile
            colorManagementDecodeSettings.InputRgbProfile =
                new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(inputRgbProfile);
        }
        // if output RGB profile is not empty
        if (!string.IsNullOrEmpty(outputRgbProfile))
        {
            // set output RGB profile
            colorManagementDecodeSettings.OutputRgbProfile =
                new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(outputRgbProfile);
        }
    }
    
    /// <summary>
    /// Reloads the images in the specified image/thumbnail viewer.
    /// </summary>
    /// <param name="viewer">The image/thumbnail viewer.</param>
    static void ReloadViewerImages(Vintasoft.Imaging.UI.ImageViewerBase viewer)
    {
        try
        {
            // get the image collection
            Vintasoft.Imaging.ImageCollection images = viewer.Images;
            // get the focused image
            int focusedIndex = viewer.FocusedIndex;
            Vintasoft.Imaging.VintasoftImage focusedImage = null;
            if (focusedIndex >= 0 && focusedIndex < images.Count)
            {
                focusedImage = images[focusedIndex];
                // if focused image is not empty
                if (focusedImage != null)
                {
                    // reload image
                    focusedImage.Reload(true);
                }
            }
    
            // for each image in collection
            foreach (Vintasoft.Imaging.VintasoftImage image in images)
            {
                // if this is not focused image
                if (image != focusedImage)
                {
                    // reload image
                    image.Reload(true);
                }
            }
        }
        catch (System.Exception ex)
        {
            // show error message
            System.Windows.Forms.MessageBox.Show(ex.Message, "Error",
                System.Windows.Forms.MessageBoxButtons.OK,
                System.Windows.Forms.MessageBoxIcon.Error);
        }
    }
    
    ''' <summary>
    ''' Enables the color management in image or thumbnail viewer.
    ''' </summary>
    ''' <param name="viewer">An image/thumbnail viewer.</param>
    ''' <param name="inputCmykProfile">The input CMYK profile.</param>
    ''' <param name="inputRgbProfile">The input RGB profile.</param>
    ''' <param name="outputRgbProfile">The output RGB profile.</param>
    Public Shared Sub EnableViewerColorManagement(viewer As Vintasoft.Imaging.UI.ImageViewerBase, inputCmykProfile As String, inputRgbProfile As String, outputRgbProfile As String)
        ' if all profiles are empty
        If String.IsNullOrEmpty(inputCmykProfile) AndAlso String.IsNullOrEmpty(inputRgbProfile) AndAlso String.IsNullOrEmpty(outputRgbProfile) Then
            Return
        End If
    
        ' get current image decoding settings from the viewer
        Dim decodingImageSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings = viewer.ImageDecodingSettings
        ' if viewer does not have image decoding settings
        If decodingImageSettings Is Nothing Then
            ' create new image decoding settings
            decodingImageSettings = New Vintasoft.Imaging.Codecs.Decoders.DecodingSettings()
        End If
    
        ' init the image decoding settings
        InitDecodingSettings(decodingImageSettings, inputCmykProfile, inputRgbProfile, outputRgbProfile)
    
        ' set decoding settings to the viewer
        viewer.ImageDecodingSettings = decodingImageSettings
        ' reload images in viewer
        ReloadViewerImages(viewer)
    End Sub
    
    ''' <summary>
    ''' Disables the color management in image/thumbnail viewer.
    ''' </summary>
    ''' <param name="viewer">An image/thumbnail viewer.</param>
    Public Shared Sub DisableViewerColorManagement(viewer As Vintasoft.Imaging.UI.ImageViewerBase)
        ' get decoding settings from image/thumbnail viewer
        Dim imageDecodingSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings = viewer.ImageDecodingSettings
        If imageDecodingSettings Is Nothing Then
            Return
        End If
    
        ' destroy the image decoding settings
        DestroyColorManagementDecodeSettings(imageDecodingSettings.ColorManagement)
        imageDecodingSettings.ColorManagement = Nothing
    
        ' set decoding settings to the image/thumbnail viewer
        viewer.ImageDecodingSettings = imageDecodingSettings
        ' reload images in image/thumbnail viewer
        ReloadViewerImages(viewer)
    End Sub
    
    
    ''' <summary>
    ''' Initializes the decoding settings.
    ''' </summary>
    ''' <param name="decodingSettings">Image decoding settings.</param>
    ''' <param name="inputCmykProfile">The input CMYK profile.</param>
    ''' <param name="inputRgbProfile">The input RGB profile.</param>
    ''' <param name="outputRgbProfile">The output RGB profile.</param>
    Private Shared Sub InitDecodingSettings(decodingSettings As Vintasoft.Imaging.Codecs.Decoders.DecodingSettings, inputCmykProfile As String, inputRgbProfile As String, outputRgbProfile As String)
        DestroyColorManagementDecodeSettings(decodingSettings.ColorManagement)
        decodingSettings.ColorManagement = Nothing
    
        decodingSettings.ColorManagement = New Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings()
    
        InitColorManagementDecodeSettings(decodingSettings.ColorManagement, inputCmykProfile, inputRgbProfile, outputRgbProfile)
    End Sub
    
    ''' <summary>
    ''' Destroys the color management decode settings.
    ''' </summary>
    ''' <param name="colorManagementDecodeSettings">Color management decode settings.</param>
    Private Shared Sub DestroyColorManagementDecodeSettings(colorManagementDecodeSettings As Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings)
        If colorManagementDecodeSettings IsNot Nothing Then
            ' if input CMYK profile is not empty
            If colorManagementDecodeSettings.InputCmykProfile IsNot Nothing Then
                ' remove input CMYK profile
                colorManagementDecodeSettings.InputCmykProfile.Dispose()
            End If
    
            ' if input RGB profile is not empty
            If colorManagementDecodeSettings.InputRgbProfile IsNot Nothing Then
                ' remove input RGB profile
                colorManagementDecodeSettings.InputRgbProfile.Dispose()
            End If
    
            ' if output RGB profile is not empty
            If colorManagementDecodeSettings.OutputRgbProfile IsNot Nothing Then
                ' remove output RGB profile
                colorManagementDecodeSettings.OutputRgbProfile.Dispose()
            End If
        End If
    End Sub
    
    ''' <summary>
    ''' Initializes the color management decode settings.
    ''' </summary>
    ''' <param name="colorManagementDecodeSettings">Color management decode settings.</param>
    ''' <param name="inputCmykProfile">The input CMYK profile.</param>
    ''' <param name="inputRgbProfile">The input RGB profile.</param>
    ''' <param name="outputRgbProfile">The output RGB profile.</param>
    Private Shared Sub InitColorManagementDecodeSettings(colorManagementDecodeSettings As Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings, inputCmykProfile As String, inputRgbProfile As String, outputRgbProfile As String)
        ' if input CMYK profile is not empty
        If Not String.IsNullOrEmpty(inputCmykProfile) Then
            ' set input CMYK profile
            colorManagementDecodeSettings.InputCmykProfile = New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(inputCmykProfile)
        End If
        ' if input RGB profile is not empty
        If Not String.IsNullOrEmpty(inputRgbProfile) Then
            ' set input RGB profile
            colorManagementDecodeSettings.InputRgbProfile = New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(inputRgbProfile)
        End If
        ' if output RGB profile is not empty
        If Not String.IsNullOrEmpty(outputRgbProfile) Then
            ' set output RGB profile
            colorManagementDecodeSettings.OutputRgbProfile = New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(outputRgbProfile)
        End If
    End Sub
    
    ''' <summary>
    ''' Reloads the images in the specified image/thumbnail viewer.
    ''' </summary>
    ''' <param name="viewer">The image/thumbnail viewer.</param>
    Private Shared Sub ReloadViewerImages(viewer As Vintasoft.Imaging.UI.ImageViewerBase)
        Try
            ' get the image collection
            Dim images As Vintasoft.Imaging.ImageCollection = viewer.Images
            ' get the focused image
            Dim focusedIndex As Integer = viewer.FocusedIndex
            Dim focusedImage As Vintasoft.Imaging.VintasoftImage = Nothing
            If focusedIndex >= 0 AndAlso focusedIndex < images.Count Then
                focusedImage = images(focusedIndex)
                ' if focused image is not empty
                If focusedImage IsNot Nothing Then
                    ' reload image
                    focusedImage.Reload(True)
                End If
            End If
    
            ' for each image in collection
            For Each image As Vintasoft.Imaging.VintasoftImage In images
                ' if this is not focused image
                If image IsNot focusedImage Then
                    ' reload image
                    image.Reload(True)
                End If
            Next
        Catch ex As System.Exception
            ' show error message
            System.Windows.Forms.MessageBox.Show(ex.Message, "Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.[Error])
        End Try
    End Sub
    



    2.10. Enable color management when getting image using decoder

    By default the decoder (class derived from DecoderBase class) does not use color management while getting image or thumbnail. For getting image with enabled color management it is necessary to enable the color management using the decodingSettings parameter (of ColorManagementDecodeSettings type) in the DecoderBase.GetImage method. For getting thumbnail with enabled color management it is necessary to enable the color management using the decodingSettings parameter (of ColorManagementDecodeSettings type) in the DecoderBase.GetThumbnail method.

    The following example demonstrates how to enable the color management while getting image of TIFF page:
    /// <summary>
    /// Returns an image of specified tiff page with enabled color management.
    /// </summary>
    public static Vintasoft.Imaging.VintasoftImage GetTiffPageWithColorManagement(
        Vintasoft.Imaging.Codecs.ImageFiles.Tiff.TiffPage tiffPage, 
        System.EventHandler<Vintasoft.Imaging.ProgressEventArgs> progressDelegate)
    {
        // create decoding settings
        Vintasoft.Imaging.Codecs.Decoders.DecodingSettings decodingSettings = 
            new Vintasoft.Imaging.Codecs.Decoders.DecodingSettings();
        // enable color management
        decodingSettings.ColorManagement = 
            new Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings();
        // get image of Tiff page
        return tiffPage.GetImage(decodingSettings, progressDelegate);
    }
    
    ''' <summary>
    ''' Returns an image of specified tiff page with enabled color management.
    ''' </summary>
    Public Shared Function GetTiffPageWithColorManagement(tiffPage As Vintasoft.Imaging.Codecs.ImageFiles.Tiff.TiffPage, progressDelegate As System.EventHandler(Of Vintasoft.Imaging.ProgressEventArgs)) As Vintasoft.Imaging.VintasoftImage
        ' create decoding settings
        Dim decodingSettings As New Vintasoft.Imaging.Codecs.Decoders.DecodingSettings()
        ' enable color management
        decodingSettings.ColorManagement = New Vintasoft.Imaging.ColorManagement.ColorManagementDecodeSettings()
        ' get image of Tiff page
        Return tiffPage.GetImage(decodingSettings, progressDelegate)
    End Function
    



    2.11. Optimization and thread-safety of color transformations

    Optimization of color transformations is needed for increasing the performance of composite color transformation and can be performed using the ColorTransformsOptimizer.GetOptimizedTransform method. The ColorManagementDecodeSettings class always returns optimized color transformation, in all other cases it may be necessary to optimize the composite color transformation.

    To optimize the composite color transformation the ColorTransformsOptimizer class analyzes the execution results of the ColorTransform.IsIdentity, ColorTransform.IsInverseTransform and ColorTransform.CreateOptimizedWith methods of color transformations, which are composed in optimized transformation.

    The value of transformation returned by ColorTransformsOptimizer.GetOptimizedTransform method can be null, if the optimized color transformation turned out identical.

    ColorTransform.IsThreadSafe property defines the thread-safety of current instance of ColorTransform class. The necessity of thread-safety is caused by usage of color transformations in multi-threaded tasks, for example, when using multi-threading in certain decoders. However, if the thread-safety is not used this can increase the performance. For example, the composite transformation FastCompositeColorTransform uses permanent memory buffers, that's why it is non-thread-safe, but more productive than SimpleCompositeColorTransform.

    ColorTransformsOptimizer.GetOptimizedTransform method with one parameter always returns not thread-safe optimized color transformation. ColorTransformsOptimizer.GetOptimizedTransform method with two parameters, the second of which is a Boolean parameter, returns thread-safe optimized color transformation, if boolean parameter is set to True, and returns not thread-safe optimized color transformation, if boolean parameter is set to False.

    ColorTransformSet class allows to forbid adding of not thread-safe color transformations into a set of color transformations using the parameter of constructor. If ColorTransformSet.IsThreadSafe property is True, set of color transformations contains only thread-safe color transformations.

    Instance of ColorManagementDecodeSettings class contains only thread-safe color transformations, however, in the most cases the methods for getting color transformation of ColorManagementDecodeSettings class return non-thread-safe composite transformation FastCompositeColorTransform, composed of thread-safe transformations.


    The following example demonstrates how to get a composite transformation from the specified input and output ICC profiles and optimize the transformation:
    /// <summary>
    /// Creates a composite color transform from specified source and destination RGB profiles
    /// and returns optimized thread-unsafe color transform.
    /// </summary>
    public static Vintasoft.Imaging.ColorManagement.ColorTransform GetOptimizedRgbTransform(
        string sourceRgbProfileFilename, string destRgbProfileFilename)
    {
        // create ICC profiles
        using (Vintasoft.Imaging.ColorManagement.Icc.IccProfile sourceIccProfile =
            new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(sourceRgbProfileFilename))
        using (Vintasoft.Imaging.ColorManagement.Icc.IccProfile destIccProfile =
            new Vintasoft.Imaging.ColorManagement.Icc.IccProfile(destRgbProfileFilename))
        {
            // check device color space of the source profile
            if (sourceIccProfile.DeviceColorSpace != Vintasoft.Imaging.ColorSpaceType.sRGB)
            {
                throw new System.ArgumentException("Source profile is not RGB profile.");
            }
            // check device color space of the destination profile
            if (destIccProfile.DeviceColorSpace != Vintasoft.Imaging.ColorSpaceType.sRGB)
            {
                throw new System.ArgumentException("Destination profile is not RGB profile.");
            }
    
            // get transforms from device color space to PCS
            Vintasoft.Imaging.ColorManagement.ColorTransform deviceToPcsTransform = sourceIccProfile.GetDeviceToPcsTransform();
            // get transforms from PCS to device color space
            Vintasoft.Imaging.ColorManagement.ColorTransform pcsToDeviceTransform = destIccProfile.GetPcsToDeviceTransform();
            // composite color transform
            Vintasoft.Imaging.ColorManagement.ColorTransform composition;
            if (sourceIccProfile.PcsColorSpace == destIccProfile.PcsColorSpace)
            {
                // create simple composite color transform
                composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(
                    deviceToPcsTransform,
                    pcsToDeviceTransform);
            }
            else
            {
                if (sourceIccProfile.PcsColorSpace == Vintasoft.Imaging.ColorSpaceType.PCSXYZ)
                {
                    // create simple composite color transform with intermediate PCSXYZ->PCSLab conversion
                    composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(
                        deviceToPcsTransform,
                        Vintasoft.Imaging.ColorManagement.ColorTransforms.PcsXyzToPcsLabD50,
                        pcsToDeviceTransform);
                }
                else
                {
                    // create simple composite color transform with intermediate PCSLab->PCSXYZ conversion
                    composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(
                        deviceToPcsTransform,
                        Vintasoft.Imaging.ColorManagement.ColorTransforms.PcsLabToPcsXyzD50,
                        pcsToDeviceTransform);
                }
            }
            // return optimized color transform
            return Vintasoft.Imaging.ColorManagement.ColorTransformsOptimizer.GetOptimizedTransform(composition, false);
        }
    }
    
    ''' <summary>
    ''' Creates a composite color transform from specified source and destination RGB profiles
    ''' and returns optimized thread-unsafe color transform.
    ''' </summary>
    Public Shared Function GetOptimizedRgbTransform(sourceRgbProfileFilename As String, destRgbProfileFilename As String) As Vintasoft.Imaging.ColorManagement.ColorTransform
        ' create ICC profiles
        Using sourceIccProfile As New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(sourceRgbProfileFilename)
            Using destIccProfile As New Vintasoft.Imaging.ColorManagement.Icc.IccProfile(destRgbProfileFilename)
                ' check device color space of the source profile
                If sourceIccProfile.DeviceColorSpace <> Vintasoft.Imaging.ColorSpaceType.sRGB Then
                    Throw New System.ArgumentException("Source profile is not RGB profile.")
                End If
                ' check device color space of the destination profile
                If destIccProfile.DeviceColorSpace <> Vintasoft.Imaging.ColorSpaceType.sRGB Then
                    Throw New System.ArgumentException("Destination profile is not RGB profile.")
                End If
    
                ' get transforms from device color space to PCS
                Dim deviceToPcsTransform As Vintasoft.Imaging.ColorManagement.ColorTransform = sourceIccProfile.GetDeviceToPcsTransform()
                ' get transforms from PCS to device color space
                Dim pcsToDeviceTransform As Vintasoft.Imaging.ColorManagement.ColorTransform = destIccProfile.GetPcsToDeviceTransform()
                ' composite color transform
                Dim composition As Vintasoft.Imaging.ColorManagement.ColorTransform
                If sourceIccProfile.PcsColorSpace = destIccProfile.PcsColorSpace Then
                    ' create simple composite color transform
                    composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(deviceToPcsTransform, pcsToDeviceTransform)
                Else
                    If sourceIccProfile.PcsColorSpace = Vintasoft.Imaging.ColorSpaceType.PCSXYZ Then
                        ' create simple composite color transform with intermediate PCSXYZ->PCSLab conversion
                        composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(deviceToPcsTransform, Vintasoft.Imaging.ColorManagement.ColorTransforms.PcsXyzToPcsLabD50, pcsToDeviceTransform)
                    Else
                        ' create simple composite color transform with intermediate PCSLab->PCSXYZ conversion
                        composition = Vintasoft.Imaging.ColorManagement.SimpleCompositeColorTransform.Create(deviceToPcsTransform, Vintasoft.Imaging.ColorManagement.ColorTransforms.PcsLabToPcsXyzD50, pcsToDeviceTransform)
                    End If
                End If
                ' return optimized color transform
                Return Vintasoft.Imaging.ColorManagement.ColorTransformsOptimizer.GetOptimizedTransform(composition, False)
            End Using
        End Using
    End Function