Created Date: May 06, 2021 09:01
Last Modifed Date: May 06, 2021 09:01


Introduction

Mako 6.1 is the first major release since Mako 6.0. This release consolidates the good work of Mako 6.0, paying particular attention to output quality and performance. We also responded to customer issues that required core code changes.

Nonetheless there was time for some new developments. Mako 6.1 introduces:

  • An object-based color separator feature
  • Support for rendering with an alpha channel (as a core feature)
  • Extended gamut support – rendering to CMYKOG, for example
  • Improved support for Acrobat Forms creation
  • A Linux ARM release for Raspberry Pi 4 (32-bit only)
  • Releases of C#, Java, and Python API libraries for macOS and Linux, including C# NuGet packages
  • A demo version to facilitate evaluation of the Mako Core SDK. (The licensing mechanism employed does not affect the builds that Mako OEMs have access to.)

The release notes are presented in terms of the development tasks (MAKO-XXXX) that were undertaken to complete this release. Only items of significance – those that add new features / improvements in this release or address identifiable support issues (labelled MAKOSUP-XXXXX)  – are included.

New features

MAKO-3263   Create a “Mako Separator” module or example for Mako

This development was driven by a customer requirement to generate color separations as Mako DOM objects instead of images made by IJawsRenderer::renderSeparations().

A new interface is introduced, ISeparator(), that fulfills this purpose. It works by taking an input IDOMFixedPage and creating from it separate IDOMFixedPages, in monochrome, one for each colorant in the input.

Two modes of operation are offered:

  • Generate process + spot separations (default)
  • Convert spot colors to process (CMYK) before separating

For each mode, the renderer and color converter transforms are employed. The renderer transform is used to render all transparency, while the color converter transform converts all color spaces to the target space (currently CMYK only), preserving DeviceN colors (if not converting spot colors).

The separator then takes the transformed IDOMFixedPage and walks the DOM, "separating" as required. There are three nodes of interest: paths, glyphs, and charpaths. For each node we take the fill or stroke brush and handle them accordingly. From here, we need to handle two cases:

  • Image brushes are handled by working out the channel and then selecting it using the channel selector filter. Changes were made to the channel selector filter for this purpose, previously only all color channels, or extra channels could be selected. A new eSelectChannel option allows you to select a specific color channel.
  • Non-image brushes are handled by getting the color space and creating a new DeviceGray color space, using the appropriate color value from the input DeviceCMYK or DeviceN color.

There are, however, some special cases where handling color is less straightforward. All shading, linear gradient, and radial gradient brushes are rendered; from there, handle it as described above for image brushes.

A sample of this code can be found here on GitHub.

MAKO-3090   Support rendering with an alpha channel as core feature

Before we added this feature, Mako provided no means to generate a raster with an alpha channel. Although it is possible to infer transparency information by rendering twice and comparing pixel values (see this example on GitHub), it is not as efficient as doing so in the RIP.

IJawsRenderer::renderSeparations() gains a new parameter, alphageneration. Set to false by default, when set to true, an additional separation image representing the alpha channel is generated. Use IDOMRecombineImage to convert this into a composite and save to an image format that supports an alpha channel (for example, PNG).

This code snippet shows how:

// Render separations
auto mRenderer = IJawsRenderer::create(jawsMako);
CEDLVector<IDOMImagePtr> separations = mRenderer->renderSeparations(
    fixedPage,
    8,
    IDOMColorSpacesRGB::create(jawsMako),
    2,
    FRect(),
    pixelWidth, pixelHeight,
    CSpotColorNames(),
    IOptionalContentPtr(),
    eOCEView,
    CU8StringVect(),
    true);
// Create a composite image from the separations
IDOMImagePtr compositeImage = createInstance<IDOMRecombineImage>(jawsMako);
IDOMRecombineImage::Data params;
params.colorSpace = IDOMColorSpaceDeviceRGB::create(jawsMako);
for (uint16 i = 0; i < 3; i++)
{
    params.componentImages.append(separations[i]);
}
params.extraChannel = separations[3];
compositeImage->init(¶ms);

// Write PNG
IDOMPNGImage::encode(jawsMako, compositeImage,
    IOutputStream::createToFile(jawsMako, "out.png"));
CPP

Only the rendering method IJawsRender::renderSeparations() supports alpha channel generation.

MAKO-2434   MAKOSUP-10436 Extended gamut separations rendering (CMYKOGV)

