PD4ML v4 is based on a completely redesigned architecture to be more compatible with current HTML, CSS and PDF standards. PD4ML v4 implements an updated API that better matches changes in the document processing flow. To avoid conflicts with the old API, PD4ML v4 also changes the Java package structure from org.zefer.pd4ml to com.pd4ml. All of this makes newer PD4ML product libraries incompatible with products based on PD4ML v3.

To simplify migration from PD4ML v3 to v4, PD4ML v4 package also includes org.zefer.pd4ml.* wrapper classes, match PD4ML v3 API. The wrapper classes translate PD4ML v3 API calls to PD4ML v4. This allows to use PD4ML v4 library JAR as a drop-in replacement for pd4ml.jar of v3 in most use cases.

To unlock more v4 features, it is recommended to switch to the new API using the instructions below. But even if you stay on the wrapper PD4ML v3 API, you always have access to com.pd4ml.PD4ML instance via org.zefer.pd4ml.PD4ML.pd4mlNew reference.

1.Applying PD4ML activation code

Software activation is new in PD4ML v4. The activation code enables or disables certain product features, depending on the license you purchased.

To activate the software, you need to either place pd4ml.lic (a text file with an activation code) in your application’s working directory, or in the root of its classpath.

For example, in the context of a web application, this could be /WEB-INF/classes (not WEB-INF/lib). You can also package pd4ml.lic into your application’s JAR, but you’ll have to experiment with this: the hierarchy of EARs, WARs, JARs, etc. can confuse the PD4ML classloader.

Another approach is to pass the activation code itself or the path to the pd4ml.lic file (or even the URL) directly to the com.pd4ml.PD4ML(String) constructor or applyLicense() method.

You can get the activation code or download pd4ml.lic from https://pd4ml.com/view-my-licenses/

The activation code contains information about the available features, as well as the end date of the maintenance period. The code only activates software versions released before the date. If you apply the code to a version of the software released later, it will watermark the generated documents with a “DEMO MODE” banner, just as if you hadn’t applied any activation at all.

Other reasons for the “DEMO MODE” banner is a corrupted activation code or if PD4ML cannot find/read pd4ml.lic for some reason. A verbose diagnostics output triggered by pd4ml.setLogLevel(255) can help to determine what is wrong with the activation.

2.New conversion flow

While PD4ML v3 processes document with a single call pd4ml.render(in, out), PD4ML v4 separates the document conversion process into two phases: input document parsing and output document rendering. It allows to collect input document metadata before the output rendering. Or to reuse parsed input document to produce multiple formats: PDF, RTF, raster images.

The example demonstrates a reading of a source document from an HTML string and a writing of a conversion result to a temp file with PD4ML v4 and v3 API.

PD4ML v4 example relies on default settings of PD4ML: output format is A4, 10mm margins etc. PD4ML v3 has different default margins (T,L,B,R): 25pt, 50pt, 25pt, 25pt

PD4ML pd4ml = new PD4ML();

String html = "TEST<pd4ml:page.break><b>Hello, World!</b>";
ByteArrayInputStream bais =
new ByteArrayInputStream(html.getBytes());

// read and parse HTML
pd4ml.readHTML(bais);

File pdf = File.createTempFile("result", ".pdf");
FileOutputStream fos = new FileOutputStream(pdf);

// render and write the result as PDF
pd4ml.writePDF(fos);

// alternatively or additionally:
// pd4ml.writeRTF(rtfos, false);
// BufferedImage[] images = pd4ml.renderAsImages();

// open the just-generated PDF with a default PDF viewer
Desktop.getDesktop().open(pdf);
PD4ML pd4ml = new PD4ML();

String html = "TEST<b>Hello, World!</b>";
StringReader bais = new StringReader(html);

File pdf = File.createTempFile("result", ".pdf");
FileOutputStream fos = new FileOutputStream(pdf);
// render and write the result as PDF
pd4ml.render(bais, fos);

// open the just-generated PDF with a default PDF viewer
Desktop.getDesktop().open(pdf);

PD4ML v3 specifies the PDF, PDFA, or RTF output document type using the outputFormat() method. PD4ML v4 has special writing methods for certain types: writePDF(OutputStream os, String pdfFormat), writeRTF(OutputStream os), renderAsImages().

3.PDF document defaults: scale factor, margins, view mode

There are 3 important PD4ML properties, impact resulting PDF page format and layout: pageSize, pageMargins, htmlWidth.

1. pageSize defines output paper format: A4, ISOB4, LETTER, LEGAL etc.

For both PD4ML v3 and v4 the default page format is A4 and orientation portrait.

