Skip to content

Commit

Permalink
Asymmetric density support (#592)
Browse files Browse the repository at this point in the history
Allow asymmetric densities, named densities
Closes #570

Co-authored-by: @bberenz
  • Loading branch information
Brett Berenz authored Apr 16, 2020
1 parent b1e31e8 commit 439c7bc
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 68 deletions.
5 changes: 4 additions & 1 deletion js/qz-tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -1132,8 +1132,11 @@ var qz = (function() {
* @param {number} [options.bounds.height=0] Height of bounding box
* @param {string} [options.colorType='color'] Valid values <code>[color | grayscale | blackwhite]</code>
* @param {number} [options.copies=1] Number of copies to be printed.
* @param {number|Array<number>} [options.density=0] Pixel density (DPI, DPMM, or DPCM depending on <code>[options.units]</code>).
* @param {number|Array<number>|Object|Array<Object>|string} [options.density=0] Pixel density (DPI, DPMM, or DPCM depending on <code>[options.units]</code>).
* If provided as an array, uses the first supported density found (or the first entry if none found).
* If provided as a string, valid values are <code>[best | draft]</code>, corresponding to highest or lowest reported density respectively.
* @param {number} [options.density.cross=0] Asymmetric pixel density for the cross feed direction.
* @param {number} [options.density.feed=0] Asymmetric pixel density for the feed direction.
* @param {boolean|string} [options.duplex=false] Double sided printing, Can specify duplex style by passing a string value: <code>[one-sided | duplex | long-edge | tumble | short-edge]</code>
* @param {number} [options.fallbackDensity=null] Value used when default density value cannot be read, or in cases where reported as "Normal" by the driver, (in DPI, DPMM, or DPCM depending on <code>[options.units]</code>).
* @param {string} [options.interpolation='bicubic'] Valid values <code>[bicubic | bilinear | nearest-neighbor]</code>. Controls how images are handled when resized.
Expand Down
44 changes: 35 additions & 9 deletions sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -350,13 +350,6 @@ <h3>Pixel Printing</h3>
<input type="number" id="pxlCopies" class="form-control pull-right" />
</div>

<div class="form-group form-inline">
<label for="pxlDensity" class="tip" data-toggle="tooltip"
title="DPI, DPCM, or DPMM depending on units specified">Density
</label>
<input type="number" id="pxlDensity" class="form-control pull-right" />
</div>

<div class="form-group form-inline">
<label for="pxlDuplex"> Duplex</label>
<select id="pxlDuplex" class="form-control pull-right">
Expand Down Expand Up @@ -421,6 +414,26 @@ <h3>Pixel Printing</h3>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="pxlDensity" class="tip" data-toggle="tooltip"
title="DPI, DPCM, or DPMM depending on units specified">Density</label>
(
<label for="pxlDensityAsymm" class="inline">Asymmetric:</label>
<input type="checkbox" id="pxlDensityAsymm" onclick="checkGroupActive('pxlDensityAsymm', 'pxlDensityGroup', 'pxlDensity');">
)
<input id="pxlDensity" class="form-control" />
</div>
<div class="inline" id="pxlDensityGroup">
<div class="form-group form-inline">
<label for="pxlCrossDensity">&nbsp; Cross:</label>
<input type="number" id="pxlCrossDensity" class="form-control pull-right" />
</div>
<div class="form-group form-inline">
<label for="pxlFeedDensity">&nbsp; Feed:</label>
<input type="number" id="pxlFeedDensity" class="form-control pull-right" />
</div>
</div>

<div class="form-group">
<label>Units</label>
<div>
Expand Down Expand Up @@ -2272,7 +2285,6 @@ <h4 class="panel-title">Options</h4>
//config
$("#pxlColorType").val("color");
$("#pxlCopies").val(1);
$("#pxlDensity").val('');
$("#pxlDuplex").val("");
$("#pxlInterpolation").val("");
$("#pxlJobName").val("");
Expand All @@ -2285,6 +2297,12 @@ <h4 class="panel-title">Options</h4>
$("#pxlScale").prop('checked', true);
$("#pxlUnitsIN").prop('checked', true);

$("#pxlDensity").val('').css('display', '');
$("#pxlCrossDensity").val('');
$("#pxlFeedDensity").val('');
$("#pxlDensityAsymm").prop('checked', false);
$("#pxlDensityGroup").css('display', 'none');

$("#pxlMargins").val(0).css('display', '');
$("#pxlMarginsTop").val(0);
$("#pxlMarginsRight").val(0);
Expand Down Expand Up @@ -2772,6 +2790,14 @@ <h4 class="panel-title">Options</h4>
};
}

var pxlDensity = includedValue($("#pxlDensity"));
if (isChecked($("#pxlDensityAsymm"), cleanConditions['pxlDensityAsymm'])) {
pxlDensity = {
cross: $("#pxlCrossDensity").val(),
feed: $("#pxlFeedDensity").val()
};
}

var pxlMargins = includedValue($("#pxlMargins"));
if (isChecked($("#pxlMarginsActive"), cleanConditions['pxlMarginsActive'])) {
pxlMargins = {
Expand Down Expand Up @@ -2801,7 +2827,7 @@ <h4 class="panel-title">Options</h4>
bounds: pxlBounds,
colorType: includedValue($("#pxlColorType")),
copies: copies,
density: includedValue($("#pxlDensity")),
density: pxlDensity,
duplex: includedValue($("#pxlDuplex")),
interpolation: includedValue($("#pxlInterpolation")),
jobName: jobName,
Expand Down
123 changes: 90 additions & 33 deletions src/qz/printer/PrintOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
}

//check for pixel options
if (!configOpts.isNull("units")) {
switch(configOpts.optString("units")) {
case "mm":
psOptions.units = Unit.MM; break;
case "cm":
psOptions.units = Unit.CM; break;
case "in":
psOptions.units = Unit.INCH; break;
default:
LoggerUtilities.optionWarn(log, "valid value", "units", configOpts.opt("units")); break;
}
}
if (!configOpts.isNull("bounds")) {
try {
JSONObject bounds = configOpts.getJSONObject("bounds");
Expand All @@ -96,29 +108,80 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
}
}
if (!configOpts.isNull("density")) {
JSONArray possibleDPIs = configOpts.optJSONArray("density");
if (possibleDPIs != null && possibleDPIs.length() > 0) {
int usableDpi = -1;

List<Integer> rSupport = output.getNativePrinter().getResolutions();
if (!rSupport.isEmpty()) {
for(int i = 0; i < possibleDPIs.length(); i++) {
if (rSupport.contains(possibleDPIs.optInt(i))) {
usableDpi = possibleDPIs.optInt(i);
break;
JSONObject asymmDPI = configOpts.optJSONObject("density");
if (asymmDPI != null) {
psOptions.density = asymmDPI.optInt("feed");
psOptions.crossDensity = asymmDPI.optInt("cross");
} else {
List<PrinterResolution> rSupport = output.getNativePrinter().getResolutions();

JSONArray possibleDPIs = configOpts.optJSONArray("density");
if (possibleDPIs != null && possibleDPIs.length() > 0) {
PrinterResolution usableRes = null;

if (!rSupport.isEmpty()) {
for(int i = 0; i < possibleDPIs.length(); i++) {
PrinterResolution compareRes;
asymmDPI = possibleDPIs.optJSONObject(i);
if (asymmDPI != null) {
compareRes = new PrinterResolution(asymmDPI.optInt("cross"), asymmDPI.optInt("feed"), psOptions.units.resSyntax);
} else {
compareRes = new PrinterResolution(possibleDPIs.optInt(i), possibleDPIs.optInt(i), psOptions.units.resSyntax);
}

if (rSupport.contains(compareRes)) {
usableRes = compareRes;
break;
}
}
}
}

if (usableDpi == -1) {
log.warn("Supported printer densities not found, using first value provided");
usableDpi = possibleDPIs.optInt(0);
if (usableRes == null) {
log.warn("Supported printer densities not found, using first value provided");
asymmDPI = possibleDPIs.optJSONObject(0);
if (asymmDPI != null) {
psOptions.density = asymmDPI.optInt("feed");
psOptions.crossDensity = asymmDPI.optInt("cross");
} else {
psOptions.density = possibleDPIs.optInt(0);
}
} else {
psOptions.density = usableRes.getFeedResolution(psOptions.units.resSyntax);
psOptions.crossDensity = usableRes.getCrossFeedResolution(psOptions.units.resSyntax);
}
} else {
String relDPI = configOpts.optString("density", "").toLowerCase();
if ("best".equals(relDPI)) {
PrinterResolution bestRes = null;
for(PrinterResolution pr : rSupport) {
if (bestRes == null || !pr.lessThanOrEquals(bestRes)) {
bestRes = pr;
}
}
if(bestRes != null) {
psOptions.density = bestRes.getFeedResolution(psOptions.units.resSyntax);
psOptions.crossDensity = bestRes.getCrossFeedResolution(psOptions.units.resSyntax);
} else {
log.warn("No print densities were found; density: \"{}\" is being ignored", relDPI);
}
} else if ("draft".equals(relDPI)) {
PrinterResolution lowestRes = null;
for(PrinterResolution pr : rSupport) {
if (lowestRes == null || pr.lessThanOrEquals(lowestRes)) {
lowestRes = pr;
}
}
if(lowestRes != null) {
psOptions.density = lowestRes.getFeedResolution(psOptions.units.resSyntax);
psOptions.crossDensity = lowestRes.getCrossFeedResolution(psOptions.units.resSyntax);
} else {
log.warn("No print densities were found; density: \"{}\" is being ignored", relDPI);
}
} else {
try { psOptions.density = configOpts.getDouble("density"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "double", "density", configOpts.opt("density")); }
}
}

psOptions.density = usableDpi;
} else {
try { psOptions.density = configOpts.getDouble("density"); }
catch(JSONException e) { LoggerUtilities.optionWarn(log, "double", "density", configOpts.opt("density")); }
}
}
if (!configOpts.isNull("dithering")) {
Expand Down Expand Up @@ -243,18 +306,6 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
LoggerUtilities.optionWarn(log, "JSONObject", "size", configOpts.opt("size"));
}
}
if (!configOpts.isNull("units")) {
switch(configOpts.optString("units")) {
case "mm":
psOptions.units = Unit.MM; break;
case "cm":
psOptions.units = Unit.CM; break;
case "in":
psOptions.units = Unit.INCH; break;
default:
LoggerUtilities.optionWarn(log, "valid value", "units", configOpts.opt("units")); break;
}
}

//grab any useful service defaults
PrinterResolution defaultRes = null;
Expand All @@ -272,8 +323,9 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
defOptions.density = 60000d / psOptions.getUnits().getDPIUnits();
}
}
if ((psOptions.isRasterize() || format == PrintingUtilities.Format.IMAGE) && psOptions.getDensity() == 0) {
if ((psOptions.isRasterize() || format == PrintingUtilities.Format.IMAGE) && psOptions.getDensity() <= 1) {
psOptions.density = defOptions.density;
psOptions.crossDensity = defOptions.density;
}

if (output.isSetService()) {
Expand Down Expand Up @@ -348,7 +400,8 @@ public class Pixel {
private Bounds bounds = null; //Bounding box rectangle
private ColorType colorType = ColorType.COLOR; //Color / black&white
private int copies = 1; //Job copies
private double density = 0; //Pixel density (DPI or DPMM)
private double crossDensity = 0; //Cross feed density
private double density = 0; //Pixel density (DPI or DPMM), feed density if crossDensity is defined
private Object dithering = RenderingHints.VALUE_DITHER_DEFAULT; //Image dithering
private Sides duplex = Sides.ONE_SIDED; //Multi-siding
private Object interpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC; //Image interpolation
Expand Down Expand Up @@ -377,6 +430,10 @@ public int getCopies() {
return copies;
}

public double getCrossDensity() {
return crossDensity;
}

public double getDensity() {
return density;
}
Expand Down
14 changes: 8 additions & 6 deletions src/qz/printer/action/PrintPixel.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ protected PrintRequestAttributeSet applyDefaultSettings(PrintOptions.Pixel pxlOp


// Java prints using inches at 72dpi
final float DENSITY = (float)pxlOpts.getDensity() * pxlOpts.getUnits().as1Inch();
final float CONVERT = pxlOpts.getUnits().toInches() * 72f;

log.trace("DPI: {}\tCNV: {}", DENSITY, CONVERT);
if (DENSITY > 0) {
attributes.add(new PrinterResolution((int)DENSITY, (int)DENSITY, ResolutionSyntax.DPI));
log.trace("DPI: [{}x{}]\tCNV: {}", pxlOpts.getDensity(), pxlOpts.getCrossDensity(), CONVERT);
if (pxlOpts.getDensity() > 0) {
double cross = pxlOpts.getCrossDensity();
if (cross == 0) { cross = pxlOpts.getDensity(); }

attributes.add(new PrinterResolution((int)cross, (int)pxlOpts.getDensity(), pxlOpts.getUnits().getDPIUnits()));
}

//apply sizing and margins
Expand Down Expand Up @@ -112,9 +114,9 @@ protected void printCopies(PrintOutput output, PrintOptions.Pixel pxlOpts, Print

PrinterResolution rUsing = (PrinterResolution)attributes.get(PrinterResolution.class);
if (rUsing != null) {
List<Integer> rSupport = output.getNativePrinter().getResolutions();
List<PrinterResolution> rSupport = output.getNativePrinter().getResolutions();
if (!rSupport.isEmpty()) {
if (!rSupport.contains(rUsing.getFeedResolution(ResolutionSyntax.DPI))) {
if (!rSupport.contains(rUsing)) {
log.warn("Not using a supported DPI for printing");
log.debug("Available DPI: {}", ArrayUtils.toString(rSupport));
}
Expand Down
Loading

0 comments on commit 439c7bc

Please sign in to comment.