Developing in C#, Java, or Python
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"));
}
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"));
}
}
}
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"));
}
}
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'))
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:
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);
}
if (keyStrLower == "inputpassword")
{
IPDFInput pdfInput = IPDFInput.fromRCObject (input);
if (pdfInput != null)
pdfInput.setPassword (valueStr);
}
if (keyStr.toLowerCase() == "inputpassword")
{
IPDFInput pdfInput = IPDFInput.fromRCObject (input);
if (pdfInput != null)
pdfInput.setPassword (valueStr);
}
if (inputFormat == jawsmakoIF_python.eFFPDF):
pdfInput = jawsmakoIF_python.IPDFInput.fromRCObject (input)
if "InputPassword" in paramDict.keys ():
pdfInput.setPassword (paramDict ["InputPassword"])
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();
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();
This pattern unfortunately makes code more verbose, but in projects where many objects are being created it is worth paying attention to.