IJawsMako::renderSeparations() now supports a DeviceN colorspace as the target space. This makes it possible to create extended gamut separations such as hi-fi color.

For this, two things are needed:

  • An ICC output profile for the color space (not a device link)
  • A list of the names of the process components that this profile produces in the order it produces them (for example, “Cyan”, “Magenta”, “Yellow”, “Black”, “Orange”, “Green” for a CMYKOG profile)

From the profile, an IDOMColorSpaceICCBased color space is created; for example:

IDOMICCProfilePtr profile = IDOMICCProfile::create(jawsMako, 
IInputStream::createFromFile(jawsMako, "SixColorCMYKOG.icc"));
IDOMColorSpaceICCBasedPtr iccCmykogSpace = 
IDOMColorSpaceICCBased::create(jawsMako, profile);
CPP

This is passed to renderSeparations() as the target space, while the vector of process color names is passed as the processColorNames parameter; for example:

// The process components in that CMYKOG profile
CU8StringVect processComponents;
processComponents.append("Cyan");
processComponents.append("Magenta");
processComponents.append("Yellow");
processComponents.append("Black");
processComponents.append("Orange");
processComponents.append("Green");

// Render separations
IJawsRendererPtr renderer = IJawsRenderer::create(jawsMako);
CEDLVector<IDOMImagePtr> separations = 
	renderer->renderSeparations(
	fixedPage, 
	8, 
	iccCmykogSpace, 
	0, FRect(), 
	0, 
	0, 
	processComponents
);
CPP

MAKO-2915   MAKOSUP-10529 Support of forms objects

This change makes it possible to create Acroforms from scratch. Previously, the IWidgetAnnotation API (used in conjunction with IForm and IFormField) could interrogate only the properties of widgets (the collection of properties that control a field’s behavior) for existing form fields. With these new APIs, they can now be created too:

  • IWidgetAnnotation::createTextField()
  • IWidgetAnnotation::createCheckButton()
  • IWidgetAnnotation::createRadioButtons() (for making a set of radio buttons)
  • IWidgetAnnotation::createChoiceField() (supports choice, drop-down, and combo annotations)
  • IWidgetAnnotation::createButton() (Push buttons)

These APIs create a field and in a single operation add it to the IForm and to the page. The following code snippet shows a text field being added:

#define MM2XPS(value) value / 25.4 * 96.0

// Create the form
IFormPtr form;
form = IForm::create(jawsMako);
document->setForm(form);

// Select Arial for the captions
IDOMFontOpenTypePtr arial;
uint32 arialIndex = 0;
arial = edlobj2IDOMFontOpenType(jawsMako->findFont("Arial", arialIndex));

// Add a text field – "Name"
IWidgetAnnotationPtr widget = IWidgetAnnotation::createTextField(
	jawsMako,
	form,
	page,
	FRect(MM2XPS(75.0), MM2XPS(25.0), MM2XPS(120), MM2XPS(6.5)),
	"Name",
	"",
	11.0f,
	arial,
	arialIndex,
	IWidgetAnnotation::eFELatin
	);
CPP

This work includes generation of appearance streams (the bitmap that represents the form field on the page) so that when opened in Acrobat, the field has the correct appearance without the need to resave the PDF.

MAKO-3105   MAKOSUP-10460 Linux support

To make it easier to use C# and Java on Linux, this release includes builds and NuGet packages for Linux and macOS.

MAKO-2926   MAKOSUP-10522 Linux Arm support

This release adds a Mako library built for Debian Buster (32-bit) built to run on a Raspberry Pi 4.

Improvements

MAKO-3080   MAKOSUP-10526 DeviceLink ICC Profiles

Support for DeviceLink ICC profiles has been improved in this release. It is now possible to “register” a DeviceLink profile you can use when conversion between two given color spaces is requested. The API that does this follows:

useDeviceLinkForConversionsBetween(
       const IDOMColorSpaceICCBasedPtr& sourceSpace,
       const IDOMColorSpaceICCBasedPtr& destSpace
)

To delete the conversion:

deleteDeviceLinkForConversionsBetween(
       const IDOMColorSpaceICCBasedPtr& sourceSpace,
       const IDOMColorSpaceICCBasedPtr& destSpace
)

