Apex PDF Output (APO)

📌 Overview

Apex PDF Output (APO) is a high speed PDF output class that is available as an alternative to Mako’s regular PDF output class, IPDFOutput.

APO is available to Mako users who have licensed Apex. Unlike the Apex renderer, APO does not require a GPU, it’s entirely CPU-based.

ℹ️ Key Features

  • Multi-threaded: APO was built from the ground up to offer vastly improved performance on modern multicore processors by employing multiple threads to prepare pages in parallel

  • Fast compression: Multi-threading even extends to the compression of images and content, a vital feature of PDF that keeps file sizes in check

  • Compatibility: Once enabled by a simple statement, no other code changes are required to use the new class

  • Performance: APO is typically twice as fast as its predecessor

💪 Usage

Enabling APO

First ensure that you have selected the Mako library for your chosen platform from the MakoApexSDK/Mako 9.0.0 distribution folder on the Mako support FTP.

To enable APO, include this statement before or after initializing JawsMako:

C++
IJawsMako::enableApexPDFOutput();
IJawsMakoPtr mako = IJawsMako::create();
IJawsMako::enableAllFeatures(mako);

In C# or Java it’s:

C#
var mako = IJawsMako.create();
IJawsMako.enableAllFeatures(mako);
IJawsMako.enableApexPDFOutput();

Thereafter, use of the IPDFOutput class will run APO instead. You can tell if a PDF was produced with APO by examining the PDF Producer property. For example, in Acrobat you would see:

image-20260703-230003.png

Once enabled, APO remains the PDF output library for the duration of the process; it’s not possible to disable once enabled

APO Library

APO is provided by a separate static library. This must be linked in to your project for APO to replace the normal PDF output. On Windows, the Apex-flavored NuGet packages already include this additional library, and this is also true of the SWIG-provided Apex packages for C#, Java & Python.

Platform

APO

Mako Core

Apex

Windows

apo.lib

mako.lib

apex.lib

macOS, Linux

apo.a

mako.a

apex.a

⌨️ Code Examples & Results

Simple converter

A PDF to PDF example, simpleconverter.exe, reads a PDF with IPDFInput and writes it with IPDFOutput, with an optional output parameter to set the PDF version to PDF 1.3. (PDF 1.3 predates transparency support in PDF, so every page must be “flattened”, a time-consuming process). In these examples, the test file is Hybrid’s 2025 Annual Report, a typical print PDF.

Results

First we’ll compare a straight PDF to PDF conversion:

PowerShell
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          16/04/2026    22:20       70432584 Annual Report 2025 - FINAL - print file.pdf
-a---          04/07/2026    17:47       42920448 SimpleConverter.exe

PS C:\apo_test> .\SimpleConverter.exe '.\Annual Report 2025 - FINAL - print file.pdf' '.\Annual Report 2025 - FINAL - print file_out.pdf'
Elapsed time: 2.815 seconds.
PS C:\apo_test> .\SimpleConverter.exe '.\Annual Report 2025 - FINAL - print file.pdf' '.\Annual Report 2025 - FINAL - print file_apo.pdf' /a
Elapsed time: 1.187 seconds.

The first execution is regular PDF output, the second with APO enabled. As you can see, it was about 2.37× as fast, or a 137% speed increase in throughput terms. This is typical of APO.

However, we’ll be the first to admit that this result is from a small sample; the annual report is only 165 pages long. To give Mako more work to do, we set the PDF version to 1.3 to force Mako to flatten transparency.

PowerShell
PS C:\apo_test> .\SimpleConverter.exe '.\Annual Report 2025 - FINAL - print file.pdf' '.\Annual Report 2025 - FINAL - print file_out.pdf' /f
Elapsed time: 17.642 seconds.
PS C:\apo_test> .\SimpleConverter.exe '.\Annual Report 2025 - FINAL - print file.pdf' '.\Annual Report 2025 - FINAL - print file_apo.pdf' /a /f
Elapsed time: 5.288 seconds.

The APO result is about 3.34× as fast, or a 234% speed increase in throughput terms, and a convincing example of the performance improvement offered by APO.

