Skip to main content
Skip table of contents

Output Intents


An output intent describes the final destination device you will use to reproduce the color in the PDF, such as the separations printing device. Output intents override working spaces during viewing and printing, but they do not convert the colors in the PDF. You can include output intents when you create PDF/X (or PDF/A) files.

Mako uses a property of the IPDFOutput class to specify the output intent when writing a PDF. The IOutputIntent class represents a PDF output intent and provides the create() method that requires several items of information, described below. More detailed information regarding the information needed is described in the PDF specification 1.7 (refer to section 14.11.5).

IOutputIntent create()

The create method requires the following information, described here with some examples:

NameOutput intent propertyTypical value / purpose
sRGBSWOPFOGRA39
registryNameProfile registryhttp://www.color.orghttp://www.color.orghttp://www.color.org
outputConditionOutput conditionsRGB IEC61966-2.1CGATS TR 001 (SWOP)FOGRA39
outputConditionIdentifier
sRGB IEC61966-2.1CGATS TR 001FOGRA39
subtypeSubtype

One of: GTS_PDFX, GTS_PDFA1, ISO_PDFE1

infoInfoA human-readable text string containing additional information or comments about the intended target device or production condition. Can be left blank.
profileICC ProfileAn IDOMICCProfile. See code example for creation of this class from a file-based ICC profile.

Worked Example

The code in the following section created a PDF, shown here displayed in Acrobat (or Acrobat Reader).

The ICC profile used for the output intent is deliberately designed to alter colors in a dramatic fashion, so that it is clear it is being used.

To see the effect on the PDF, you can open it in Adobe Acrobat Reader DC and set Edit > Preferences > Page Display > Use Overprint Preview to 'Always':

With the 'Use Overprint Preview' option set to 'Never'.With the 'Use Overprint Preview' option set to 'Always'.

Code

CPP
/* -----------------------------------------------------------------------
 * <copyright file="SaveWithOutputIntent.cpp" company="Global Graphics Software Ltd">
 *  Copyright (c) 2022-2023 Global Graphics Software Ltd. All rights reserved.
 * </copyright>
 * <summary>
 *  This example is provided on an "as is" basis and without warranty of any kind.
 *  Global Graphics Software Ltd. does not warrant or make any representations
 *  regarding the use or results of use of this example.
 * </summary>
 * -----------------------------------------------------------------------
 */

#include <iostream>
#include <format>
#include <filesystem>
using namespace std;
namespace fs = std::filesystem;

#include <jawsmako/jawsmako.h>
#include <jawsmako/layout.h>
#include <jawsmako/outputintent.h>
#include <jawsmako/pdfinput.h>
#include <jawsmako/pdfoutput.h>
#include <edl/idomresources.h>

using namespace JawsMako;
using namespace EDL;

#define M2X(value) ((value) / 25.4 * 96.0)
#define P2X(value) ((value) / 72.0 * 96.0)

IDOMImagePtr getImage(const IJawsMakoPtr& mako, const U8String& imageFile);