2. pageMargins define blank page area width around the page content. The default value for it in PD4ML v4 is new PageMargins(10, 10, 10, 10, Units.MM), while in PD4ML v3 it is new Insets(25, 50, 25, 25); (T,L,B,R in typographical points). So if you’d like to keep the margins as it was in v3, explicitly call pd4ml.setPageMargins(new PageMargins(50, 25, 25, 25, Units.PT)); (L,T,R,B)

3. htmlWidth default value in PD4ML v3 and in v4 is 640px.

With htmlWidth=727px you can achieve 1:1 pixel/point correspondence of 72 DPI resolution. It is calculated from (A4.width - margins.left - margins.right) * PIXELS_PER_POINT, which is (595pt - (10mm + 10mm) * 2.835pt/mm) * 1.35px/pt

4. Default <body> margin in PD4ML v3 is 8px. Can be applied in PD4ML v4 with pd4ml.addStyle("BODY {margin: 8px}", true);

5. PD4ML v3 default PDF view mode can be set in PD4ML v4 with pd4ml.setParam(Constants.PD4ML_DOCUMENT_VIEW_MODE, "OneColumn");

PD4ML pd4ml = new PD4ML();
pd4ml.setParam(Constants.PD4ML_DOCUMENT_VIEW_MODE, "OneColumn");
pd4ml.setHtmlWidth(640);
pd4ml.addStyle("BODY { margin: 8px }", true);
pd4ml.setPageSize(PageSize.A4);
pd4ml.setPageMargins(new PageMargins(50, 25, 25, 25, Units.PT));

4.PD4ML API calls map

The chart shows the correspondence between PD4ML API calls in v3 and v4. The method names are hyperlinked with matching Javadoc entries.

org.zefer.pd4ml.PD4ML (v3) com.pd4ml.PD4ML (v4) Comments
addDocumentActionHandler(
String actionType, String javaScript)
addDocumentActionHandler(
String actionType, String javaScript)
method defines JavaScript action handler for generated document.
addMetadata(String key, String value, boolean hide) addMetadata(String key, String value,
boolean hide)
The method defines custom properties for PDF document meta data.

addStyle
(String stylesheet, boolean overrideDocumentStyles)
addStyle(String stylesheet,
boolean overrideDocumentStyles)
Apply additional stylesheet to the document
addStyle(URL stylesheet, boolean overrideDocumentStyles) addStyle(URL stylesheet,
boolean overrideDocumentStyles)
Apply additional stylesheet to the document
adjustHtmlWidth() adjustHtmlWidth(boolean adjust) sets htmlWidth to the most right margin of the HTML block content.
changePageOrientation(Dimension d) PageSize.rotate() rotates given page format by 90 degrees.
clearCache() The font cache still can be cleared with terminate(),
however a forcing to clear cache is not recommended in general.
removes all objects (images, CSS, etc) from internal caches.
disableHyperlinks() enableHyperlinks(boolean enable) if enable==false, PD4ML does not generate active hyperlinks in resulting
PDF. Default is “true”
enableDebugInfo() setLogLevel(int level) enables an output of diagnostics messages.
enableImgSplit(boolean split) By default, image splitting by page break is enabled. It can be disabled with CSS IMG {page-break-inside: avoid}, applied either in input document inline or via addStyle() allows to disable image splitting by page breaks.
enableRenderingPatch(boolean patch) Deprecated in v3; not supported in v4
enableSmartTableBreaks(boolean enable) The feature is disabled by default.
It can be controled imput document structure and style. The freature is implicitly enabled if table has a header (<thead> section or top rows consist of <th> cells only) and TR {page-break-inside: avoid} style applied.
The method switches on/off the table break feature. This feature protects
table rows from being split by page breaks (if possible) and forces the
table header to be replicated after each in-table page break.
enableTableBreaks(boolean enable) Deprecated in v3; not supported in v4
fitPageVertically() fitPageVertically(int align) forces PD4ML to downscale entire HTML layout to fit a single PDF page
vertically.
generateMulticolumn(int columns, int span, boolean millimeters) generateMulticolumn(int columns,
int span, boolean millimeters)
switches PD4ML into multicolumn mode
generateOutlines(
boolean fromHeadings)
generateBookmarksFromAnchors(
boolean enable)