Click to see C++ & C# code examples that produced these results

C++

C++
/* -----------------------------------------------------------------------
 * <copyright file="main.cpp" company="Hybrid Software Helix Ltd">
 *  Copyright (c) 2026 Hybrid Software Ltd. All rights reserved.
 * </copyright>
 * <summary>
 *  This example is provided on an "as is" basis and without warranty of any kind.
 *  Hybrid Software Ltd. does not warrant or make any representations
 *  regarding the use or results of use of this example.
 * </summary>
 * -----------------------------------------------------------------------
 */

#include <iostream>

#include <jawsmako/jawsmako.h>
#include <jawsmako/pdfoutput.h>

using namespace JawsMako;
using namespace EDL;

int main(int argc, char* argv[])
{
    if (argc < 3)
        throw std::invalid_argument("Usage: <input_file> <output_file> [/a] [/f]");
    
    bool useAPO = false;
    bool flattenTransparency = false;

    for (int i = 3; i < argc; ++i)
    {
        if (strcmp(argv[i], "/a") == 0)
            useAPO = true;
        else if (strcmp(argv[i], "/f") == 0)
            flattenTransparency = true;
    }

    try
    {
        const auto mako = IJawsMako::create();
        IJawsMako::enableAllFeatures(mako);
        if (useAPO)
            IJawsMako::enableApexPDFOutput();

        const auto assembly = IInput::create(mako, eFFPDF)->open(argv[1]);

        const auto pdfOutput = IPDFOutput::create(mako);
        if (flattenTransparency)
            pdfOutput->setVersion(IPDFOutput::ePDF1_3);

        // Timer
        clock_t begin = clock();

        pdfOutput->writeAssembly(assembly, argv[2]);

        clock_t end = clock();
        double elapsed_secs = static_cast<double>(end - begin) / CLOCKS_PER_SEC;
        std::wcout << L"Elapsed time: " << elapsed_secs << L" seconds." << std::endl;
    }
    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 EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

C#

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

using System.Diagnostics;
using JawsMako;

namespace SimpleConverter.CSharp;

internal static class Program
{
    private static int Main(string[] args)
    {
        if (args.Length < 2)
        {
            Console.Error.WriteLine("Usage: <input_file> <output_file> [/a] [/f]");
            return 1;
        }

        var useApo = false;
        var flattenTransparency = false;

        for (var i = 2; i < args.Length; ++i)
        {
            if (args[i] == "/a")
            {
                useApo = true;
            }
            else if (args[i] == "/f")
            {
                flattenTransparency = true;
            }
        }

        try
        {
            using var mako = IJawsMako.create();
            IJawsMako.enableAllFeatures(mako);
            if (useApo)
            {
                IJawsMako.enableApexPDFOutput();
            }

            using var input = IInput.create(mako, eFileFormat.eFFPDF);
            using var assembly = input.open(args[0]);

            using var pdfOutput = IPDFOutput.create(mako);
            if (flattenTransparency)
            {
                pdfOutput.setVersion(IPDFOutput.ePDFVersion.ePDF1_3);
            }

            var stopwatch = Stopwatch.StartNew();
            pdfOutput.writeAssembly(assembly, args[1]);
            stopwatch.Stop();

            Console.WriteLine($"Elapsed time: {stopwatch.Elapsed.TotalSeconds} seconds.");
        }
        catch (MakoException e)
        {
            Console.Error.WriteLine($"Exception thrown: {e.m_errorCode}: {e.m_msg}");
            return (int)e.m_errorCode;
        }
        catch (Exception e)
        {
            Console.Error.WriteLine($"Exception thrown: {e.Message}");
            return 1;
        }

        return 0;
    }
}

For APO in Mako 9.0.0, the PDF output settings to produce PDFs to ISO standards such as PDF/X or PDF/A are not yet fully implemented and attempts to use them with throw an exception.

The regular PDF output is able to produce these. In the next release of Mako, the ability to write PDFs that meet these standards will be available in Apex PDF Output.

📚 Additional Resources