VintaSoft Imaging .NET SDK 14.0: Документация для .NET разработчика
В этом разделе
    Управление цветом
    В этом разделе

    1. Управление цветом, основные понятия

    Управление цветом в цифровых изображениях - это контролируемое преобразование цветов изображения для достижения идентичного отображения изображения на всех устройствах.

    Поскольку разные устройства имеют разные характеристики и возможности, возникает потребность в некоторой открытой и согласованной модели управления цветом, поддерживаемой большинством устройств и программных систем. На данный момент наиболее признанной моделью является модель управления цветом, разработанная International Color Consortium (ICC).

    Модель ICC, наряду с широко используемыми цветовыми пространствами (RGB, CMYK, оттенки серого и т. д.), представляет концепцию цветового пространства PCS (Пространство подключения профиля) , который может быть одним из двух цветовых пространств:
    Основным способом хранения информации о преобразовании цвета в модели ICC является цветовой профиль ICC цветовой профиль . ICC-профиль определяет цветовые преобразования, необходимые для преобразования цвета из определенного цветового пространства в PCS или наоборот. Таким образом, для переноса цветов одного устройства в цвета другого достаточно цветового профиля, который определяет перенос цвета из цветового пространства первого устройства в PCS (этот профиль называется "исходным профилем"), и цветового профиля, который определяет перевод PCS в цветовое пространство второго устройства (этот профиль называется "целевым профилем").

    Общая схема перевода цветов из одного цветового пространства в другое выглядит так:




    Например, схема преобразования цветов из пространства CMYK в RGB может выглядеть так:





    2. Архитектура управления цветом VintaSoft Imaging .NET SDK

    Vintasoft Imaging .NET SDK имеет встроенную систему управления цветом, которая позволяет:
    Ключевые классы, позволяющие использовать управление цветом:

    2.1. Класс ColorTransform - преобразование одного цвета

    Термины:
    ColorTransform - базовый класс для всех преобразований цвета. Класс обеспечивает возможность работы с цветами и цветовыми векторами, имеющими вещественное (двойное) или целочисленное (8 или 16-битное) представление цветового канала.
    Экземпляр цветового преобразования может быть:
    Каждое цветовое преобразование определяет формат входного и выходного цвета.
    Формат цвета определяется с помощью класса ColorSpaceFormat, который определяет цветовое пространство с помощью перечисления ColorSpaceType и порядка цветовых каналов с помощью класса ColorChannelsOrder.
    Формат входного и выходного цвета определяется в конструкторе цветового преобразования и не может быть изменен позже. Входной формат цвета можно получить с помощью свойства ColorTransform.SourceColorFormat, а выходной формат - с помощью свойства ColorTransform.DestColorFormat.


    Класс ColorTransform имеет набор методов, определяющих алгоритм преобразования цвета для различных представлений входных и выходных значений цвета:
    Эти методы принимают 2 параметра: первый параметр - массив, определяющий исходный цвет или вектор цвета; второй параметр - массив, в который будет записан преобразованный цвет или вектор цвета. Значения массивов определяют значения цветовых каналов в соответствии с заданным цветовым форматом. Значения цветовых каналов могут быть представлены следующим образом:
    Из перечисленных методов класса ColorTransform только метод ColorTransform.TransformVector является абстрактным и должен быть определен в производных классах, остальные методы в базовой реализации используют метод ColorTransform.TransformVector для выполнения преобразования, при необходимости целочисленные значения преобразуются в вещественные значения и наоборот. Однако любой из методов можно переопределить в производном классе для повышения производительности или реализации некоторых дополнительных алгоритмов преобразования.


    Класс имеет абстрактное свойство ColorTransform.IsThreadSafe, которое предоставляет возможность определить, является ли преобразование цвета потокобезопасным или нет.


    2.2. Класс "ColorTransforms" - стандартные цветовые преобразования

    Статический класс ColorTransforms содержит предопределенные стандартные цветовые преобразования в виде статических экземпляров.
    Доступны следующие стандартные преобразования цвета:
    В качестве пространства RGB используется стандартное пространство sRGB.

    Вот диаграмма, показывающая стандартные цветовые преобразования, доступные в статическом классе ColorTransforms. Зеленые овалы обозначают пространства, независимые от устройства, синие прямоугольники - пространства, зависящие от устройства. Стрелки указывают доступные цветовые преобразования в указанных направлениях.




    В следующем примере показано, как преобразовать цвет в формате RGB в цвет в формате XYZ, используя стандартное преобразование из sRGB в 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" - составное цветовое преобразование

    Термины:
    CompositeColorTransform - это базовый класс для составных цветовых преобразований. SDK содержит две реализации составных преобразований - SimpleCompositeColorTransform и FastCompositeColorTransform.
    SimpleCompositeColorTransform класс имеет следующую особенность: если все цветовые преобразования, включенные в экземпляр класса SimpleCompositeColorTransform, являются потокобезопасными, то само преобразование является потокобезопасным.
    FastCompositeColorTransform класс не является потокобезопасным, но имеет более высокую производительность, чем SimpleCompositeColorTransform, поскольку он использует внутренние буферы памяти для промежуточных преобразований.

    Экземпляры классов можно создавать с помощью статических методов SimpleCompositeColorTransform.Create и FastCompositeColorTransform.Create. Каждый метод принимает в качестве параметра массив объединенных преобразований.

    При создании составных преобразований необходимо учитывать, что в цепочке преобразований каждая пара соседних цветовых преобразований должна быть совместима, т.е. выходной формат первого цветового преобразования должен быть равен входному формату второго цветового преобразования.

    В следующем примере показано, как создать составное цветовое преобразование, состоящее из указанных цветовых преобразований:
    /// <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" - набор цветовых преобразований.

    Термины:
    ColorTransformSet предоставляет возможность работать с цветовыми преобразованиями, как с набором. Набор поддерживает следующие операции:
    ColorTransformSet обеспечивает уникальность своих элементов за счет сочетания входного и выходного формата цветового пространства.

    Класс ColorTransformSet позволяет получить цветовое преобразование, необходимое для преобразования цвета из исходного формата цвета в целевой формат цвета. Существует два способа получить цветовое преобразование из набора:

    2.5. Класс "IccProfile" - ICC-профиль

    Термины:
    Класс IccProfile предоставляет возможность получения следующих цветовых преобразований:
    Оба метода позволяют указать порядок цветовых каналов при преобразовании цвета и/или способ рендеринга.


    Следующие свойства класса IccProfile предоставляют возможность получения дополнительной информации:
    В следующем примере показано, как получить преобразование цветового пространства устройства в цветовое пространство PCS из профиля ICC:
    /// <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"

    Класс ColorManagementDecodeSettings предназначен для упрощения управления цветом при декодировании изображений.


    ColorManagementDecodeSettings.ColorSpaceTransforms содержит набор цветовых преобразований, которые используются для преобразования цветов изображения. По умолчанию свойство ColorManagementDecodeSettings.ColorSpaceTransforms содержит следующие стандартные цветовые преобразования:
    Если профили ICC должны быть использованы для преобразования цветов изображения, необходимые профили ICC можно указать с помощью следующих свойств:
    Изменение значения свойств ColorManagementDecodeSettings.InputCmykProfile, ColorManagementDecodeSettings.InputRgbProfile, ColorManagementDecodeSettings.InputGrayscaleProfile, ColorManagementDecodeSettings.OutputRgbProfile или ColorManagementDecodeSettings.OutputGrayscaleProfile приводит к изменению набора цветовых преобразований, определяемых свойством ColorManagementDecodeSettings.ColorSpaceTransforms.


    Методы ColorManagementDecodeSettings.GetColorTransform, ColorManagementDecodeSettings.GetColorTransformUsingEmbeddedProfile и ColorManagementDecodeSettings.GetColorTransformUsingEmbeddedProfileMetadata позволяют получить цветовое преобразование, необходимое для преобразования цветов изображения.

    Дополнительные параметры управления цветом можно задать с помощью следующих свойств:
    В следующем примере показано, как получить настройки управления цветом:
    /// <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. Преобразование цветов изображения

    Преобразование цвета объекта VintasoftImage можно выполнить с помощью класса ColorTransformCommand. Для этого необходимо с помощью свойства ColorTransformCommand.ColorTransform задать соответствующее преобразование цвета и применить команду к изображению.

    В следующем примере показано, как выполнить преобразование цвета изображения:
    /// <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. Включение управление цветом при декодировании изображения

    Свойство VintasoftImage.DecodingSettings определяет настройки декодирования изображения. Свойство DecodingSettings.ColorManagement определяет настройки управления цветом изображения.

    Важно: Управление цветом невозможно применить к изображению на основе растрового объекта (свойству VintasoftImage.HasBitmapData присвоено значение True ).

    Следующий пример демонстрирует, как включить управление цветом при получении копии объекта VintasoftImage:
    /// <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
    



    Если есть необходимость использовать разные настройки управления цветом при декодировании одного и того же изображения, необходимо создать новое изображение как копию исходного изображения с помощью метода VintasoftImage.CreateImageBasedOnSourceImageDecoder и назначить новые настройки декодирования и управления цветом для нового изображения

    В следующем примере показано, как получить растровое изображение из объекта VintasoftImage с настройками декодирования, отличными от настроек декодирования объекта VintasoftImage:

    /// <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. Включение управление цветом в просмотрщике изображений/миниатюр

    Все UI-контролы для просмотр изображений и миниатюр (ImageViewer, WpfImageViewer, ThumbnailViewer, WpfThumbnailViewer, AnnotationViewer, WpfAnnotationViewer и т. д.) имеют встроенную поддержку управления цветом. Свойство ImageViewerBase.ImageDecodingSettings определяет настройки декодирования изображения. Свойство DecodingSettings.ColorManagement определяет настройки управления цветом изображения.

    Важно: Управление цветом невозможно применить к изображению на основе растрового объекта (свойству VintasoftImage.HasBitmapData присвоено значение True ).

    В следующем примере показано, как включить или отключить управление цветом в просмотрщике изображений:
    /// <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. Включение управление цветом при получении изображения с помощью декодера

    По умолчанию декодер (класс, производный от класса DecoderBase) не использует управление цветом при получении изображения или миниатюры. Для получения изображения с включенным управлением цветом необходимо включить управление цветом с помощью параметра decodingSettings (типа ColorManagementDecodeSettings) в методе DecoderBase.GetImage. Для получения миниатюры с включенным управлением цветом необходимо включить управление цветом с помощью параметра decodingSettings (типа ColorManagementDecodeSettings) в методе DecoderBase.GetThumbnail.

    В следующем примере показано, как включить управление цветом при получении изображения TIFF страницы:
    /// <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. Оптимизация и потокобезопасность при преобразовании цветов

    Оптимизация преобразований цветов необходима для повышения производительности составного преобразования цветов и может быть выполнена с помощью метода ColorTransformsOptimizer.GetOptimizedTransform. Класс ColorManagementDecodeSettings всегда возвращает оптимизированное цветовое преобразование, во всех остальных случаях может потребоваться оптимизация составного цветового преобразования.

    Для оптимизации составного цветового преобразования класс ColorTransformsOptimizer анализирует результаты выполнения методов ColorTransform.IsIdentity, ColorTransform.IsInverseTransform и ColorTransform.CreateOptimizedWith цветового преобразования, которые состоят из оптимизированной трансформации.
    Значение преобразования, возвращаемое методом ColorTransformsOptimizer.GetOptimizedTransform, может быть null , если оптимизированное преобразование цвета оказалось идентичным.

    ColorTransform.IsThreadSafe определяет потокобезопасность текущего экземпляра класса ColorTransform. Необходимость потокобезопасности вызвана использованием преобразований цвета в многопоточных задачах, например, при использовании многопоточности в некоторых декодерах. Однако если потокобезопасность не используется, это может повысить производительность. Например, составное преобразование FastCompositeColorTransform использует буферы постоянной памяти, поэтому оно не является потокобезопасным, но более производительным, чем SimpleCompositeColorTransform.

    ColorTransformsOptimizer.GetOptimizedTransform метод с одним параметром всегда возвращает не оптимизированное потоко-безопасное цветовое преобразование. Метод ColorTransformsOptimizer.GetOptimizedTransform с двумя параметрами, второй из которых является логическим параметром, возвращает оптимизированное потоко-безопасное цветовое преобразование, если для логического параметра установлено значение True , и возвращает оптимизированное не потоко-безопасное цветовое преобразование, если логический параметр установлен в False .

    ColorTransformSet класс позволяет запретить добавление не потоко-безопасных цветовых преобразований в набор цветовых преобразований с помощью параметра конструктор. Если свойство ColorTransformSet.IsThreadSafe имеет значение True , набор цветовых преобразований содержит только потоко-безопасные цветовые преобразования.

    Экземпляр класса ColorManagementDecodeSettings содержит только потоко-безопасные цветовые преобразования, однако в большинстве случаев методы получения цвтового преобразования класса ColorManagementDecodeSettings возвращают не потоко-безопасное составное преобразование FastCompositeColorTransform , состоящее из потоко-безопасных преобразований.


    В следующем примере показано, как получить составное преобразование из указанных входных и выходных профилей ICC и оптимизировать преобразование:
    /// <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