Skip to content

Commit

Permalink
Allow spool limits for pdf prints (qzind#728)
Browse files Browse the repository at this point in the history
Allow spool limits for pdf prints
Closes qzind#727 
Co-authored-by: tresf <tres.finocchiaro@gmail.com>
  • Loading branch information
tresf committed Nov 13, 2020
2 parents 3829d70 + a7dd033 commit 572191a
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 55 deletions.
28 changes: 21 additions & 7 deletions js/qz-tray.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

/**
* @version 2.1.2
* @version 2.1.2+11
* @overview QZ Tray Connector
* <p/>
* Connects a web client to the QZ Tray software.
Expand Down Expand Up @@ -38,7 +38,7 @@ var qz = (function() {
///// PRIVATE METHODS /////

var _qz = {
VERSION: "2.1.2", //must match @version above
VERSION: "2.1.2+11", //must match @version above
DEBUG: false,

log: {
Expand Down Expand Up @@ -451,8 +451,7 @@ var qz = (function() {

altPrinting: false,
encoding: null,
endOfDoc: null,
perSpool: 1
spool: null
}
},

Expand Down Expand Up @@ -767,7 +766,19 @@ var qz = (function() {
config.rasterize = true;
}
}

if(_qz.tools.versionCompare(2, 1, 2, 11) < 0) {
if(config.spool) {
if(config.spool.size) {
config.perSpool = config.spool.size;
delete config.spool.size;
}
if(config.spool.end) {
config.endOfDoc = config.spool.end;
delete config.spool.end;
}
delete config.spool;
}
}
return config;
},

Expand Down Expand Up @@ -1305,8 +1316,11 @@ var qz = (function() {
*
* @param {boolean} [options.altPrinting=false] Print the specified file using CUPS command line arguments. Has no effect on Windows.
* @param {string} [options.encoding=null] Character set
* @param {string} [options.endOfDoc=null]
* @param {number} [options.perSpool=1] Number of pages per spool.
* @param {string} [options.endOfDoc=null] DEPRECATED Raw only: Character(s) denoting end of a page to control spooling.
* @param {number} [options.perSpool=1] DEPRECATED: Raw only: Number of pages per spool.
* @param {Object} [options.spool=null] Advanced spooling options.
* @param {number} [options.spool.size=null] Number of pages per spool. Default is no limit. If <code>spool.end</code> is provided, defaults to <code>1</code>
* @param {string} [options.spool.end=null] Raw only: Character(s) denoting end of a page to control spooling.
*
* @memberof qz.configs
*/
Expand Down
20 changes: 14 additions & 6 deletions sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ <h3>Raw Printing</h3>
</div>

<div class="form-group form-inline">
<label for="rawEndOfDoc">End Of Doc</label>
<input type="text" id="rawEndOfDoc" class="form-control pull-right" />
<label for="rawSpoolEnd">End Of Doc</label>
<input type="text" id="rawSpoolEnd" class="form-control pull-right" />
</div>

<div class="form-group form-inline">
Expand Down Expand Up @@ -414,6 +414,11 @@ <h3>Pixel Printing</h3>
<label for="pxlRotation">Rotation</label>
<input type="number" step="any" id="pxlRotation" class="form-control pull-right" />
</div>

<div class="form-group form-inline">
<label for="pxlSpoolSize">Per Spool</label>
<input type="number" id="pxlSpoolSize" class="form-control pull-right" />
</div>
</div>
<div class="col-md-6">
<div class="form-group">
Expand Down Expand Up @@ -2273,9 +2278,9 @@ <h4 class="panel-title">Options</h4>
/// Resets ///
function resetRawOptions() {
//config
$("#rawPerSpool").val(1);
$("#rawSpoolSize").val(1);
$("#rawEncoding").val(null);
$("#rawEndOfDoc").val(null);
$("#rawSpoolEnd").val(null);
$("#rawAltPrinting").prop('checked', false);
$("#rawCopies").val(1);

Expand All @@ -2302,6 +2307,7 @@ <h4 class="panel-title">Options</h4>
$("#pxlPrinterTray").val(null);
$("#pxlRasterize").prop('checked', false);
$("#pxlRotation").val(0);
$("#pxlSpoolSize").val("");
$("#pxlScale").prop('checked', true);
$("#pxlUnitsIN").prop('checked', true);

Expand Down Expand Up @@ -2825,20 +2831,22 @@ <h4 class="panel-title">Options</h4>
}

var copies = 1;
var spoolSize = null;
var jobName = null;
if ($("#rawTab").hasClass("active")) {
copies = includedValue($("#rawCopies"));
spoolSize = includedValue($("#rawSpoolSize"));
jobName = includedValue($("#rawJobName"));
} else {
copies = includedValue($("#pxlCopies"));
spoolSize = includedValue($("#pxlSpoolSize"));
jobName = includedValue($("#pxlJobName"));
}

cfg.reconfigure({
altPrinting: includedValue($("#rawAltPrinting"), isChecked($("#rawAltPrinting"), cleanConditions['rawAltPrinting'])),
encoding: includedValue($("#rawEncoding")),
endOfDoc: includedValue($("#rawEndOfDoc")),
perSpool: includedValue($("#rawPerSpool")),
spool: { size: spoolSize, end: includedValue($("#rawSpoolEnd")) },

bounds: pxlBounds,
colorType: includedValue($("#pxlColorType")),
Expand Down
68 changes: 43 additions & 25 deletions src/qz/printer/BookBundle.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
package qz.printer;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qz.utils.SystemUtilities;

import javax.print.attribute.standard.OrientationRequested;
import java.awt.*;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.util.ArrayList;
import java.util.List;

/**
* Wrapper of the {@code Book} class as a {@code Printable} type,
* since PrinterJob implementations do not seem to handle the {@code Pageable} interface properly.
*/
public class BookBundle extends Book implements Printable {
public class BookBundle extends Book {

private static final Logger log = LoggerFactory.getLogger(BookBundle.class);

Expand All @@ -30,33 +24,57 @@ public BookBundle() {
super();
}

@Override
public int print(Graphics g, PageFormat format, int pageIndex) throws PrinterException {
log.trace("Requested page {} for printing", pageIndex);

if (pageIndex < getNumberOfPages()) {
Printable printable = getPrintable(pageIndex);
if (printable != lastPrint) {
lastPrint = printable;
lastStarted = pageIndex;
}

return printable.print(g, format, pageIndex - lastStarted);
}

return NO_SUCH_PAGE;
}

/**
* 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(this, getPageFormat(i));
cover.append(new PrintingPress(), getPageFormat(i));
}

return cover;
}

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

return coverSubset;
}


/** Printable wrapper to ensure proper reading of multiple documents across spooling */
private class PrintingPress implements Printable {
private int pageOffset;

public PrintingPress() {
this(0);
}

public PrintingPress(int offset) {
pageOffset = offset;
}

@Override
public int print(Graphics g, PageFormat format, int pageIndex) throws PrinterException {
pageIndex += pageOffset;
log.trace("Requested page {} for printing", pageIndex);

if (pageIndex < getNumberOfPages()) {
Printable printable = getPrintable(pageIndex);
if (printable != lastPrint) {
lastPrint = printable;
lastStarted = pageIndex;
}

return printable.print(g, format, pageIndex - lastStarted);
}

return NO_SUCH_PAGE;
}
}

}
58 changes: 46 additions & 12 deletions src/qz/printer/PrintOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,30 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
if (!configOpts.isNull("encoding")) {
rawOptions.encoding = configOpts.optString("encoding", null);
}
if (!configOpts.isNull("endOfDoc")) {
rawOptions.endOfDoc = configOpts.optString("endOfDoc", null);
}
if (!configOpts.isNull("perSpool")) {
try { rawOptions.perSpool = configOpts.getInt("perSpool"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "integer", "perSpool", configOpts.opt("perSpool")); }
if (!configOpts.isNull("spool")) {
JSONObject spool = configOpts.optJSONObject("spool");
if (spool != null) {
if (!spool.isNull("size")) {
try { rawOptions.spoolSize = spool.getInt("size"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "integer", "spool.size", spool.opt("size")); }
}
// TODO: Implement spool.start
if (!spool.isNull("end")) {
rawOptions.spoolEnd = spool.optString("end");
}

} else {
LoggerUtilities.optionWarn(log, "JSONObject", "spool", configOpts.opt("spool"));
}
} else {
// Deprecated
if (!configOpts.isNull("perSpool")) {
try { rawOptions.spoolSize = configOpts.getInt("perSpool"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "integer", "perSpool", configOpts.opt("perSpool")); }
}
if (!configOpts.isNull("endOfDoc")) {
rawOptions.spoolEnd = configOpts.optString("endOfDoc", null);
}
}
if (!configOpts.isNull("copies")) {
try { rawOptions.copies = configOpts.getInt("copies"); }
Expand Down Expand Up @@ -272,6 +290,17 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
try { psOptions.paperThickness = configOpts.getDouble("paperThickness"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "double", "paperThickness", configOpts.opt("paperThickness")); }
}
if (!configOpts.isNull("spool")) {
JSONObject spool = configOpts.optJSONObject("spool");
if (spool != null) {
if (!spool.isNull("size")) {
try { psOptions.spoolSize = spool.getInt("size"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "integer", "spool.size", spool.opt("size")); }
}
} else {
LoggerUtilities.optionWarn(log, "JSONObject", "spool", configOpts.opt("spool"));
}
}
if (!configOpts.isNull("printerTray")) {
psOptions.printerTray = configOpts.optString("printerTray", null);
}
Expand Down Expand Up @@ -358,8 +387,8 @@ public Pixel getPixelOptions() {
public class Raw {
private boolean altPrinting = false; //Alternate printing for linux systems
private String encoding = null; //Text encoding / charset
private String endOfDoc = null; //End of document character
private int perSpool = 1; //Pages per spool
private String spoolEnd = null; //End of document character(s)
private int spoolSize = 1; //Pages per spool
private int copies = 1; //Job copies
private String jobName = null; //Job name

Expand All @@ -372,12 +401,12 @@ public String getEncoding() {
return encoding;
}

public String getEndOfDoc() {
return endOfDoc;
public String getSpoolEnd() {
return spoolEnd;
}

public int getPerSpool() {
return perSpool;
public int getSpoolSize() {
return spoolSize;
}

public int getCopies() {
Expand All @@ -404,6 +433,7 @@ public class Pixel {
private Margins margins = new Margins(); //Page margins
private Orientation orientation = null; //Page orientation
private double paperThickness = -1; //Paper thickness
private int spoolSize = 0; //Pages before sending to printer
private String printerTray = null; //Printer tray to use
private boolean rasterize = true; //Whether documents are rasterized before printing
private double rotation = 0; //Image rotation
Expand Down Expand Up @@ -464,6 +494,10 @@ public double getPaperThickness() {
return paperThickness;
}

public int getSpoolSize() {
return spoolSize;
}

public String getPrinterTray() {
return printerTray;
}
Expand Down
19 changes: 16 additions & 3 deletions src/qz/printer/action/PrintPDF.java
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,23 @@ public void print(PrintOutput output, PrintOptions options) throws PrinterExcept
bundle.append(new PDFWrapper(doc, scale, false, (float)(useDensity * pxlOpts.getUnits().as1Inch()), false, pxlOpts.getOrientation(), hints), page, doc.getNumberOfPages());
}

job.setJobName(pxlOpts.getJobName(Constants.PDF_PRINT));
job.setPageable(bundle.wrapAndPresent());
if (pxlOpts.getSpoolSize() > 0 && bundle.getNumberOfPages() > pxlOpts.getSpoolSize()) {
int jobNum = 1;
int offset = 0;
while(offset < bundle.getNumberOfPages()) {
job.setJobName(pxlOpts.getJobName(Constants.PDF_PRINT) + "-" + jobNum++);
job.setPageable(bundle.wrapAndPresent(offset, pxlOpts.getSpoolSize()));

printCopies(output, pxlOpts, job, attributes);
printCopies(output, pxlOpts, job, attributes);

offset += pxlOpts.getSpoolSize();
}
} else {
job.setJobName(pxlOpts.getJobName(Constants.PDF_PRINT));
job.setPageable(bundle.wrapAndPresent());

printCopies(output, pxlOpts, job, attributes);
}
}

private void rotatePage(PDDocument doc, PDPage page, double rotation) {
Expand Down
4 changes: 2 additions & 2 deletions src/qz/printer/action/PrintRaw.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,9 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
PrintOptions.Raw rawOpts = options.getRawOptions();

List<ByteArrayBuilder> pages;
if (rawOpts.getPerSpool() > 0 && rawOpts.getEndOfDoc() != null && !rawOpts.getEndOfDoc().isEmpty()) {
if (rawOpts.getSpoolSize() > 0 && rawOpts.getSpoolEnd() != null && !rawOpts.getSpoolEnd().isEmpty()) {
try {
pages = ByteUtilities.splitByteArray(commands.getByteArray(), rawOpts.getEndOfDoc().getBytes(encoding), rawOpts.getPerSpool());
pages = ByteUtilities.splitByteArray(commands.getByteArray(), rawOpts.getSpoolEnd().getBytes(encoding), rawOpts.getSpoolSize());
}
catch(UnsupportedEncodingException e) {
throw new PrintException(e);
Expand Down

0 comments on commit 572191a

Please sign in to comment.