generateBookmarksFromHeadings
(
boolean enable)
if triggered, than PD4ML generates PDF bookmarks (aka outlines).
generatePdfa(boolean enable) PDF/A output can be enebled in writePDF(OutputStream os,
String pdfFormat),
where pdfFormat isPDFA
Forces PD4ML to output PDF compliant with PDF/A specification.
generatePdfForms(boolean enable, String useTtfFont) generateForms(boolean enable,
String useTtfFont)
forces PD4ML to convert HTML forms into PDF forms (Acroforms).
getCache() getCache() returns cache object to be “recycled” by another PD4ML instance
getLastRenderInfo(String key) getLastRenderInfo(String key) returns statistics for the last render() call
getVersion() getVersion() getVersion() returns current version number
interpolateImages(boolean mode) Always “false” enables or disables image interpolation
isDemoMode() isDemoMode() returns true if the library is used in evaluation mode
isPro() isPro() returns true if it is Pro version of the library
merge(InputStream input, int fromPage, int toPage, boolean append) merge(PdfDocument pdf, int fromPage,
int toPage, boolean append)
Merges conversion result with an already existing PDF document
merge(Reader input, int fromPage, int toPage, boolean append) merge(PdfDocument pdf, int fromPage,
int toPage, boolean append)
Merges conversion result with an already existing PDF document
monitorProgress(
PD4ProgressListener listener)
monitorProgressWith(
ProgressListener listener)
conversion progress callback support
outputFormat(String format) Output format is controlled by
chosen write method:
writePDF(...)
or
writeRTF(...)
or
renderAsImages(...)
outputFormat(String format, int width, int height) Output format is controlled by
chosen write method:
writePDF(...)
or
writeRTF(...)
or
renderAsImages(...)
outputRange(String description) outputRange(String description)
overrideDocumentEncoding(String encoding) overrideDocumentEncoding(String encoding) sets default encoding for URL-addressed HTML documents
predictPageHeight(Insets pageInsets, Dimension pageSize, int userSpace) predictPageHeight(PageMargins pageMargins,
PageSize pageSize, int userSpace)
predicts page height for given conversion parameters
predictScale(Insets pageInsets, Dimension pageSize, int userSpace) predictScale(PageMargins pageMargins,
PageSize pageSize, int userSpace)
predicts document HTML-to-PDF mapping scale for given conversion parameters
protectPhysicalUnitDimensions() protectPhysicalUnitDimensions(boolean
keepPhysicalUnitDimensions)
makes PD4ML to output PDF objects respecting dimensions/font sizes given
in “in”, “pt”, “cm” etc.
render(InputStreamReader isr, OutputStream os) readHTML(InputStream isr)
+
writePDF(OutputStream os)
converts input data to PDF
render(InputStreamReader isr, OutputStream os, URL base) readHTML(InputStream isr, URL base)
+
writePDF(OutputStream os)
converts input data to PDF.
render(String textUrl, OutputStream os) readHTML(URL url)
+
writePDF(OutputStream os)
input data referred by URL to PDF
render(StringReader[] isrs,
OutputStream os, URL base)
Can be achieved by repeating of

readHTML(InputStream isr, URL base)
+
writePDF(OutputStream os)
and merging of the multiple resulting docs with

PdfDocument.mergePDFs(InputStream pdf1,
InputStream pdf2, OutputStream result)

converts input data to PDF
render(StringReader isr, OutputStream os) readHTML(InputStream isr)
+
writePDF(OutputStream os)
converts input data to PDF


render
(StringReader isr, OutputStream os, URL base)
readHTML(InputStream isr, URL base)
+
writePDF(OutputStream os)
converts input data to PDF
render(StringReader isr, OutputStream os, URL base,
String encoding)
readHTML(InputStream isr, URL base,
String encoding)
+
writePDF(OutputStream os)
converts input data to PDF
render(URL[] urls, OutputStream os) Can be achieved by repeating of

readHTML
(URL url)

+
writePDF(OutputStream os)
and merging of the multiple resulting docs withPdfDocument.mergePDFs(InputStream pdf1,
InputStream pdf2, OutputStream result)
converts input data referred by URLs to PDF
render(URL url, OutputStream os) readHTML(URL url)
+
writePDF(OutputStream os)
converts input data referred by URL to PDF
renderAsImages(StringReader isr,URL base, int width, int height) readHTML(InputStream isr, URL base)
+
renderAsImages()
or
renderAsImages(File dir,
String fileNamePrefix, String format)
or
renderAsImages(String format)
converts input HTML code to image object(s)
renderAsImages(URL url, int width, int height) readHTML(URL url)
+
renderAsImages()
or
renderAsImages(File dir,
String fileNamePrefix, String format)
or
renderAsImages(String format)
converts URL to image object(s)
resetAddedStyles() No need in v4 Reset all styles added with PD4ML.addStyle()
setAuthorName(String name) setAuthorName(String name) sets an author name for the document
setCache(PD4Cache cacheWrapper) setCache(Object fontCache) lets PD4ML to reuse data, cached by another PD4ML instance.
setCookie(String name, String value) setCookie(String name, String value) makes PD4ML to add a cookie with given name and value to each URL connection
request
setDefaultTTFs(String serif, String sansserif, String monospace) Can be achieved with CSS, e.g by addStyle() defines deafult TTF font faces to be used as substritutions for unknown
fonts.
setDocumentTitle(String title) setDocumentTitle(String title) forces to override HTML title
setDynamicParams(
java.util.Map dynamicParams)
Depending on param type, use one of the methods:

