TIFF Extra Channels To Spot Color Space

TIFF Extra Channels Spot Color Adobe Resources Pipeline

Converts a TIFF file with extra channels to PDF with separation color space.

Сode Snippet

public static void Run()
{
    using (var reader = new TiffReader("TiffWithExtraChannels.tif"))
    using (var writer = new PdfWriter("TiffWithExtraChannels.pdf"))
    {
        reader.TreatFirstExtraChannelAsAlpha = false;

        Pipeline.Run(reader + writer);

        var names = ParseChannelNames(reader.AdobeResources);

        var displayInfos = ParseDisplayInfo(reader.AdobeResources);

        using (var gr = writer.GetGraphics())
        {
            for (int i = 0; i < reader.Frames[0].ExtraChannels.Count; i++)
            {
                var extraChannel = reader.Frames[0].ExtraChannels[i];

                using (var extraChannelBitmap = extraChannel.GetBitmap())
                using (var spotImage = new Bitmap(extraChannelBitmap.Width, extraChannelBitmap.Height, PixelFormat.Format16bppAspot, RgbColor.White))
                {
                    spotImage.DpiX = extraChannelBitmap.DpiX;
                    spotImage.DpiY = extraChannelBitmap.DpiY;

                    Color color = GetColor(displayInfos[i]);

                    var ink = new Ink(names[i], color)
                    {
                        Solidity = displayInfos[i].Opacity / 100.0f,
                    };

                    spotImage.Ink = ink;
                    extraChannelBitmap.Transforms.Invert();
                    spotImage.Channels[1] = extraChannelBitmap;

                    spotImage.Channels.ScaleAlpha(ink.Solidity);

                    gr.DrawImage(spotImage, 0, 0);
                }
            }
        }
    }
}

private static string[] ParseChannelNames(AdobeResourceDictionary ar)
{
    // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
    const int unicodeAlphaNames = 0x0415;

    var block = (AdobeResourceBlock)ar[unicodeAlphaNames];

    var names = new List<string>();

    int i = 0;

    while (i < block.Data.Length)
    {
        // skip zeros
        i += 2;

        var length = (block.Data[i] << 8) | block.Data[i + 1];
        i += 2;

        if (length * 2 > block.Data.Length - i)
        {
            throw new System.ArgumentException("Invalid block data.");
        }

        // Get the name without trailing zero
        var name = System.Text.Encoding.BigEndianUnicode.GetString(block.Data, i, (length - 1) * 2);

        i += length * 2;

        names.Add(name);
    }

    return names.ToArray();
}

private static DisplayInfo[] ParseDisplayInfo(AdobeResourceDictionary ar)
{
    // https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
    const int displayInfo = 0x0435;

    var block = (AdobeResourceBlock)ar[displayInfo];

    var displayInfos = new List<DisplayInfo>();

    int i = 4;

    while (i < block.Data.Length)
    {
        var di = new DisplayInfo
        {
            Color = new int[4],
        };

        // Read color space
        di.ColorSpace = (block.Data[i] << 8) | block.Data[i + 1];
        i += 2;

        // Read colors
        for (int j = 0; j < 4; j++)
        {
            di.Color[j] = (block.Data[i] << 8) | block.Data[i + 1];
            i += 2;
        }

        // Read opacity
        di.Opacity = (block.Data[i] << 8) | block.Data[i + 1];
        i += 2;

        di.Kind = block.Data[i++];

        displayInfos.Add(di);
    }

    return displayInfos.ToArray();
}

private static Color GetColor(DisplayInfo di)
{
    if (di.ColorSpace == 0)
    {
        return new RgbColor(
            (byte)(di.Color[0] / 256),
            (byte)(di.Color[1] / 256),
            (byte)(di.Color[2] / 256));
    }
    else if (di.ColorSpace == 2)
    {
        return new CmykColor(
            (byte)(di.Color[0] / 256),
            (byte)(di.Color[1] / 256),
            (byte)(di.Color[2] / 256),
            (byte)(di.Color[3] / 256));
    }
    else
    {
        throw new System.ArgumentException("Unsupported color space.");
    }
}

private struct DisplayInfo
{
    public int ColorSpace;
    public int[] Color;
    public int Opacity;
    public int Kind;
}

Input

TiffWithExtraChannels.tif

Download

Output

TiffWithExtraChannels.pdf

Download

TiffWithExtraChannels.png

For AI-assisted development: Download Graphics Mill Code Samples XML Catalog