diff --git a/js/qz-tray.js b/js/qz-tray.js
index 3dcfb884d..e25847988 100644
--- a/js/qz-tray.js
+++ b/js/qz-tray.js
@@ -467,6 +467,7 @@ var qz = (function() {
rotation: 0,
scaleContent: true,
size: null,
+ stream: false,
units: 'in',
forceRaw: false,
@@ -1533,6 +1534,7 @@ var qz = (function() {
* @param {Object} [options.spool=null] Advanced spooling options.
* @param {number} [options.spool.size=null] Number of pages per spool. Default is no limit. If spool.end
is provided, defaults to 1
* @param {string} [options.spool.end=null] Raw only: Character(s) denoting end of a page to control spooling.
+ * @param {boolean} [options.stream=false] Currently PDF only. If documents should be loaded on demand.
*
* @memberof qz.configs
*/
diff --git a/src/qz/printer/PrintOptions.java b/src/qz/printer/PrintOptions.java
index 1a34bfed6..da19d5575 100644
--- a/src/qz/printer/PrintOptions.java
+++ b/src/qz/printer/PrintOptions.java
@@ -353,6 +353,10 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
LoggerUtilities.optionWarn(log, "JSONObject", "size", configOpts.opt("size"));
}
}
+ if (!configOpts.isNull("stream")) {
+ try { psOptions.stream = configOpts.getBoolean("stream"); }
+ catch(JSONException e) { LoggerUtilities.optionWarn(log, "boolean", "stream", configOpts.opt("stream")); }
+ }
//grab any useful service defaults
PrinterResolution defaultRes = null;
@@ -477,6 +481,7 @@ public class Pixel {
private double rotation = 0; //Image rotation
private boolean scaleContent = true; //Adjust paper size for best image fit
private Size size = null; //Paper size
+ private boolean stream = false; //Lazy loading documents
private Unit units = Unit.INCH; //Units for density, margins, size
@@ -556,6 +561,10 @@ public Size getSize() {
return size;
}
+ public boolean isStream() {
+ return stream;
+ }
+
public Unit getUnits() {
return units;
}
diff --git a/src/qz/printer/action/PrintPDF.java b/src/qz/printer/action/PrintPDF.java
index fd288ddf9..af5ee2480 100644
--- a/src/qz/printer/action/PrintPDF.java
+++ b/src/qz/printer/action/PrintPDF.java
@@ -20,7 +20,9 @@
import qz.printer.PrintOptions;
import qz.printer.PrintOutput;
import qz.printer.action.pdf.BookBundle;
+import qz.printer.action.pdf.FuturePdf;
import qz.printer.action.pdf.PDFWrapper;
+import qz.printer.action.pdf.PdfParams;
import qz.utils.ConnectionUtilities;
import qz.utils.PrintingUtilities;
import qz.utils.SystemUtilities;
@@ -36,23 +38,17 @@
import java.awt.print.PrinterJob;
import java.io.*;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
public class PrintPDF extends PrintPixel implements PrintProcessor {
private static final Logger log = LogManager.getLogger(PrintPDF.class);
- private List originals;
- private List printables;
- private Splitter splitter = new Splitter();
+ private final List originals;
+ private final List printables;
+ private final Splitter splitter = new Splitter();
- private double docWidth = 0;
- private double docHeight = 0;
- private boolean ignoreTransparency = false;
- private boolean altFontRendering = false;
+ private PdfParams pdfParams;
public PrintPDF() {
@@ -68,54 +64,24 @@ public PrintingUtilities.Format getFormat() {
@Override
public void parseData(JSONArray printData, PrintOptions options) throws JSONException, UnsupportedOperationException {
PrintOptions.Pixel pxlOpts = options.getPixelOptions();
- double convert = 72.0 / pxlOpts.getUnits().as1Inch();
+ RenderingHints renderingHints = new RenderingHints(buildRenderingHints(pxlOpts.getDithering(), pxlOpts.getInterpolation()));
for(int i = 0; i < printData.length(); i++) {
JSONObject data = printData.getJSONObject(i);
- HashSet pagesToPrint = new HashSet<>();
- if (!data.isNull("options")) {
- JSONObject dataOpt = data.getJSONObject("options");
-
- if (!dataOpt.isNull("pageWidth") && dataOpt.optDouble("pageWidth") > 0) {
- docWidth = dataOpt.optDouble("pageWidth") * convert;
- }
- if (!dataOpt.isNull("pageHeight") && dataOpt.optDouble("pageHeight") > 0) {
- docHeight = dataOpt.optDouble("pageHeight") * convert;
- }
-
- ignoreTransparency = dataOpt.optBoolean("ignoreTransparency", false);
- altFontRendering = dataOpt.optBoolean("altFontRendering", false);
-
- if (!dataOpt.isNull("pageRanges")) {
- String[] ranges = dataOpt.optString("pageRanges", "").split(",");
- for(String range : ranges) {
- range = range.trim();
- if(range.isEmpty()) {
- continue;
- }
- String[] period = range.split("-");
-
- try {
- int start = Integer.parseInt(period[0]);
- pagesToPrint.add(start);
-
- if (period.length > 1) {
- int end = Integer.parseInt(period[period.length - 1]);
- pagesToPrint.addAll(IntStream.rangeClosed(start, end).boxed().collect(Collectors.toSet()));
- }
- }
- catch(NumberFormatException nfe) {
- log.warn("Unable to parse page range {}.", range);
- }
- }
- }
- }
+ pdfParams = new PdfParams(data.optJSONObject("options"), options, renderingHints);
PrintingUtilities.Flavor flavor = PrintingUtilities.Flavor.parse(data, PrintingUtilities.Flavor.FILE);
try {
PDDocument doc;
+
+ if (options.getPixelOptions().isStream()) {
+ doc = new FuturePdf(data.getString("data"));
+ printables.add(doc);
+ continue; //no further doc processing, as it doesn't exist yet
+ }
+
switch(flavor) {
case PLAIN:
// There's really no such thing as a 'PLAIN' PDF, assume it's a URL
@@ -135,29 +101,19 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
}
if (pxlOpts.getBounds() != null) {
- PrintOptions.Bounds bnd = pxlOpts.getBounds();
-
for(PDPage page : doc.getPages()) {
- PDRectangle box = new PDRectangle(
- (float)(bnd.getX() * convert),
- page.getMediaBox().getUpperRightY() - (float)((bnd.getHeight() + bnd.getY()) * convert),
- (float)(bnd.getWidth() * convert),
- (float)(bnd.getHeight() * convert));
- page.setMediaBox(box);
+ page.setMediaBox(pdfParams.calculateMediaBox(page));
}
}
- if (pagesToPrint.isEmpty()) {
- pagesToPrint.addAll(IntStream.rangeClosed(1, doc.getNumberOfPages()).boxed().collect(Collectors.toSet()));
- }
-
+ pdfParams.setPageRange(doc);
originals.add(doc);
List splitPages = splitter.split(doc);
originals.addAll(splitPages); //ensures non-ranged page will still get closed
for(int pg = 0; pg < splitPages.size(); pg++) {
- if (pagesToPrint.contains(pg + 1)) { //ranges are 1-indexed
+ if (pdfParams.getPageRange().contains(pg + 1)) { //ranges are 1-indexed
printables.add(splitPages.get(pg));
}
}
@@ -194,7 +150,6 @@ public void print(PrintOutput output, PrintOptions options) throws PrinterExcept
job.setPrintService(output.getPrintService());
PrintOptions.Pixel pxlOpts = options.getPixelOptions();
- Scaling scale = (pxlOpts.isScaleContent()? Scaling.SCALE_TO_FIT:Scaling.ACTUAL_SIZE);
PrintRequestAttributeSet attributes = applyDefaultSettings(pxlOpts, job.getPageFormat(null), (Media[])output.getPrintService().getSupportedAttributeValues(Media.class, null, null));
@@ -204,36 +159,33 @@ public void print(PrintOutput output, PrintOptions options) throws PrinterExcept
attributes.clear();
}
- RenderingHints hints = new RenderingHints(buildRenderingHints(pxlOpts.getDithering(), pxlOpts.getInterpolation()));
- double useDensity = pxlOpts.getDensity();
-
- if (!pxlOpts.isRasterize()) {
- if (pxlOpts.getDensity() > 0) {
- // clear density for vector prints (applied via print attributes instead)
- useDensity = 0;
- } else if (SystemUtilities.isMac() && Constants.JAVA_VERSION.compareWithBuildsTo(Version.valueOf("1.8.0+121")) < 0) {
- log.warn("OSX systems cannot print vector PDF's, forcing raster to prevent crash.");
- useDensity = options.getDefaultOptions().getDensity();
- }
- }
-
BookBundle bundle = new BookBundle();
for(PDDocument doc : printables) {
PageFormat page = job.getPageFormat(null);
applyDefaultSettings(pxlOpts, page, output.getSupportedMedia());
- //trick pdfbox into an alternate doc size if specified
- if (docWidth > 0 || docHeight > 0) {
- Paper paper = page.getPaper();
+ if (doc instanceof FuturePdf) {
+ FuturePdf future = (FuturePdf)doc;
+ future.buildFutureWrapper(pdfParams);
- if (docWidth <= 0) { docWidth = page.getImageableWidth(); }
- if (docHeight <= 0) { docHeight = page.getImageableHeight(); }
+ bundle.flagForStreaming(true);
+ //fixme - book bundle short-circuits based on total pages, how to bypass ?
+ bundle.append(future.getFutureWrapper(), page, 5);
- paper.setImageableArea(paper.getImageableX(), paper.getImageableY(), docWidth, docHeight);
+ continue; //no further doc processing, as it doesn't exist yet
+ }
+
+ //trick pdfbox into an alternate doc size if specified
+ if (pdfParams.isCustomSize()) {
+ Paper paper = page.getPaper();
+ paper.setImageableArea(paper.getImageableX(),
+ paper.getImageableY(),
+ pdfParams.getDocWidth(page.getImageableWidth()),
+ pdfParams.getDocHeight(page.getImageableHeight()));
page.setPaper(paper);
- scale = Scaling.SCALE_TO_FIT; //to get custom size we need to force scaling
+ pdfParams.setScaling(Scaling.SCALE_TO_FIT); //to get custom size we need to force scaling
//pdf uses imageable area from Paper, so this can be safely removed
attributes.remove(MediaPrintableArea.class);
@@ -263,10 +215,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrinterExcept
}
}
- PDFWrapper wrapper = new PDFWrapper(doc, scale, false, ignoreTransparency, altFontRendering,
- (float)(useDensity * pxlOpts.getUnits().as1Inch()),
- false, pxlOpts.getOrientation(), hints);
-
+ PDFWrapper wrapper = new PDFWrapper(doc, pdfParams);
bundle.append(wrapper, page, doc.getNumberOfPages());
}
@@ -327,10 +276,5 @@ public void cleanup() {
originals.clear();
printables.clear();
-
- docWidth = 0;
- docHeight = 0;
- ignoreTransparency = false;
- altFontRendering = false;
}
}
diff --git a/src/qz/printer/action/pdf/BookBundle.java b/src/qz/printer/action/pdf/BookBundle.java
index 38fb38267..2a3339ea6 100644
--- a/src/qz/printer/action/pdf/BookBundle.java
+++ b/src/qz/printer/action/pdf/BookBundle.java
@@ -17,6 +17,9 @@ public class BookBundle extends Book {
private static final Logger log = LogManager.getLogger(BookBundle.class);
+ private boolean streaming = false;
+ private int streamAt = 0;
+
private Printable lastPrint;
private int lastStarted;
@@ -24,13 +27,17 @@ public BookBundle() {
super();
}
+ public void flagForStreaming(boolean streaming) {
+ this.streaming = streaming;
+ }
+
/**
* Wrapper of the wrapper class so that PrinterJob implementations will handle it as proper pageable
*/
public Book wrapAndPresent() {
Book cover = new Book();
for(int i = 0; i < getNumberOfPages(); i++) {
- cover.append(new PrintingPress(), getPageFormat(i));
+ cover.append(new PrintingPress(streaming), getPageFormat(i));
}
return cover;
@@ -39,23 +46,25 @@ public Book wrapAndPresent() {
public Book wrapAndPresent(int offset, int length) {
Book coverSubset = new Book();
for(int i = offset; i < offset + length && i < getNumberOfPages(); i++) {
- coverSubset.append(new PrintingPress(offset), getPageFormat(i));
+ coverSubset.append(new PrintingPress(offset, streaming), getPageFormat(i));
}
return coverSubset;
}
-
/** Printable wrapper to ensure proper reading of multiple documents across spooling */
private class PrintingPress implements Printable {
+
+ private boolean isStream;
private int pageOffset;
- public PrintingPress() {
- this(0);
+ public PrintingPress(boolean stream) {
+ this(0, stream);
}
- public PrintingPress(int offset) {
+ public PrintingPress(int offset, boolean stream) {
pageOffset = offset;
+ isStream = stream;
}
@Override
@@ -63,7 +72,27 @@ public int print(Graphics g, PageFormat format, int pageIndex) throws PrinterExc
pageIndex += pageOffset;
log.trace("Requested page {} for printing", pageIndex);
- if (pageIndex < getNumberOfPages()) {
+ if (isStream) {
+ Printable printable = getPrintable(streamAt);
+ if (printable != lastPrint) {
+ lastPrint = printable;
+ lastStarted = pageIndex;
+ }
+
+ //fixme - this setup results in too many blank pages after a no_such_page
+ int result = printable.print(g, format, pageIndex - lastStarted);
+ if (result == NO_SUCH_PAGE) {
+ // finished the last page of this document, move to the next
+ streamAt++;
+ ((FuturePdf.FutureWrapper)printable).sendToPast();
+ }
+ if (streamAt < getNumberOfPages()) {
+ // always return "exists" if there are more documents to print
+ return PAGE_EXISTS;
+ }
+
+ return result;
+ } else if (pageIndex < getNumberOfPages()) {
Printable printable = getPrintable(pageIndex);
if (printable != lastPrint) {
lastPrint = printable;
diff --git a/src/qz/printer/action/pdf/FuturePdf.java b/src/qz/printer/action/pdf/FuturePdf.java
new file mode 100644
index 000000000..9f7f5d0c4
--- /dev/null
+++ b/src/qz/printer/action/pdf/FuturePdf.java
@@ -0,0 +1,86 @@
+package qz.printer.action.pdf;
+
+import org.apache.pdfbox.Loader;
+import org.apache.pdfbox.io.RandomAccessReadBuffer;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.printing.Scaling;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import qz.printer.PrintOptions;
+import qz.utils.ConnectionUtilities;
+
+import java.awt.*;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.io.IOException;
+
+public class FuturePdf extends PDDocument {
+
+ private String futureDocument;
+ private FutureWrapper futureWrapper;
+
+ public FuturePdf(String futureDoc) {
+ super();
+
+ this.futureDocument = futureDoc;
+ }
+
+ public void buildFutureWrapper(PdfParams pdfParams) {
+ futureWrapper = new FutureWrapper(this.futureDocument, pdfParams);
+ }
+
+ public FutureWrapper getFutureWrapper() {
+ return futureWrapper;
+ }
+
+
+ static class FutureWrapper implements Printable {
+
+ private static final Logger log = LoggerFactory.getLogger(FutureWrapper.class);
+
+ private String futureDocument;
+ private PdfParams pdfParams;
+ private PDDocument presentDocument;
+ private PDFWrapper realWrapper;
+
+
+ FutureWrapper(String futureDoc, PdfParams pdfParams) {
+ this.futureDocument = futureDoc;
+ this.pdfParams = pdfParams;
+ }
+
+ public void bringToPresent() throws IOException {
+ if (presentDocument == null) {
+ log.trace("Loading document for use");
+ //TODO - include various processing handled for non streamed documents ??
+ presentDocument = Loader.loadPDF(new RandomAccessReadBuffer(ConnectionUtilities.protocolRestricted(this.futureDocument).openStream()));
+ realWrapper = new PDFWrapper(presentDocument, pdfParams);
+ }
+ }
+
+ public void sendToPast() {
+ try {
+ log.trace("Unloading document after completion");
+ presentDocument.close();
+ }
+ catch(IOException ioe) {
+ log.error("Unable to unload streamed pdf document", ioe);
+ }
+ }
+
+ @Override
+ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
+ try {
+ bringToPresent();
+ return realWrapper.print(graphics, pageFormat, pageIndex);
+ }
+ catch(IOException ioe) {
+ //todo - how to handle??
+ throw new PrinterException(ioe.getMessage());
+ }
+ }
+
+ }
+
+}
diff --git a/src/qz/printer/action/pdf/PDFWrapper.java b/src/qz/printer/action/pdf/PDFWrapper.java
index 42297a145..4df57650e 100644
--- a/src/qz/printer/action/pdf/PDFWrapper.java
+++ b/src/qz/printer/action/pdf/PDFWrapper.java
@@ -7,7 +7,6 @@
import org.apache.pdfbox.printing.PDFPrintable;
import org.apache.pdfbox.printing.Scaling;
import org.apache.pdfbox.rendering.PDFRenderer;
-import qz.printer.PrintOptions;
import qz.utils.SystemUtilities;
import javax.print.attribute.standard.OrientationRequested;
@@ -19,23 +18,18 @@
public class PDFWrapper implements Printable {
private static final Logger log = LogManager.getLogger(PDFWrapper.class);
-
private PDDocument document;
- private Scaling scaling;
- private OrientationRequested orientation = OrientationRequested.PORTRAIT;
+ private PdfParams pdfParams;
private PDFPrintable printable;
- public PDFWrapper(PDDocument document, Scaling scaling, boolean showPageBorder, boolean ignoreTransparency, boolean useAlternateFontRendering, float dpi, boolean center, PrintOptions.Orientation orientation, RenderingHints hints) {
+ public PDFWrapper(PDDocument document, PdfParams pdfParams) {
this.document = document;
- this.scaling = scaling;
- if (orientation != null) {
- this.orientation = orientation.getAsOrientRequested();
- }
+ this.pdfParams = pdfParams;
- PDFRenderer renderer = new ParamPdfRenderer(document, useAlternateFontRendering, ignoreTransparency);
- printable = new PDFPrintable(document, scaling, showPageBorder, dpi, center, renderer);
- printable.setRenderingHints(hints);
+ PDFRenderer renderer = new ParamPdfRenderer(document, pdfParams);
+ printable = new PDFPrintable(document, pdfParams.getScaling(), pdfParams.isShowPageBorder(), pdfParams.getDpi(), pdfParams.isCenter(), renderer);
+ printable.setRenderingHints(pdfParams.getRenderingHints());
}
@@ -47,7 +41,7 @@ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws
graphics.drawString(" ", 0, 0);
//reverse fix for OSX
- if (SystemUtilities.isMac() && orientation == OrientationRequested.REVERSE_LANDSCAPE) {
+ if (SystemUtilities.isMac() && pdfParams.isOrientationRequested(OrientationRequested.REVERSE_LANDSCAPE)) {
adjustPrintForOrientation(graphics, pageFormat, pageIndex);
}
@@ -68,7 +62,7 @@ private void adjustPrintForOrientation(Graphics g, PageFormat format, int page)
//adjust across page to account for wrong origin corner
double leftAdjust, topAdjust;
- if (scaling != Scaling.ACTUAL_SIZE) {
+ if (pdfParams.getScaling() != Scaling.ACTUAL_SIZE) {
if ((docWidth / docHeight) >= (format.getImageableWidth() / format.getImageableHeight())) {
leftAdjust = 0;
topAdjust = format.getImageableHeight() - (docHeight / (docWidth / format.getImageableWidth()));
diff --git a/src/qz/printer/action/pdf/ParamPdfRenderer.java b/src/qz/printer/action/pdf/ParamPdfRenderer.java
index d9d03c0ce..8eeb119e3 100644
--- a/src/qz/printer/action/pdf/ParamPdfRenderer.java
+++ b/src/qz/printer/action/pdf/ParamPdfRenderer.java
@@ -12,21 +12,18 @@
public class ParamPdfRenderer extends PDFRenderer {
- private boolean useAlternateFontRendering;
- private boolean ignoreTransparency;
+ private PdfParams pdfParams;
- public ParamPdfRenderer(PDDocument document, boolean useAlternateFontRendering, boolean ignoreTransparency) {
+ public ParamPdfRenderer(PDDocument document, PdfParams pdfParams) {
super(document);
-
- this.useAlternateFontRendering = useAlternateFontRendering;
- this.ignoreTransparency = ignoreTransparency;
+ this.pdfParams = pdfParams;
}
@Override
protected PageDrawer createPageDrawer(PageDrawerParameters parameters) throws IOException {
- if (useAlternateFontRendering) {
- return new PdfFontPageDrawer(parameters, ignoreTransparency);
- } else if(ignoreTransparency) {
+ if (pdfParams.isAltFontRendering()) {
+ return new PdfFontPageDrawer(parameters, pdfParams.isIgnoreTransparency());
+ } else if(pdfParams.isIgnoreTransparency()) {
return new OpaquePageDrawer(parameters);
}
// Fallback to default PageDrawer
diff --git a/src/qz/printer/action/pdf/PdfParams.java b/src/qz/printer/action/pdf/PdfParams.java
new file mode 100644
index 000000000..4b48cd214
--- /dev/null
+++ b/src/qz/printer/action/pdf/PdfParams.java
@@ -0,0 +1,179 @@
+package qz.printer.action.pdf;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.pdfbox.pdmodel.PDDocument;
+import org.apache.pdfbox.pdmodel.PDPage;
+import org.apache.pdfbox.pdmodel.common.PDRectangle;
+import org.apache.pdfbox.printing.Scaling;
+import org.codehaus.jettison.json.JSONObject;
+import qz.printer.PrintOptions;
+
+import javax.print.attribute.standard.OrientationRequested;
+import java.awt.*;
+import java.util.HashSet;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class PdfParams {
+ private static final Logger log = LogManager.getLogger(PdfParams.class);
+ private PrintOptions options;
+ private boolean showPageBorder;
+ private boolean center;
+ private double convert;
+ private Scaling scaling;
+ private RenderingHints renderingHints;
+ private double docWidth;
+ private double docHeight;
+ private boolean ignoreTransparency;
+ private boolean altFontRendering;
+ HashSet pageRange;
+ private float dpi;
+
+
+ public PdfParams(JSONObject params, PrintOptions options, RenderingHints renderingHints) {
+ this.options = options;
+ showPageBorder = false;
+ center = false;
+ this.renderingHints = renderingHints;
+ convert = 72.0 / options.getPixelOptions().getUnits().as1Inch();
+ scaling = options.getPixelOptions().isScaleContent() ? Scaling.SCALE_TO_FIT:Scaling.ACTUAL_SIZE;
+
+ if(params != null) {
+ docWidth = params.optDouble("pageWidth", 0) * convert;
+ docHeight = params.optDouble("pageHeight", 0) * convert;
+ ignoreTransparency = params.optBoolean("ignoreTransparency", false);
+ altFontRendering = params.optBoolean("altFontRendering", false);
+ pageRange = parsePageRange(params);
+ dpi = calculateDpi(options);
+ } else {
+ docWidth = 0;
+ docHeight = 0;
+ ignoreTransparency = false;
+ altFontRendering = false;
+ pageRange = new HashSet<>();
+ dpi = 0;
+ }
+ }
+
+ /**
+ * Calculates the DPI based on PDF-specific factors
+ * - Vector prints will use a value of 0
+ * - Rasterized prints will use the value specified, converted to inches
+ */
+ private static float calculateDpi(PrintOptions options) {
+ PrintOptions.Pixel pxlOpts = options.getPixelOptions();
+ if (!pxlOpts.isRasterize()) {
+ // clear density for vector prints (applied via print attributes instead)
+ return 0;
+ }
+ return (float)(pxlOpts.getDensity() * pxlOpts.getUnits().as1Inch());
+ }
+
+ private static HashSet parsePageRange(JSONObject params) {
+ HashSet pageRange = new HashSet<>();
+ String[] ranges = params.optString("pageRanges", "").split(",");
+ for(String range : ranges) {
+ range = range.trim();
+ if(range.isEmpty()) {
+ continue;
+ }
+ String[] period = range.split("-");
+
+ try {
+ int start = Integer.parseInt(period[0]);
+ pageRange.add(start);
+
+ if (period.length > 1) {
+ int end = Integer.parseInt(period[period.length - 1]);
+ pageRange.addAll(IntStream.rangeClosed(start, end).boxed().collect(Collectors.toSet()));
+ }
+ }
+ catch(NumberFormatException nfe) {
+ log.warn("Unable to parse page range {}.", range);
+ }
+ }
+ return pageRange;
+ }
+
+ /**
+ * Sets the fallback page range based on the number of pages in the document
+ */
+ public void setPageRange(PDDocument doc) {
+ if(pageRange.isEmpty()) {
+ pageRange.addAll(IntStream.rangeClosed(1, doc.getNumberOfPages()).boxed().collect(Collectors.toSet()));
+ }
+ }
+
+ public PDRectangle calculateMediaBox(PDPage page) {
+ PrintOptions.Bounds bnd = options.getPixelOptions().getBounds();
+ return new PDRectangle(
+ (float)(bnd.getX() * convert),
+ page.getMediaBox().getUpperRightY() - (float)((bnd.getHeight() + bnd.getY()) * convert),
+ (float)(bnd.getWidth() * convert),
+ (float)(bnd.getHeight() * convert));
+ }
+
+ public double getDocWidth(double defaultVal) {
+ return docWidth > 0 ? docWidth : defaultVal;
+ }
+
+ public double getDocHeight(double defaultVal) {
+ return docHeight > 0 ? docHeight : defaultVal;
+ }
+
+ public boolean isShowPageBorder() {
+ return showPageBorder;
+ }
+
+ public boolean isCenter() {
+ return center;
+ }
+
+ public boolean isIgnoreTransparency() {
+ return ignoreTransparency;
+ }
+
+ public boolean isAltFontRendering() {
+ return altFontRendering;
+ }
+
+ public double getConvert() {
+ return convert;
+ }
+
+ public boolean isCustomSize() {
+ return docWidth >= 0 || docHeight >= 0;
+ }
+
+ public HashSet getPageRange() {
+ return pageRange;
+ }
+
+ public float getDpi() {
+ return dpi;
+ }
+
+ public void setScaling(Scaling scaling) {
+ this.scaling = scaling;
+ }
+
+ public Scaling getScaling() {
+ return scaling;
+ }
+
+ public RenderingHints getRenderingHints() {
+ return renderingHints;
+ }
+
+ public PrintOptions.Orientation getOrientation() {
+ return options.getPixelOptions().getOrientation();
+ }
+
+ public boolean isOrientationRequested(OrientationRequested match) {
+ return getOrientation() == null ? false : getOrientation().getAsOrientRequested() == match;
+ }
+
+}
+
+