Additional APIs (getNumDeviceLinkICCProfiles() and getDeviceLinkICCProfile() are provided to help manage them.

MAKO-3119   Add OCG support to ISVGGenerator

The SVG generator class, ISVGGenerator(), adds two new methods:

  1. setOptionalContent(IOptionalContentPtr optionalContent),which makes the document’s optional content known to the SVG generator.
  2. setOptionalContentUsage(eOptionalContentEvent optionalContentEvent), which determines if the OCG is included in the output based on visibility when viewing, printing, or exporting (eOCEView, eOCEPrint, eOCEExport).

The above methods are similar to the optionalContent and optionalContentUsage arguments to IJawsRenderer::render().

MAKO-2718  Expose TIFF Tag Predictor in Mako

An additional parameter is added to the IDOMTIFFImage::encode() method to specify a prediction type, either horizontal (eTIFFPrediction::eTPHorizontal) or none (eTIFFPrediction::eTPNone).

MAKO-3032   Support SWIG on M1 Macs (Python)

The SWIG (Simplified Wrapper and Interface Generator, www.swig.orgdistribution includes a Python library built to run natively on M1 Macs.

MAKO-2798  Support embedding of disk-based CID fonts

This is now supported by the IDistiller class, and exposed as new arguments added to MakoDistillerCMD:

Argument

Action

-dfb

Embed the base 14 fonts

-dfc

Embed disk-based (external) CIDFonts

-dfe

embed fonts (use -dfb for the base 14 fonts and -dfc for CID)

This matches the equivalent for Jaws PDF Library, the testpdflibcmd utility.

MAKO-3085   Add support for Type1 (PFB) fonts to IDistiller::addFont()

Type1 fonts of this type are less popular than they once were, as most modern fonts are packaged as OpenType. Mako’s IDistiller class was not configured to accept Type1 via the addFont() method (although it was possible to add them via a PostScript prolog). This change adds that support.

MAKO-2727   Add autorotate pages option to MakoDistiller

This change adds control over auto-rotation of pages, which is where the output is rotated according to the predominant text direction on the page.

IDistiller() adds autorotatepages=true|false to the list of supported parameters (applied with IDistiller::setParameter().

The feature is off by default as it is in Jaws PDFLib, but PDFLib’s test application testpdflibcmd recognizes the -dr switch to enable it. The same switch is added to the equivalent sample app in Mako (makodistillercmd).

MAKO-3163   Add -dB(C|N|P) argument to makodistillercmd to match testpdflibcmd

The command-line test application for IDistiller(), makodistillercmd, adds an argument to control the processing of DSC (Document Structuring Conventions) comments that specify a bounding box. With this control, the box dimensions are interpreted as follows:

Argument

Use the DSC BoundingBox to specify:

-dBC

The Crop box

-dBN

Nothing (default)

-dBP

Page size (Media Box)

This matches the equivalent for Jaws PDF Library, the testpdflibcmd utility.

MAKO-3111   SWIG library versioning

The C# and Java libraries now carry Mako version information to facilitate support triaging.

MAKO-3165   Add SWIG makoconverter source code to distribution for Python and Java

This source, now included in the SWIG builds, provides valuable sample code, particularly as there is a C++ version for easy comparison.

MAKO-3103   Support DeviceGray in PDF/X-1a output

Although the PDF/X-1a specification states that DeviceRGB is prohibited in PDF/X-1a, it is silent on DeviceGrayHowever, there are PDF/X-1a files using DeviceGray, and this change allows MAKO’s PDF/X-1a preset to output DeviceGray.

MAKO-2925   MAKOSUP-6559 Support for spot color output in PDF/X-1a

Before this version, choosing PDF/X-1a as the output format for conversion would produce a CMYK result even when spot colors were present in the original. With this change, setting the output to PDF/X-1a preserves spot colors; this is now the default behavior.

You can use the makoconverter sample with the preset as before:

makoconverter MyInput.pdf MyOutput.pdf Preset=PDF/X-1a

If you want to restrict the output to CMYK, simply add ConvertAllColors=true; for example:

makoconverter MyInput.pdf MyOutput.pdf Preset=PDF/X-1a ConvertAllColors=true

MAKO-3113   Compliance regression when processing files to PDF/X-1a

For PDF/X-1a Mako sets the setShouldConvertForSpaceType flag so that it does not convert DeviceN colorspaces (to preserve spots). However, the alternate colorspace of the spot must also be valid for PDF/X-1a so it also needs to be inspected. Now fixed.

MAKO-3110   Move iOS builds to the iOS 14.4 SDK

The iOS builds are now built with an updated compiler.

Bug fixes

MAKO-2076   QualityLogic test files failing compliance checks when converted to PDF/A-2b and PDF/X-4

and

MAKO-3177   MAKOSUP-10665 Mako Converter and preset=PDF/A-2b

This change addresses some PDF/A and PDF/X compliance issues. Certain XMP entries in the image or object metadata are not permitted by these ISO standards, as they are not listed in the XMP metadata specification. A table of approved entries and namespaces has been added to Mako and offending entries are now removed, enabling files created by Mako to pass compliance checks.

MAKO-3120   Mako PDFInput.create().open(filename) never returns

This was fixed in Mako 6.0.1, and fixes a very old issue, MAKO-86. See the Mako 6.0.1 Release Notes (MAKO-3148) for full details.

MAKO-2472   Regression in Trunk CID Font handling case compared to 4.8.7

This issue is concerned with Mako’s behavior when substituting a CID Font with a vertical writing mode. If a vertical version of the glyph does not exist in the substitute font, a normal glyph is selected, but in this case a .notdef character was being substituted. Now fixed.

MAKO-3052   MAKOSUP-10574 Mako hangs in getPage(1)

This was an issue in PCL input when reading image data, causing a hang. Now fixed.

MAKO-3093   Font embedding issue with Type1 font (regression)

A Type1 font in a PostScript job was incorrectly identified as a Symbolic font. Now fixed.

MAKO-3164   PDF/X-4 output preset dropping trapped flag

The flag indicating that a PDF is trapped was ignored during PDF to PDF/X-4 conversion. It is now preserved.

MAKO-3109   A Font Merge Crashes with an Internal RIP Error

Mako features a powerful font merger that can merge subsets or complete fonts as part of its PDF output. A QA exercise, whereby thousands of fonts from hundreds of PDF test files are merged to root out issues, uncovered a problem that is now fixed. 

MAKO-3112   MAKOSUP-10604 Mako renders different characters for PCL6 occasionally

Investigation uncovered an issue when reading PCL XL TrueType character Format 1 Class 2 headers. Now fixed.

MAKO-3118   MAKOSUP-10616 A PDF that appears to be corrupted is displayed without errors in Adobe Reader.

It was noted that Acrobat's Preflight: Report PDF Syntax Issues for the input file reports that the document structure is corrupt. Once converted with Mako, this no longer occurs (that is, Mako 6.1.0 can process and successfully repair the file).

MAKO-3121   MAKOSUP-10614 PDF processing fails because of Bad PDF file trailer

This is a port to Mako of a Jaws RIP fix. See Jaws 4001.0 Latest (March 2021) Release Notes for details.

MAKO-3143   MAKOSUP-10639 Text glyphs replaced with something else

The fix required working around a broken CFF font in a PDF.

MAKO-3167   MAKOSUP-10660 Text is missing after processing

This problem is caused by a badly broken PDF. It contains a BT (begin text) operator, but with no text, and no corresponding ET (end text) operator. The file does, however, display as expected in Acrobat, which simply ignores the problem.

The same is now possible in Mako, but it was felt that a repair of this type, given the nature of the breakage of the PDF specification, should be controlled via an environment variable so that it can be turned on only if required. To enable this feature, set J_ALLOWGRAPHICSINTEXTOBJECTS before processing.

The need for the environment variable is demonstrated below. Without it, an exception as shown here is thrown:

Exception thrown: [jaws/makojaws.cpp:7391] Internal RIP error: General failure:
              %%%%[ Warning: Job contains a gsave inside a text object. Continuing. ]%%%%
              %%[ Error: fill or stroke encountered within a text object ]%%
              %%[ Error: invalidcontext; OffendingCommand: -f- ]%%
              %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%
TEXT

MAKO-3173   MAKOSUP-10661 Mako discards PDF searchable text layer added by OCR engine

The customer file makes use of Text Rendering Mode 3, which is a rendering mode for PDF text where the text is invisible. Usually Mako discards such elements, as they have no impact on the visual appearance of the page, but in this case that is not what is required.

To solve this, changes to Mako’s DOM were needed. Two new methods are added to the IDOMGlyphs class, IDOMGlyphs::getIsInvisible() and IDOMGlyphs::setIsInvisible() and other changes. This ensures that such text is maintained into output PDFs; it carries the correct encoding information to enable meaningful copy and paste.

MAKO-3180   MAKOSUP-10667 Unexpected result rasterizing .ai file

The customer file contained very large patterns, enough to cause the in-memory pattern display lists to fill up and then spill to disk. A problem with this mechanism was the cause of the content being lost. Now fixed (after some significant improvements were made).

MAKO-3193   MAKOSUP-10676 Quality Issue with separation rendering

The reason the customer sees the behavior they do is that Mako currently restricts the resolution of some rendering operations. The two main affected areas are transparent images (particularly where they overlap or have a soft mask) and shading patterns. This was done for performance reasons, in the expectation that these items would not usually benefit from rendering at higher resolutions.

In those situations, the resolution was capped to the effective resolution of the output. For example, in the customer case, they rendered at an effective 50 dpi, and so the soft masked image at the bottom right was flattened at 50 dpi. Without this restriction on resolution, when rendering at a quality factor of three, the flattening would occur at 150 dpi before being ultimately filtered down to 50 dpi output.

The cap on effective resolution is removed, which causes images to be flattened at the internal oversampled resolution. However, this may come with a performance cost, so we now offer some additional control via an environment variable J_AA_LPICONTROL.

If J_AA_LPICONTROL is set to UNSCALED, Mako reverts to the previous behavior. If it is set to an integer > 0 and lower than the resolution, we populate the internal lpi with that amount. Transparency flattening with overlapping images and soft masks are performed at a resolution twice that value.

The meaning of the quality level for renderAntiAliased() and renderSeparations() anti-aliasing is not the same. To get an equivalent quality level for renderSeparations() you need to add 1. So renderSeparations() with anti-aliasing quality 4 gives the same quality as renderAntiAliased() with quality 3.

MAKO-3206   MAKOSUP-10675 SIGSEGV rendering a file (thumbnail worker)

The job contains a font with a Version 5 OS/2 table. Mako supports these, but when reading the OS/2 table data, it’s reading the larger Version 5 data into a structure sized for Version 3, and an exception is thrown. Now fixed.

MAKO-3226   MAKOSUP-10689 Non space text only extracted as spaces

The job contains bad bfrange entries in its ToUnicode CMap, causing Mako to reject the CMap entirely. Now fixed, by ignoring such entries and continuing to process the CMap.

MAKO-3233   MAKOSUP-10690 Conversion of QES Signed PDF to XPS losing content

The customer file contained a signature in the form of an annotation, which when converted to XPS was incorrectly clipped, resulting in content that was obscured by a white box. Now fixed.

MAKO-3255   MAKOSUP-10693 setMediaBox doesn't reset the origin

In Mako 5.2.1, a change was made such that the MediaBox was retained as-is when writing non-incremental pages to PDF. Prior to this change, incremental pages were always retaining the origin, and non-incremental pages would have their MediaBox origin reset to 0,0.

This was done because the previous behavior was breaking a customer’s workflow. Unfortunately, this change has broken a different customer’s workflow, who requested an option to revert the behavior. This change provides it via a new IPDFOutput API:

               virtual void setForceMediaBoxOriginZero(bool force) = 0;

If force is true (default false) then in the PDF output, Mako sets the page media box origin to 0,0

Alternatively, IPDFOutput::setParameter("ForceMediaBoxOriginZero", "true") achieves the same result as calling the above API with true.

Distribution

MAKO 6.1.0 is built for the following platforms:

  • Android
  • iOS
  • Linux (for Debian-based distributions, for example, Ubuntu, Mint)
  • Linux (Centos)
  • Linux (for Debian Stretch)
  • Linux (for MUSL distributions, for example, Alpine Linux)
  • macOS
  • Windows (static and dynamic libs, VS 2019 (V142), x86 and x64)
  • Windows UWP (Store apps, Windows 10 IoT)

Mako supports the following programming languages:

  • C++ (Mako is written in C++)
  • C# (.Net Framework and .Net Core)
  • Java (built with OpenJDK11)
  • Python (v3.8)

The alternatives to C++ are built using SWIG (www.swig.org), which provides a translation to the native libraries, found in these distribution folders:

  • Linux_SWIG_(C#-Java-Python)
  • macOS_SWIG_(C#-Java-Python)
  • Windows_SWIG_(C#-Java-Python)