int main()
{
    try
    {
        const auto mako = IJawsMako::create();
        mako->enableAllFeatures(mako);

        // Create assembly, document, page, fixed page
        const auto assembly = IDocumentAssembly::create(mako);
        const auto document = IDocument::create(mako);
        assembly->appendDocument(document);
        const auto page = IPage::create(mako);
        document->appendPage(page);
        const auto fixedPage = IDOMFixedPage::create(mako, M2X(250), M2X(210));
        page->setContent(fixedPage);

        // The ICC profiles
        CEDLVector<std::pair<U8String, U8String>> profiles;
        profiles.append(std::pair<U8String, U8String>("Probev2_ICCv4.icc", "https://www.color.org/probeprofile.xalter"));
        profiles.append(std::pair<U8String, U8String>("GRACoL2006_Coated1v2.icc", "https://idealliance.org"));
        profiles.append(std::pair<U8String, U8String>("JapanColor2011Coated.icc", "https://www.xrite.com"));

        // Get a font
        uint32 fontIndex;
        const auto font = edlobj2IDOMFontOpenType(mako->findFont("Arial", fontIndex));

        // Create a colour
        const auto darkBlue = IDOMColor::createSolidRgb(mako, 0.0f, 0.0f, 0.5f);

        // Create a layout
        const auto layout = ILayout::create(mako);

        // Add frame to hold content
        layout->addFrame(ILayoutFrame::create(FRect(M2X(12), M2X(12), M2X(273), M2X(186))));

        // Create template paragraphs
        const auto header = ILayoutParagraph::create(ILayoutParagraph::eHALeft, P2X(6));
        const auto body = ILayoutParagraph::create(ILayoutParagraph::eHALeft, P2X(6));

        // A vector to point to each paragraph to be added to the frame(s)
        auto paragraphs = CEDLVector<ILayoutParagraphPtr>();
        uint32 paraIndex = 0;

        // Create paragraphs and text runs 
        std::string text = "This PDF has an Output Intent referencing this ICC profile:";
        auto run = ILayoutTextRun::create(text.c_str(), font, fontIndex, P2X(12), darkBlue);
        paragraphs.append(header->clone());
        paragraphs[paraIndex]->addRun(run);
        text = std::format("  ● {} (from {})", profiles[0].first, profiles[0].second);
        run = ILayoutTextRun::create(text.c_str(), font, fontIndex, P2X(10));
        paragraphs.append(body->clone());
        paragraphs[++paraIndex]->addRun(run);

        // Picture
        const auto parrot = getImage(mako, R"(..\..\TestFiles\Parrot.png)");
        paragraphs.append(ILayoutParagraph::create());
        paragraphs[++paraIndex]->addRun(ILayoutImageRun::create(mako, parrot, 0, M2X(169)));

        // Add content to the page
        fixedPage->appendChild(layout->layout(paragraphs));

        // Load profile from local storage
        const auto iccProfile = IDOMICCProfile::create(mako, IInputStream::createFromFile(mako, R"(..\..\TestFiles\)" + profiles[0].first));

        // Output intent metadata
        U8String subtype = "GTS_PDFX";
        U8String registryName = "http://www.color.org";
        U8String outputCondition = profiles[0].first;
        U8String outputConditionIdentifier = profiles[0].first;
        U8String info = "Output Intent test";

        // Create a PDF output set to write PDF/X
        auto output = IPDFOutput::create(mako);
        output->setPreset("PDF/X-4");

        // Create an intent and add to PDF (the primary, and only intent recognized for PDF/X purposes)
        auto outputIntent = IOutputIntent::create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
        output->setOutputIntent(outputIntent);

        // Write PDF/X-compliant PDF
        output->writeAssembly(assembly, "OutputIntentExample.pdf");

        // Check that the PDF has an output intent
        auto testDocument = IPDFInput::create(mako)->open("OutputIntentExample.pdf")->getDocument();
        _ASSERT(testDocument->getOutputIntents().size() == 1);

        // Demonstration of adding more than one output intent. PDF/X allows it, may suit some custom workflows
        COutputIntentVect outputIntents;
        outputIntents.append(outputIntent);

        // We add two alternates
        subtype = "GGS_DUMMY";
        registryName = "https://idealliance.org";
        outputCondition = profiles[1].first;
        outputConditionIdentifier = profiles[1].first;
        info = "The GRACoL 2006 Coated v2 from idealliance.org";

        // Create an intent and add to list
        outputIntent = IOutputIntent::create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
        outputIntents.append(outputIntent);

        subtype = "GGS_DUMMY";
        registryName = "https://www.xrite.com";
        outputCondition = profiles[2].first;
        outputConditionIdentifier = profiles[2].first;
        info = "The Japan Color 2011 profile from xrite.com";

        // Create an intent and add to list
        outputIntent = IOutputIntent::create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
        outputIntents.append(outputIntent);

        // Set multiple intents
        output->setOutputIntents(outputIntents);

        // Write PDF
        output->writeAssembly(assembly, "OutputIntentExampleThreeIntents.pdf");

        // Check that the PDF has three output intents
        testDocument = IPDFInput::create(mako)->open("OutputIntentExampleThreeIntents.pdf")->getDocument();
        _ASSERT(testDocument->getOutputIntents().size() == 3);

        // Done
    }
    catch (IError& e)
    {
        const String errorFormatString = getEDLErrorString(e.getErrorCode());
        std::wcerr << L"Exception thrown: " << e.getErrorDescription(errorFormatString) << std::endl;
        return static_cast<int>(e.getErrorCode());
    }
    catch (std::exception& e)
    {
        std::wcerr << L"std::exception thrown: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

// Get image 
IDOMImagePtr getImage(const IJawsMakoPtr& mako, const U8String& imageFile)
{
    IDOMImagePtr image = IDOMImagePtr();
    const auto imagePath = fs::path(imageFile);
    if (!exists(imagePath))
    {
        std::string msg = "Image file ";
        msg += imageFile;
        msg += " not found.";
        throw std::exception(msg.c_str());
    }

    if (imagePath.extension() == ".jpg")
        image = IDOMJPEGImage::create(mako, IInputStream::createFromFile(mako, imageFile));

    if (imagePath.extension() == ".png")
        image = IDOMPNGImage::create(mako, IInputStream::createFromFile(mako, imageFile));

    if (imagePath.extension() == ".tif")
        image = IDOMTIFFImage::create(mako, IInputStream::createFromFile(mako, imageFile));

    if (!image)
    {
        std::string msg = "Image file ";
        msg += imageFile;
        msg += " could not be loaded.";
        throw std::exception(msg.c_str());
    }

    return image;
}


C#
/* -----------------------------------------------------------------------
 * <copyright file="SaveWithOutputIntent.cs" company="Global Graphics Software Ltd">
 *  Copyright (c) 2022-2023 Global Graphics Software Ltd. All rights reserved.
 * </copyright>
 * <summary>
 *  This example is provided on an "as is" basis and without warranty of any kind.
 *  Global Graphics Software Ltd. does not warrant or make any representations
 *  regarding the use or results of use of this example.
 * </summary>
 * -----------------------------------------------------------------------
 */

using JawsMako;
using System;
using static JawsMako.jawsmakoIF_csharp;

namespace SaveWithOutputIntentCS;

class SaveWithOutputIntent
{
    static void Main(string[] args)
    {
        // The ICC profiles
        var profiles = new List<Tuple<string, string>>();
        profiles.Add(Tuple.Create("Probev2_ICCv4.icc", @"https://www.color.org/probeprofile.xalter"));
        profiles.Add(Tuple.Create("GRACoL2006_Coated1v2.icc", "https://idealliance.org"));
        profiles.Add(Tuple.Create("JapanColor2011Coated.icc", "https://www.xrite.com"));

        try
        {
            var mako = IJawsMako.create();
            IJawsMako.enableAllFeatures(mako);

            // Get a page ready to accept some DOM
            using var assembly = IDocumentAssembly.create(mako);
            using var document = IDocument.create(mako);
            assembly.appendDocument(document);
            using var page = IPage.create(mako);
            document.appendPage(page);
            var fixedPage = IDOMFixedPage.create(mako, M2X(250), M2X(210));
            page.setContent(fixedPage);

            // Get a font
            var font = IDOMFontOpenType.fromRCObject(mako.findFont("Arial", out var fontIndex).toRCObject());

            // Create a colour
            var darkBlue = IDOMColor.createSolidRgb(mako, 0.0f, 0.0f, 0.5f);

            // Create a layout
            var layout = ILayout.create(mako);

            // Add frame to hold content
            layout.addFrame(ILayoutFrame.create(new FRect(M2X(12), M2X(12), M2X(273), M2X(186))));

            // Create template paragraphs
            var header = ILayoutParagraph.create(ILayoutParagraph.eHorizontalAlignment.eHALeft, P2X(6));
            var body = ILayoutParagraph.create(ILayoutParagraph.eHorizontalAlignment.eHALeft, P2X(5));

            // A vector to point to each paragraph to be added to the frame(s)
            CEDLVectILayoutParagraph paragraphs = new CEDLVectILayoutParagraph();
            uint paraIndex = 0;

            // Create paragraphs and text runs 
            var text = "This PDF has an Output Intent referencing this ICC profile:";
            var run = ILayoutTextRun.create(text, font, fontIndex, P2X(12), darkBlue);
            paragraphs.append(header.clone());
            paragraphs[paraIndex].addRun(ILayoutRun.fromRCObject(run.toRCObject()));
            text = $"  ● {profiles[0].Item1} (from {profiles[0].Item2})";
            run = ILayoutTextRun.create(text, font, fontIndex, P2X(10));
            paragraphs.append(body.clone());
            paragraphs[++paraIndex].addRun(ILayoutRun.fromRCObject(run.toRCObject()));

            // Picture
            var parrot = GetImage(ref mako, @"..\..\..\..\TestFiles\Parrot.png");
            paragraphs.append(ILayoutParagraph.create());
            paragraphs[++paraIndex].addRun(ILayoutImageRun.create(mako, parrot, 0, M2X(169)));

            // Add content to the page
            fixedPage.appendChild(layout.layout(paragraphs));

            // Load profile from local storage
            var iccProfile = IDOMICCProfile.create(mako, IInputStream.createFromFile(mako, Path.Combine(@"..\..\..\..\TestFiles\", profiles[0].Item1)));

            // Output intent metadata
            var subtype = "GTS_PDFX";
            var registryName = "http://www.color.org";
            var outputCondition = profiles[0].Item1;
            var outputConditionIdentifier = profiles[0].Item1;
            var info = "Output Intent test";

            // Create a PDF output set to write PDF/X
            using var output = IPDFOutput.create(mako);
            output.setPreset("PDF/X-4");

            // Create an intent and add to PDF
            var outputIntent = IOutputIntent.create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
            output.setOutputIntent(outputIntent);

            // Write PDF
            output.writeAssembly(assembly, "OutputIntentExample.pdf");

            // Check that the PDF has an output intent
            var testDocument = IPDFInput.create(mako).open("OutputIntentExample.pdf").getDocument();
            if(testDocument.getOutputIntents().size() != 1)
                throw new ApplicationException("Output intent count not equal to 1");

            // Demonstration of adding more than one output intent. PDF/X allows it, may suit some custom workflows
            CEDLVectIOutputIntent outputIntents = new CEDLVectIOutputIntent();
            outputIntents.append(outputIntent);

            // We add two alternates
            subtype = "GGS_DUMMY";
            registryName = "https://idealliance.org";
            outputCondition = profiles[1].Item1;
            outputConditionIdentifier = profiles[1].Item1;
            info = "The GRACoL 2006 Coated v2 from idealliance.org";

            // Create an intent and add to list
            outputIntent = IOutputIntent.create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
            outputIntents.append(outputIntent);

            subtype = "GGS_DUMMY";
            registryName = "https://www.xrite.com";
            outputCondition = profiles[2].Item1;
            outputConditionIdentifier = profiles[2].Item1;
            info = "The Japan Color 2011 profile from xrite.com";

            // Create an intent and add to list
            outputIntent = IOutputIntent.create(mako, subtype, outputCondition, outputConditionIdentifier, registryName, info, iccProfile);
            outputIntents.append(outputIntent);

            // Set multiple intents
            output.setOutputIntents(outputIntents);

            // Write PDF
            output.writeAssembly(assembly, "OutputIntentExampleThreeIntents.pdf");

            // Check that the PDF has three output intents
            testDocument = IPDFInput.create(mako).open("OutputIntentExampleThreeIntents.pdf").getDocument();
            if (testDocument.getOutputIntents().size() != 3)
                throw new ApplicationException("Output intent count not equal to 3");

            // Done
        }
        catch (MakoException e)
        {
            var errorFormatString = getEDLErrorString(e.m_errorCode);
            Console.WriteLine("Exception thrown: " + e.m_msg);
        }
        catch (Exception e)
        {
            Console.WriteLine($"Exception thrown: {e}");
        }
    }

    // Points (1/72") to XPS units (1/96")
    public static double P2X(double value)
    {
        return value / 72.0 * 96.0;
    }

    // Millimetres to XPS units (1/96")
    public static double M2X(double value)
    {
        return value / 25.4 * 96.0;
    }

    // Get image 
    private static IDOMImage GetImage(ref IJawsMako mako, string imageFile)
    {
        var fileInfo = new FileInfo(imageFile);
        if (!fileInfo.Exists)
        {
            throw new FileNotFoundException($"Image file {imageFile} not found.");
        }

        IDOMImage? image = null;

        if (fileInfo.Extension == ".jpg")
            image = IDOMJPEGImage.create(mako, IInputStream.createFromFile(mako, imageFile));

        if (fileInfo.Extension == ".png")
            image = IDOMPNGImage.create(mako, IInputStream.createFromFile(mako, imageFile));

        if (fileInfo.Extension == ".tif")
            image = IDOMTIFFImage.create(mako, IInputStream.createFromFile(mako, imageFile));

        if (image == null)
        {
            throw new Exception($"Image file {imageFile} could not be loaded.");
        }

        return image;
    }
}
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.