DEV Community 👩‍💻👨‍💻

Dmitry Matuzko
Dmitry Matuzko

Posted on

Working with ICC profiles in Aspose.Imaging

Aspose.Imaging supports retrieving, applying and storing ICC color profiles for PSD and JPEG images, and can embed color profiles when exporting TIFF images. For other formats, embedded color profiles are processed when loading image, but are not availible for manipulation as of v18.7. In this article I'll show how to work with ICC profiles for JPEG, PSD and TIFF.

Helper methods for loading and saving profiles

ICC color profiles stored in PSD and JPEG images are represented as properties of type StreamSource, which facilitates directly loading/saving them from/to .icc(m) files.
In this section I will provide methods that will be used in following sections. Here are methods to create a StreamSource from file and to save StreamSource to file:

using Aspose.Imaging.Sources;
using Aspose.Imaging.ImageOptions;
using System.IO;


private static StreamSource GetSourceForFilename(string filename)
{
    MemoryStream memory = new MemoryStream(File.ReadAllBytes(filename));
    memory.Seek(0, System.IO.SeekOrigin.Begin);
    StreamSource source = new StreamSource(memory);
    return source;
}

private static void SaveSourceToFile(StreamSource source, string filename)
{
    using (FileStream fileStream = new FileStream(filename, FileMode.Create))
    {
        long position = source.Stream.Position;
        source.Stream.Seek(0, System.IO.SeekOrigin.Begin);
        int byteCount;
        byte[] buffer = new byte[1024];
        while ((byteCount = source.Stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            fileStream.Write(buffer, 0, byteCount);
        }
        source.Stream.Seek(position, System.IO.SeekOrigin.Begin);
        fileStream.Flush();
    }
}

Enter fullscreen mode Exit fullscreen mode

In case of TIFF files, color profiles are applied during saving of the image, and are provided in IccProfile property of TiffOptions's instance as an instance of MemoryStream. Here are methods to convert StreamSource to MemoryStream and to load a file into MemoryStream:

private static MemoryStream FileToMemoryStream(string filename)
{
    MemoryStream memory = new MemoryStream(File.ReadAllBytes(filename));
    memory.Seek(0, System.IO.SeekOrigin.Begin);
    return memory;
}

        private static MemoryStream SourceToMemoryStream(StreamSource streamSource)
{
    Stream srcStream = streamSource.Stream;
    MemoryStream dstStream = new MemoryStream();

    int byteCount;
    byte[] buffer = new byte[1024];
    long pos = srcStream.Position;
    srcStream.Seek(0, System.IO.SeekOrigin.Begin);
    while ((byteCount = srcStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        dstStream.Write(buffer, 0, byteCount);
    }

    srcStream.Seek(pos, System.IO.SeekOrigin.Begin);
    return dstStream;
}
Enter fullscreen mode Exit fullscreen mode

Applying color profile when saving to TIFF

This is straightforward to do: just set IccProfile property of TiffOptions with the profile, and save the image:

using (Image image = Image.Load("sample.jpg"))
{
    TiffOptions options = new TiffOptions(FileFormats.Tiff.Enums.TiffExpectedFormat.Default);
    using(MemoryStream ms = FileToMemoryStream("profile.icc"))
    {
        options.IccProfile = ms;
        image.Save("profiled_sample.tif", options);
    }
}
Enter fullscreen mode Exit fullscreen mode

Color profiles in PSD

There are three color profile properties in PSDImage, two of them are applied to CMYK images and must be used together for correct conversion, these are the RgbColorProfile and CmykColorProfile. By default, if these profiles are embedded in image, they will be applied during loading by default.
Here is an example where CMYK color profile from PSD image is embedded into CMYK TIFF image:

string inputFile = "cmyk.psd";
string outputFile = "cmyk.tiff";

using (PsdImage image = (PsdImage)Image.Load(inputFile))
{
    TiffOptions tiff = new TiffOptions(FileFormats.Tiff.Enums.TiffExpectedFormat.TiffLzwCmyk);
    using (MemoryStream ms = SourceToMemoryStream(image.CmykColorProfile))
    {
        tiff.IccProfile = ms;
        image.Save(outputFile, tiff);
    }
}
Enter fullscreen mode Exit fullscreen mode

Third is GrayColorProfile, used in monochrome images, and is not applied during loading. To enable application of profile explicitly, create LoadOptions instance, set UseIccProfileConversion to true and load image using this instance. See example:

// Save to grayscale TIFF
TiffOptions saveOptions = new TiffOptions(TiffExpectedFormat.Default);
saveOptions.setPhotometric(TiffPhotometrics.MinIsBlack);
saveOptions.setBitsPerSample(new int[] { 8 });

// If the image contains a built-in Gray ICC profile, it is not be applied by default in contrast of the CMYK profile.
// Enable ICC conversion explicitly.
LoadOptions loadOptions = new LoadOptions();
loadOptions.UseIccProfileConversion= true;

using(PsdImage psdImage = (PsdImage)Image.load(sourcePath, loadOptions))
{
    // Embed the gray ICC profile to the output TIFF.
    // The built-in Gray Profile can be read via the PsdImage.GrayColorProfile property.
    saveOptions.setIccProfile(toMemoryStream(psdImage.getGrayColorProfile()));
    psdImage.save(outputPath, saveOptions);
}
Enter fullscreen mode Exit fullscreen mode

Color profiles in JPEG

JpegImage contains four properties related to color profiles. RgbColorProfile and CmykColorProfile, likewise to PSD, are used for CMYK and YCCK JPEG images when loading the image. DestinationCmykColorProfile and DestinationRgbColorProfile are applied when a JpegImage is saved, and should be paired with opponent profile - i.e. when using DestinationCmykColorProfile, RgbColorProfile should be set to a corresponding profile, and when using DestinationRgbColorProfile, CmykColorProfile should be set to a corresponding profile too.
Here is an example that shows use of profiles when loading image:

using (JpegImage image = (JpegImage)Image.Load("image.jpg"))
{
    //load profiles
    StreamSource rgbprofile = GetSourceForFilename("rgb.icc");
    StreamSource cmykprofile = GetSourceForFilename("cmyk.icc");
    // set profiles for image
    image.RgbColorProfile = rgbprofile;
    image.CmykColorProfile = cmykprofile;
    //now the profiles are applied when image's data is retrieved
    Aspose.Imaging.Color[] colors = image.LoadPixels(new Rectangle(0, 0, image.Width, image.Height));
}
Enter fullscreen mode Exit fullscreen mode

Here is an example that shows use of profiles when saving image:

using (JpegImage image = (JpegImage)Image.Load("image.jpg"))
{
    //load profiles
    StreamSource rgbprofile = GetSourceForFilename("rgb.icc");
    StreamSource cmykprofile = GetSourceForFilename("cmyk.icc");
    // apply profiles to image for saving
    image.DestinationRgbColorProfile = rgbprofile;
    image.DestinationCmykColorProfile = cmykprofile;
    //save changes back to image
    image.Save();
}
Enter fullscreen mode Exit fullscreen mode

Disabling default application of embedded color profile.

If you don't want to apply image's embedded color profile during image loading, there is an option to disable this processing using LoadOptions. See example:

LoadOptions loadOptions = new LoadOptions();
loadOptions.UseIccProfileConversion= false;

using(image = Image.load(sourcePath, loadOptions))
{
    image.save(outputPath, new PngOptions());
}
Enter fullscreen mode Exit fullscreen mode

That's all for now, stay tuned!

For more examples please visit the Aspose.Imaging GitHub page. There's also Twitter and Facebook pages for news on Aspose.Imaging.

Top comments (0)

🌚 Life is too short to browse without dark mode