VintaSoft Imaging .NET SDK 15.1: 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 when transforming colors

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