Skip to main content
Skip table of contents

Apex: Getting started

Introduction

The Apex-enabled builds of Mako are found in the MakoApexSDK folder in your Global Graphics support FTP account. If it is not visible, please contact Global Graphics, as Apex is licensed via an addendum to your Mako agreement.

This getting started guide explains what you need to get your first Apex project built and running. These are the topics it covers:

  • Installing Vulkan

  • Apex on Windows

  • Apex on macOS

Mako 8.1 offers a simple way to evaluate Apex in the context of an existing project that makes use of the Jaws renderer (IJawsRenderer class). Refer to this page for further details.

Installing Vulkan

Vulkan must be installed in order to build an Apex-enabled Mako project.

The Vulkan SDK is a cross-platform, low-overhead graphics and compute API for GPUs. We chose Vulkan so that the Apex developers could use low-level, performant APIs to access GPU functions without having to worry about the differences in implementations from the various GPU vendors, such as NVidia & AMD. Plus it’s cross-platform, which was also necessary.

LunarG have made obtaining the SDK very easy. Visit their download page to install for the platform you need.

image-20250801-121505.png

LunarG Vulkan SDK download page

Apex on Windows

Ensure Vulkan is installed before following these instructions. Vulkan adds an environment variable for the path to the SDK (for example, VULKAN_SDK=C:\VulkanSDK\1.3.283.0) so that the Vulkan libraries can be linked. The NuGet packages are configured with this setting, so to simplify this example, I’m using one of the Apex NuGet packages. Refer to this page to learn more about the Mako NuGet packages and how to use them.

We’ll use Visual Studio for this example, although the same approach will work equally well in Rider.

C++

  • Create a new C++ console project

  • Add the NuGet package. Here I’m installing MakoCore.OEM.Apex.Win-x64.VS2019.Static.8.1.0.89.nupkg

image-20250801-154809.png

Installing a NuGet package with the Manage NuGet Packages view

  • Double-click the source file. Delete any boilerplate that Visual Studio has added, then paste this code:

Click to expand
CPP
//
//  ApexRenderExample.cpp
//

#include <iostream>

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

using namespace JawsMako;
using namespace EDL;

int main(int argc, const char* argv[])
{
    try
    {
        // Create our JawsMako instance.
        IJawsMakoPtr jawsMako = IJawsMako::create();
        IJawsMako::enableAllFeatures(jawsMako);

        U8String testFilePath = R"(C:\ggsource\Projects\CPP\ApexRenderExample\Testfiles\)";
        U8String resultFilePath = R"(C:\ggsource\Projects\CPP\ApexRenderExample\Results\)";

        // Open the document assembly, the first document, the first page and get the content thereof
        auto input = IInput::create(jawsMako, eFFPDF);
        auto assembly = input->open(testFilePath + "Cheshire Cat.pdf");
        auto document = assembly->getDocument();
        auto page = document->getPage(0);
        auto cropBox = page->getCropBox();
        auto content = page->getContent();

        // Let's render with Apex
        auto renderer = IApexRenderer::create(jawsMako);

        // First we need a renderspec, in this case to render to an IDOMImage
        auto imageRenderSpec = CImageRenderSpec();

        // We want a 300dpi result, so calculate the size in pixels
        imageRenderSpec.width = static_cast<uint32_t>(page->getWidth() / 96.0 * 300.0);
        imageRenderSpec.height = static_cast<uint32_t>(page->getHeight() / 96.0 * 300.0);

        // Specify the area to be rendered
        imageRenderSpec.sourceRect = cropBox;

        // And the color space
        imageRenderSpec.processSpace = IDOMColorSpaceDeviceRGB::create(jawsMako);

        // Now render
        renderer->render(content, &imageRenderSpec);

        // Fetch the result and encode in an image
        auto image = imageRenderSpec.result;
        IDOMPNGImage::encode(jawsMako, image, IOutputStream::createToFile(jawsMako, resultFilePath + "Cheshire Cat.png"));

        return 0;
    }
    catch (IError& e)
    {
        String errorFormatString = getEDLErrorString(e.getErrorCode());
        std::wcerr << L"Exception thrown: " << e.getErrorDescription(errorFormatString) << std::endl;
        return 1;
    }
    catch (std::exception& e)
    {
        std::wcerr << L"std::exception thrown: " << e.what() << std::endl;
        return 1;
    }
}
  • Adjust the paths (lines 21-22) and the filenames (lines 26 & 53) to suit

  • Build and run

