Mako 6.1.0 Release Notes
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 inputDeviceCMYK
orDeviceN
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"));
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);
This is passed to renderSeparations()
as the target space, while the vector of process color names is passed as the processColorName
s 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
);
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
);
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,
const IDOMICCProfilePtr& devlink
)
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:
-
setOptionalContent(IOptionalContentPtr optionalContent),
which makes the document’s optional content known to the SVG generator. 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.org) distribution 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 DeviceGray
. However, 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 color space 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 ]%%
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)