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; + } + +} + +