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:
-
PCSXYZ - device-independent color space, based on CIEXYZ, relative to illuminant chromaticity of CIE D50.
-
PCSLAB - device-independent color space, based on CIELAB, relative to illuminant chromaticity of CIE D50.
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:
- Use the color management when decoding image files.
- Use the color management when displaying and printing images.
- Perform the color transformation of images.
- Obtain the color transformations from ICC-profiles v.2.0-4.3.
- Use a number of standard color transformations and define custom color transformations.
The key classes allowing the usage of color management are:
2.1. ColorTransform class - single color transformation
Terms:
-
Color format - a combination of color space with the order of color channels.
-
Color transformation - a transformation, which with a certain affordable accuracy translates a set of numeric values, defining color in source color format, into ordered set of numeric values, defining color in destination color format.
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:
- real numeric values - define the color channel in range from 0 to 1, where 0 is minimum and 1 is maximum value. Values are represented as System.Double[] type.
- 8-bit integer values - define the color channel in range from 0 to 255, where 0 is minimum and 255 is maximum value. Values are represented as System.Byte[] type.
- 16-bit integer values - define the color channel in range from 0 to 65536, where 0 is minimum and 65536 is maximum value. Values are represented as System.Byte[] type. Each channel is defined by two bytes sequentially following each other, the first one is the low byte of 16-bit integer and second one is the upper byte.
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:
- RGB => PCSXYZ
- RGB => PCSXYZ, with accelerated performance.
- PCSXYZ => RGB
- PCSXYZ => BGR
- PCSXYZ => BGR, with accelerated performance.
- PCSLAB => PCSXYZ
- PCSXYZ => PCSLAB
- Gray => PCSXYZ
- PCSXYZ => Gray.
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:
-
Composite color transformation - a color transformation, which contains a sequence of color transformations.
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:
-
Direct color transformation - single color transformation, which allows to convert colors from specified input format to specified output format.
ColorTransformSet provides the ability to work with color transformations like with a set. The set supports the following operations:
- add color transformation
- remove color transformation
- get color transformation
- get a chain of color transformations using information about input and output format of necessary color space.
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:
-
Getting direct color transformation using the ColorTransformSet.GetDirectColorTransform method. Method searches for the color transformation with specified input and output formats in the color transformations of a set. Method returns null if the appropriate transformation is not found.
-
Getting a chain of transformations using the ColorTransformSet.GetColorTransform method. Initially, method searches for the direct color transformation and returns it if found. If direct color transformation is not found the method will form all possible chains of transformations for color transformation from specified input format to specified output format. Method will return chain of transformations with minimum length as composite transformation (SimpleCompositeColorTransform), if at least one chain of transformations is found; method will return null, if no (one) chain is found.
2.5. "IccProfile" class - ICC profile
Terms:
-
ICC color profile defines one or more transformations of color from one format into another as well as some additional information.
-
Rendering intent defines a style of mapping color values from one color space to another color space when the gamut of source color space exceeds the gamut of destination color space. Default rendering intent is RenderingIntent.Perceptual.
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:
- sRGB => PCSXYZ
- CMYK => PCSXYZ
- Gray => PCSXYZ
- PCSXYZ => sRGB
- PCSXYZ => Gray
- PCSXYZ => PCSLab
- PCSLab => PCSXYZ
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 wehn 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.
-
ColorTransform.IsIdentity method should return True only if the color transformation is identical.
-
ColorTransform.IsInverseTransform method should return True only if the color transformation is inverse to the initial, i.e. when the combination of current transformation with the specified one is an identical transformation.
-
ColorTransform.CreateOptimizedWith should return certain color transformation, which differs from null, only in case if it equals to the combination of current and specified transformations, but has greater performance than that combination itself.
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