C#

  • Create a new C# console project

  • Add the NuGet package. Here I’m installing MakoCore.OEM.Net.Apex.Windows.nupkg

image-20250801-163412.png

Installing the Mako NuGet package for C#

  • Open the source file (Program.cs). Delete any boilerplate that Visual Studio has added, then paste this code:

Click to expand
C#
//
//  ApexRenderExample
//
//  Program.cs
//

using JawsMako;

namespace ApexRenderExample;

internal class Program
{
    static int Main(string[] args)
    {
        try
        {
            var testFilePath = @"C:\ggsource\Projects\CS\ApexRenderExample\Testfiles\";
            var resultFilePath = @"C:\ggsource\Projects\CS\ApexRenderExample\Results\";

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

            // Open the document assembly, the first document, the first page and get the content thereof
            var input = IInput.create(mako, eFileFormat.eFFPDF);
            var assembly = input.open(testFilePath + "Cheshire Cat.pdf");
            var document = assembly.getDocument();
            var page = document.getPage();
            var cropBox = page.getCropBox();
            var content = page.getContent();

            // Let's render with Apex
            var renderer = IApexRenderer.create(mako);

            // First we need a renderspec, in this case to render to an IDOMImage
            var imageRenderSpec = new CImageRenderSpec();

            // We want a 300dpi result, so calculate the size in pixels
            imageRenderSpec.width = (uint)(page.getWidth() / 96.0 * 300.0);
            imageRenderSpec.height = (uint)(page.getHeight() / 96.0 * 300.0);

            // Specify the area to be rendered
            imageRenderSpec.sourceRect = cropBox;

            // And the color space
            imageRenderSpec.processSpace = IDOMColorSpaceDeviceRGB.create(mako);

            // Now render
            renderer.render(content, imageRenderSpec);

            // Fetch the result and encode in an image
            var image = imageRenderSpec.result;
            IDOMPNGImage.encode(mako, image, IOutputStream.createToFile(mako, resultFilePath + "Cheshire Cat.png"));
        }
        catch (MakoException e)
        {
            Console.WriteLine($"Exception thrown: {e.m_errorCode}: {e.m_msg}");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Exception thrown: {e}");
        }

        return 0;
    }
}
  • Adjust the paths (lines 17-18) and the filenames (lines 25 & 52) to suit

  • Build and run

Apex on macOS

A reminder that the Vulkan SDK must be installed for these examples to build and run correctly.

C++

For this example, we’ll use XCode.

  • Begin by creating a new Command Line Tool

image-20250802-103607.png

Xcode new project window

  • Set some options

image-20250802-103814.png

Project options

  • Decide where to save it

image-20250802-165704.png

Save location

  • Next we need Mako. I’ve copied the folder from the macOS distribution folder found in MakoApexSDKto the parent folder, and we add the interface and libs paths to the project settings.

image-20250802-171724.png

Path to headers (in Build Settings)

  • Besides Mako we need some standard application frameworks, plus Metal and MoltenVK.

    • Apple’s Metal is the low-level, high-performance graphics and compute API that offers developers near-direct access to the GPU for rendering and computation on Apple devices.

    • MoltenVK is the interface layer between Vulkan and Metal. It’s packaged with the Vulkan SDK.

  • Add these frameworks and libraries in the Build Phases tab

image-20250802-175605.png
  • You can find the MoltenVK framework in the Vulkan SDK. Click Add other… in the Frameworks pane, then navigate to your installation of the Vulkan SDK.

image-20250802-174357.png

Location of MoltenVK in the Vulkan SDK

  • The libraries come from the Mako distribution folder. You need both mako.a and apex.a:

image-20250802-175040.png

Mako libraries

Now we can write some code. Open main.cpp , remove any boilerplate that Xcode has added, then paste this code:

Click to expand
CPP
//
//  main.cpp
//  ApexRenderExample
//
//  Created by you on 31/07/2025.
//

#include <iostream>

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

using namespace JawsMako;
using namespace EDL;

