Created Date: Mar 12, 2021 13:39
Last Modifed Date: May 06, 2021 11:28


First read the introduction below, then use these links to go directly to:


Introduction

Mako is developed in C++, for many the first choice of language for developing with Mako. Recent versions of Mako offered the possibility to develop in other languages.

Support for C#, Java, and Python is provided by SWIG, a software development tool that connects programs written in C++ with a variety of high-level programming languages. The same Mako classes and methods are available, although the syntax is modified to suit the target language. Compare these examples for creating a thumbnail image of the first page of a PDF:

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

using namespace JawsMako;
using namespace EDL;

int wmain()
{
    // Instantiate Mako
    auto jawsMako = IJawsMako::create();
    jawsMako->enableAllFeatures(jawsMako);

    // Load the first page from the document
    auto documentAssembly = IPDFInput::create(jawsMako)->open("Test.pdf");
    auto document = documentAssembly->getDocument();
    auto fixedPage = document->getPage(0)->getContent();

    // Render an anti-aliased RGB thumbnail and save to a PNG
    auto renderer = IJawsRenderer::create(jawsMako);
    auto renderedImage = renderer->renderAntiAliased(fixedPage);

    IDOMPNGImage::encode(jawsMako, renderedImage, IOutputStream::createToFile(jawsMako, "Test.png"));
}
CPP
using JawsMako;

namespace MyMakoProject
{
    class Program
    {
        static void Main(string[] args)
        {
            // Instantiate Mako
            using var jawsMako = IJawsMako.create();
            IJawsMako.enableAllFeatures(jawsMako);

            // Load the first page from the document
            using var documentAssembly = IPDFInput.create(jawsMako).open("Test.pdf");
            using var document = documentAssembly.getDocument();
			using var page = document.getPage(0);
            using var fixedPage = page.getContent();

            // Render an anti-aliased RGB thumbnail and save to a PNG
            using var renderer = IJawsRenderer.create(jawsMako);
            using var renderedImage = renderer.renderAntiAliased(fixedPage);
            IDOMPNGImage.encode(jawsMako, renderedImage, IOutputStream.createToFile(jawsMako.getFactory(), "Test.png"));
        }
    }
}
C#
import com.globalgraphics.JawsMako.jawsmakoIF.*;

class MyMakoJavaProject
{
	public static void main(String[] args)
	{
		// Instantiate Mako
		var jawsMako = IJawsMako.create();
		IJawsMako.enableAllFeatures(jawsMako);

		// Load the first page from the document
		var documentAssembly = IPDFInput.create(jawsMako).open("Test.pdf");
		var document = documentAssembly.getDocument();
		var fixedPage = document.getPage(0).getContent();

		// Render an anti-aliased RGB thumbnail and save to a PNG
		var renderer = IJawsRenderer.create(jawsMako);
		var renderedImage = renderer.renderAntiAliased(fixedPage);
		IDOMPNGImage.encode(jawsMako, renderedImage, IOutputStream.createToFile(jawsMako.getFactory(), "Test.png"));
	}
}
JAVA
import jawsmakoIF_python as mako

# Instantiate Mako
jawsmako = mako.IJawsMako.create ()
mako.IJawsMako.enableAllFeatures (jawsmako)

# Load the first page from the document
documentassembly = mako.IPDFInput.create(jawsmako).open('Test.pdf')
document = documentassembly.getDocument()
fixedpage = document.getPage(0).getContent()

# Render an anti-aliased RGB thumbnail and save to a PNG
renderer = mako.IJawsRenderer.create(jawsmako)
renderedimage = renderer.renderAntiAliased(fixedpage)
mako.IDOMPNGImage.encode(jawsmako, renderedimage, mako.IOutputStream.createToFile(jawsmako.getFactory(), 'Test.png'))
PY


Documentation

The API documentation reflects the C++ syntax, although it can guide development in other languages. Classes have the same names; methods have the same name and signature (choice of parameters).

One important difference is concerned with inheritance. Mako relies heavily on this to organize classes in a logical manner. For example, all of the input classes (such as PDF, XPS, and PCL) inherit from the IInput base class, as shown in the API documentation:

Inheritance graph

It's occasionally necessary to cast from one class to another. Take this example, extracted from the standard sample makoconverter. Here the IInput instance is cast to an IPDFInput so that the API is available to supply the PDF's password.


if (keyStrLower == "inputpassword")
{
    IPDFInputPtr pdfInput = obj2IPDFInput (input);
    if (pdfInput)
        pdfInput->setPassword (valueStr);
}
CPP
if (keyStrLower == "inputpassword")
{
    IPDFInput pdfInput = IPDFInput.fromRCObject (input);
    if (pdfInput != null)
        pdfInput.setPassword (valueStr);
}
C#
if (keyStr.toLowerCase() == "inputpassword")
{
    IPDFInput pdfInput = IPDFInput.fromRCObject (input);
    if (pdfInput != null)
        pdfInput.setPassword (valueStr);
}
JAVA
if (inputFormat == jawsmakoIF_python.eFFPDF):
    pdfInput = jawsmakoIF_python.IPDFInput.fromRCObject (input)
    if "InputPassword" in paramDict.keys ():
        pdfInput.setPassword (paramDict ["InputPassword"])
PY


In C++, the cast is carried out by a typedef, for which one exists for each type of cast that's available. They are listed here.

C# and the other supported languages do not have the same class relationship, so each has additional methods, toRCObject() and fromRCObject() to achieve the same result. (RC means "reference counted", a characteristic of all Mako C++ classes.)

Managing C# resources with a Using statement

In the first C# example on this page, notice that every Mako class is instantiated with a Using clause. Their purpose is to indicate to the C# runtime that as soon as the object goes out of scope, it can be safely disposed. For a short example such as this there is little risk of resources running low, but in larger projects that may not be the case.

This also implies that statements that chain object creation, such as the example below, are to be avoided.

using var fixedPage = IPDFInput.create(jawsMako).open("Test.pdf").getDocument().getPage(0).getContent();
C#

Instead, create classes individually:

using var documentAssembly = IPDFInput.create(jawsMako).open("Test.pdf");
using var document = documentAssembly.getDocument();
using var page = document.getPage(0);
using var fixedPage = page.getContent();
C#

This pattern unfortunately makes code more verbose, but in projects where many objects are being created it is worth paying attention to.