setDynamicData(Map<String,String> map)– dynamic data to substitute $[placeholders]

setParam(String key, String value) - Sets parsing/rendering parameters

setRenderingHints(Map hints)– replaces the values of all preferences for the image rendering algorithms with the specified hints.

setHtmlWidth(int width) setHtmlWidth(int width) defines desired HTML page width in screen pixels.
setPageFooter(PD4PageMark mark) setPageFooter(String htmlCode,
int heightPx)

setPageFooter(String htmlCode,
int heightPx, String scope)
defines page footer area
setPageHeader(PD4PageMark mark) setPageHeader(String htmlCode,
int heightPx)
setPageHeader(String htmlCode, int heightPx, String scope)
defines page header area
setPageInsets(Insets ii) setPageMargins(PageMargins margins)

setPageMargins(PageMargins margins,
String scope)

specifies page insets in points
setPageInsetsMM(Insets ii) setPageMargins(PageMargins margins)

setPageMargins(PageMargins margins,
String scope)

specifies page insets in millimeters.
setPageSize(Dimension d) setPageSize(PageSize d)

setPageSize(PageSize d, String scope)

defines page size in points.
setPageSizeMM(Dimension d) setPageSize(PageSize d)

setPageSize(PageSize d, String scope)

defines page size in milimeters.
setPermissions(String password, int permissions, boolean isStrong) setPermissions(String password,
int permissions)
forces the resulting document to be encrypted with the given password
setSessionID(String sessionID) setSessionID(String sessionID) the method informs PD4ML about current session ID (in web application
environments).
translate(int i) translateToPt(float mm) converts from millimeters to points
useAdobeFontMetrics(boolean use) Deprecated in v3; not supported in v4
useHttpRequest(
HttpServletRequest httpRequest, HttpServletResponse httpResponse)
useHttpRequest(
HttpServletRequest httpRequest, HttpServletResponse httpResponse)
method allows to inform PD4ML about actual HTTP request context (if
any).
useServletContext(ServletContext ctx) useHttpRequest(
HttpServletRequest httpRequest, HttpServletResponse httpResponse)
method allows to inform PD4ML about actual servlet context (if any).
useTTF(String pathToFontDirs, boolean embed) useTTF(String pathToFontDirs)

useTTF(String pathToFontDirs, boolean generateFontMappingFileIfMissing)

useTTF(String pathToFontDirs, String fontFileNameFilter)
+
embedTTFs(boolean embed, boolean allGlyphs)

enables TTF font embedding subsystem.

 

6.JSP taglib

Both PD4ML v3 and v4 distributions among other features also include JSP custom tag library. PD4ML JSP custom tags provide a simple mechanism for a converting of HTML or JSP page output into PDF in Web scenarios. In PD4ML v4 the taglib is an integral part of the main library. In PD4ML v3 it comes as a separate pd4ml_tl.jar.

For backward compatibility with JSP documents created for PD4ML v3, you can use pd4ml_tl.jar taken from PD4ML v3 distribution together with PD4ML v4.

But if you want to use the latest taglib, you should consider the following.

In PD4ML v4 we changed the taglib structure and removed some redundant wrapper classes. Now we recommend to use pd4tl: tag prefix instead of previous pd4ml: in order to distinguish the custom JSP tags from PD4ML proprietary tags (e.g. <pd4ml:page.break>).

<%@ taglib uri="http://pd4ml.com/tlds/4.0" 
  prefix="pd4tl"%><%@page 
  contentType="text/html; charset=ISO8859_1"%><pd4tl:transform
  screenWidth="400"
  pageFormat="A5"
  pageOrientation="landscape"
  pageInsets="100,100,100,100,points">
<html>
<head>
<title>pd4ml test</title>
<style type="text/css">
body {
	color: red;
	font-family: Tahoma, "Sans-Serif";
	font-size: 10pt;
}
</style>
</head>
<body>
	<p>
		Hello, World!
	</p>
	<pd4ml:page.break />
	<table style="border: 1px solid gray; border-radius: 5px; background-color: #f8f8f8; color: #000000">
		<tr>
			<td>Hello, New Page!</td>
		</tr>
	</table>
</body>
</html>
</pd4tl:transform>

See https://pd4ml.com/support-topics/pd4ml-v4-programmers-manual/#pd4ml-jsp-taglib-and-web-applications for more PD4ML JSP taglib usage hints.

Suggest Edit