int main(int argc, const char * argv[])
{
    try
    {
        U8String testFilePath = "/Users/davids/ggsource/ApexExamples/TestFiles/";
        U8String resultFilePath = "/Users/davids/ggsource/ApexExamples/Results/";
      
        // Create our JawsMako instance.
        IJawsMakoPtr jawsMako = IJawsMako::create();
        IJawsMako::enableAllFeatures(jawsMako);

        // Open the adocument assembly, the first document, the first page and get the content thereof
        auto input = IInput::create(jawsMako, eFFPDF);
        auto assembly = input->open(testFilePath + "Cheshire Cat.pdf");
        auto document = assembly->getDocument();
        auto page = document->getPage(0);
        auto cropBox = page->getCropBox();
        auto content = page->getContent();
        
        // Let's render with Apex
        auto renderer = IApexRenderer::create(jawsMako);
        
        // First we need a renderspec, in this case to render to an IDOMImage
        auto imageRenderSpec = CImageRenderSpec();
        
        // We want a 300dpi result, so calculate the size in pixels
        imageRenderSpec.width = page->getWidth() / 96.0 * 300.0;
        imageRenderSpec.height = page->getHeight() / 96.0 * 300.0;
        
        imageRenderSpec.sourceRect = cropBox;
        imageRenderSpec.processSpace = IDOMColorSpaceDeviceRGB::create(jawsMako);
        
        // Now render
        renderer->render(content, &imageRenderSpec);
        
        // Fetch the result and encode in an image
        auto image = imageRenderSpec.result;
        IDOMPNGImage::encode(jawsMako, image, IOutputStream::createToFile(jawsMako, resultFilePath + "Cheshire Cat.png"));
        
        return 0;
    }
    catch (IError &e)
    {
        String errorFormatString = getEDLErrorString(e.getErrorCode());
        std::wcerr << L"Exception thrown: " << e.getErrorDescription(errorFormatString) << std::endl;
        return 1;
    }
    catch (std::exception &e)
    {
        std::wcerr << L"std::exception thrown: " << e.what() << std::endl;
        return 1;
    }
        
    return 0;
}
  • Adjust the paths (lines 20-21) and the filenames (lines 29 & 53) to suit

  • Build and run

C#

For C# I’ll use Rider. The MakoApexSDK SWIG/macOS_SWIG_(C#-Java-Python) contains a NuGet package that we can use.

  • Create a new C# console project

image-20250802-184624.png

Create a new Console project

  • Add the NuGet package. See this page on how to work with NuGet packages from the Mako SDK if you are unfamiliar with them. Here I’m installing MakoCore.OEM.Net.Apex.macOS.ub.8.1.0.110.nupkg.

image-20250802-185835.png
  • Click plus (arrowed) to initiate installation of the package.

image-20250802-185956.png
  • Add some code. Open the source file (Program.cs). Delete any boilerplate that Rider has added, then paste this code:

Click to expand
C#
//
//  ApexRenderExample
//
//  Program.cs
//

using JawsMako;

namespace ApexRenderExampleCS;

internal class Program
{
    static int Main(string[] args)
    {
        try
        {
            const string testFilePath = "/Users/davids/ggsource/ApexExamples/TestFiles/";
            const string resultFilePath = "/Users/davids/ggsource/ApexExamples/Results/";

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

            // Open the document assembly, the first document, the first page and get the content thereof
            var input = IInput.create(mako, eFileFormat.eFFPDF);
            var assembly = input.open(testFilePath + "Cheshire Cat.pdf");
            var document = assembly.getDocument();
            var page = document.getPage();
            var cropBox = page.getCropBox();
            var content = page.getContent();

            // Let's render with Apex
            var renderer = IApexRenderer.create(mako);

            // First, we need a renderspec; in this case, to render to an IDOMImage
            var imageRenderSpec = new CImageRenderSpec();

            // We want a 300dpi result, so calculate the size in pixels
            imageRenderSpec.width = (uint)(page.getWidth() / 96.0 * 300.0);
            imageRenderSpec.height = (uint)(page.getHeight() / 96.0 * 300.0);

            // Specify the area to be rendered
            imageRenderSpec.sourceRect = cropBox;

            // And the color space
            imageRenderSpec.processSpace = IDOMColorSpaceDeviceRGB.create(mako);

            // Now render
            renderer.render(content, imageRenderSpec);

            // Fetch the result and encode in an image
            var image = imageRenderSpec.result;
            IDOMPNGImage.encode(mako, image, IOutputStream.createToFile(mako, resultFilePath + "Cheshire Cat.png"));
        }
        catch (MakoException e)
        {
            Console.WriteLine($"Exception thrown: {e.m_errorCode}: {e.m_msg}");
        }
        catch (Exception e)
        {
            Console.WriteLine($"Exception thrown: {e}");
        }

        return 0;
    }
}
  • Adjust the paths (lines 17-18) and the filenames (lines 25 & 52) to suit

  • Build and run

JavaScript errors detected

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

If this problem persists, please contact our support.