Created Date: 06 Nov, 2020 17:22
Last Modifed Date: 17 May, 2022 13:52

The Mako SDK is a simple C++ SDK. The beauty of the APIs is that simple operations are just that, really simple. As your experience grows, the APIs grow with you too, facilitating complex document manipulations, rendering and transforms.

Using the API

The Mako SDK APIs are all grouped under the JawsMako namespace. This can be referenced to reduce the verbosity of the code. Most of the Mako functionality is under the jawsmako.h header file, so don't forget to include that too.

#include <jawsmako/jawsmako.h>
using namespace JawsMako;

Creating an Mako Instance

Most APIs in mako that create instances or resources will require a Mako instance. The Mako instance should also be a singleton, or in other words, there should one instance of IJawsMako in a single process at any one time. If multiple instances are used in a single process, an EDL panic exception may be raised.

Creating an instance of an IJawsMako is simple.

IJawsMakoPtr jawsMako = IJawsMako::create();

There are also overloads to the create method to set the temporary directory that Mako uses, along with it's cache directory and temporary store parameters.

These can be useful in virtualised, cloud or Docker environments.


The API makes extensive use of smart pointers. If an object uses a smart pointer, it'll end with the suffix Ptr. These can be a great help when developing in C++ as it reduces the burden of tracking ownership and ensuring correct memory de-allocation.

Opening a Document

Opening a document with the Mako SDK couldn't be simpler. All it takes is a few simple lines.

IDocumentAssemblyPtr assembly = IPDFInput::create(jawsMako)->open(pdfPath);

In the case above, we create a new instance of JawsMako. From here, we enable all of its features (including using PDF as in input format). The last step is to create an IPDFInput instance and open the pdf at the path specified by pdfPath.

Opening the path returns an IDocumentAssembly. 

You can access the document within the assembly by adding one additional line.

IDocumentPtr document = assembly->getDocument(0)

This gets the first document within the assembly.

Did you know?

An IDocumentAssembly can have more than one document inside it. PDFs will usually just have the one document, but the XPS format allows multiple documents, or 'Fixed Documents' within one XPS assembly.

Document Pages

Once you have an IDocument, enumerating or modifying the pages is easy.

for (uint32 pageIndex = 0; pageIndex < document->getNumPages(); pageIndex++)
	// Get the page and do something with it
	IPagePtr page = document.getPage(pageIndex);

Once you have an IPage, you can start querying the content.

Enumerating Page Content

Accessing the Page Content DOM

Once you have a page, you can enumerate its content. A Mako page exposes its content using a DOM. To get the root of the page, simply call either page::getContent(), or page::edit(), depending on whether you wish to read or edit the page data. This will return the root node of the DOM, which is an IDOMFixedPagePtr.

// Use this when you are reading the page content.
IDOMFixedPagePtr fixedPage = page->getContent();

// Use this when you want to edit the page content. This will give a hint to 
// mako to retain the page in memory, even under low memory conditions.
IDOMFixedPagePtr fixedPage = page->getContent();

// If a page has been edited, you can revert changes by:

Enumerating DOM Nodes

Once we have the root of the DOM, IDOMFixedPagePtr, you can access further nodes in the DOM by using a number of different methods, including:

IDOMNodePtr firstChild = node->getFirstChild();
IDOMNodePtr lastChild = node->getLastChild();

IDOMNodePtr nextChild = node->getNextChild(firstChild);
IDOMNodePtr previousChild = node->getPreviousChild(lastChild);

IDOMNodePtr nextSibling = node->getNextSibling();
IDOMNodePtr nextSibling = node->getPreviousSibling();

Once you have an IDOMNodePtr, you can see which type it is, and cast it appropriately, by calling node->getNodeType().

Below is an example of seeing whether a node is a path node, and casting it appropriately.

if (node->getNodeType() == eDOMPathNode)
	IDOMPathNode pathNode = edlobj2IDOMPathNode(node);
	// Do something with our path node...

For more details on casting, see the casting page.

There are also additional methods which allow all child nodes of a specific type to be returned in one call. 

For example, the following code can be used to get all child path nodes. 

IDOMFixedPagePtr fixedPage = page->getContent();

CEDLVector<IDOMNodePtr> pathNodes;
page->getContent()->findChildrenOfType(eDOMPathNode, pathNodes);

for (const auto& node : pathNodes)
    const auto pathNode = edlobj2IDOMPathNode(node);
	// Do something with our path node...

Custom Transforms

As an alternative, custom transforms can also be used to enumerate content. In this case, when a custom transform is implemented, you choose the methods to override, depending on which node types you want to review or edit.