Skip to content

Commit

Permalink
Allow re-encoding on non-String parameters (qzind#781)
Browse files Browse the repository at this point in the history
Adds optional "from" and "to" parameters for re-encoding of non-string data.

Co-authored-by: Berenz <[email protected]>
  • Loading branch information
tresf and Berenz authored Apr 1, 2021
1 parent 9865d2e commit 2aa773e
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 33 deletions.
4 changes: 3 additions & 1 deletion js/qz-tray.js
Original file line number Diff line number Diff line change
Expand Up @@ -1343,7 +1343,9 @@ var qz = (function() {
* @param {string} [options.units='in'] Page units, applies to paper size, margins, and density. Valid value <code>[in | cm | mm]</code>
*
* @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|Object} [options.encoding=null] Character set for commands. Can be provided as an object for converting encoding types for RAW types.
* @param {string} [options.encoding.from] If this encoding type is provided, RAW type commands will be parsed from this for the purpose of being converted to the <code>encoding.to</code> value.
* @param {string} [options.encoding.to] Encoding RAW type commands will be converted into. If <Code>encoding.from</code> is not provided, this will be treated as if a string was passed for encoding.
* @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.
Expand Down
24 changes: 18 additions & 6 deletions src/qz/printer/PrintOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,14 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
catch(JSONException e) { LoggerUtilities.optionWarn(log, "boolean", "altPrinting", configOpts.opt("altPrinting")); }
}
if (!configOpts.isNull("encoding")) {
rawOptions.encoding = configOpts.optString("encoding", null);
JSONObject encodings = configOpts.optJSONObject("encoding");
if(encodings != null) {
rawOptions.srcEncoding = encodings.optString("from", null);
rawOptions.destEncoding = encodings.optString("to", null);
}
else {
rawOptions.destEncoding = configOpts.optString("encoding", null);
}
}
if (!configOpts.isNull("spool")) {
JSONObject spool = configOpts.optJSONObject("spool");
Expand Down Expand Up @@ -129,8 +136,8 @@ public PrintOptions(JSONObject configOpts, PrintOutput output, PrintingUtilities
psOptions.density = asymmDPI.optInt("feed");
psOptions.crossDensity = asymmDPI.optInt("cross");
} else {
List<PrinterResolution> rSupport = output.isSetService() ?
output.getNativePrinter().getResolutions() : new ArrayList<>();
List<PrinterResolution> rSupport = output.isSetService()?
output.getNativePrinter().getResolutions():new ArrayList<>();

JSONArray possibleDPIs = configOpts.optJSONArray("density");
if (possibleDPIs != null && possibleDPIs.length() > 0) {
Expand Down Expand Up @@ -386,7 +393,8 @@ public Pixel getPixelOptions() {
/** Raw printing options */
public class Raw {
private boolean altPrinting = false; //Alternate printing for linux systems
private String encoding = null; //Text encoding / charset
private String destEncoding = null; //Text encoding / charset
private String srcEncoding = null; //Conversion text encoding
private String spoolEnd = null; //End of document character(s)
private int spoolSize = 1; //Pages per spool
private int copies = 1; //Job copies
Expand All @@ -397,8 +405,12 @@ public boolean isAltPrinting() {
return altPrinting;
}

public String getEncoding() {
return encoding;
public String getDestEncoding() {
return destEncoding;
}

public String getSrcEncoding() {
return srcEncoding;
}

public String getSpoolEnd() {
Expand Down
68 changes: 42 additions & 26 deletions src/qz/printer/action/PrintRaw.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import java.io.*;
import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
Expand All @@ -61,7 +60,7 @@ public class PrintRaw implements PrintProcessor {

private ByteArrayBuilder commands;

private String encoding = null;
private String destEncoding = null;


public PrintRaw() {
Expand All @@ -73,16 +72,16 @@ public PrintingUtilities.Format getFormat() {
return PrintingUtilities.Format.COMMAND;
}

private byte[] getBytes(String str, String encoding) throws ArabicShapingException, IOException {
switch(encoding.toLowerCase(Locale.ENGLISH)) {
private byte[] getBytes(String str, String destEncoding) throws ArabicShapingException, IOException {
switch(destEncoding.toLowerCase(Locale.ENGLISH)) {
case "ibm864":
case "cp864":
case "csibm864":
case "864":
case "ibm-864":
return ArabicConversionUtilities.convertToIBM864(str);
default:
return str.getBytes(encoding);
return str.getBytes(destEncoding);
}
}

Expand All @@ -105,38 +104,38 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
PrintOptions.Raw rawOpts = options.getRawOptions();
PrintOptions.Pixel pxlOpts = options.getPixelOptions();

encoding = rawOpts.getEncoding();
if (encoding == null || encoding.isEmpty()) { encoding = Charset.defaultCharset().name(); }
destEncoding = rawOpts.getDestEncoding();
if (destEncoding == null || destEncoding.isEmpty()) { destEncoding = Charset.defaultCharset().name(); }

try {
switch(format) {
case HTML:
commands.append(getHtmlWrapper(cmd, opt, flavor, pxlOpts).getImageCommand(opt));
commands.append(getHtmlWrapper(cmd, opt, flavor, rawOpts, pxlOpts).getImageCommand(opt));
break;
case IMAGE:
commands.append(getImageWrapper(cmd, opt, flavor, pxlOpts).getImageCommand(opt));
commands.append(getImageWrapper(cmd, opt, flavor, rawOpts, pxlOpts).getImageCommand(opt));
break;
case PDF:
commands.append(getPdfWrapper(cmd, opt, flavor, pxlOpts).getImageCommand(opt));
commands.append(getPdfWrapper(cmd, opt, flavor, rawOpts, pxlOpts).getImageCommand(opt));
break;
case COMMAND:
default:
switch(flavor) {
case BASE64:
commands.append(Base64.decodeBase64(cmd));
commands.append(seekConversion(Base64.decodeBase64(cmd), rawOpts));
break;
case FILE:
commands.append(FileUtilities.readRawFile(cmd));
commands.append(seekConversion(FileUtilities.readRawFile(cmd), rawOpts));
break;
case HEX:
commands.append(ByteUtilities.hexStringToByteArray(cmd));
commands.append(seekConversion(ByteUtilities.hexStringToByteArray(cmd), rawOpts));
break;
case XML:
commands.append(Base64.decodeBase64(FileUtilities.readXMLFile(cmd, opt.optString("xmlTag"))));
commands.append(seekConversion(Base64.decodeBase64(FileUtilities.readXMLFile(cmd, opt.optString("xmlTag"))), rawOpts));
break;
case PLAIN:
default:
commands.append(getBytes(cmd, encoding));
commands.append(getBytes(cmd, destEncoding));
break;
}
break;
Expand All @@ -148,7 +147,24 @@ public void parseData(JSONArray printData, PrintOptions options) throws JSONExce
}
}

private ImageWrapper getImageWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Pixel pxlOpts) throws IOException {
private byte[] seekConversion(byte[] rawBytes, PrintOptions.Raw rawOpts) {
if (rawOpts.getSrcEncoding() != null) {
if(rawOpts.getSrcEncoding().equals(rawOpts.getDestEncoding())) {
log.warn("Provided srcEncoding and destEncoding are the same, skipping");
} else {
try {
String rawConvert = new String(rawBytes, rawOpts.getSrcEncoding());
return rawConvert.getBytes(rawOpts.getDestEncoding());
}
catch(UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
}
return rawBytes;
}

private ImageWrapper getImageWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Raw rawOpts, PrintOptions.Pixel pxlOpts) throws IOException {
BufferedImage bi;
// 2.0 compat
if (data.startsWith("data:image/") && data.contains(";base64,")) {
Expand All @@ -158,19 +174,19 @@ private ImageWrapper getImageWrapper(String data, JSONObject opt, PrintingUtilit
}

if (flavor == PrintingUtilities.Flavor.BASE64) {
bi = ImageIO.read(new ByteArrayInputStream(Base64.decodeBase64(data)));
bi = ImageIO.read(new ByteArrayInputStream(seekConversion(Base64.decodeBase64(data), rawOpts)));
} else {
bi = ImageIO.read(ConnectionUtilities.getInputStream(data));
}

return getWrapper(bi, opt, pxlOpts);
}

private ImageWrapper getPdfWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Pixel pxlOpts) throws IOException {
private ImageWrapper getPdfWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Raw rawOpts, PrintOptions.Pixel pxlOpts) throws IOException {
PDDocument doc;

if (flavor == PrintingUtilities.Flavor.BASE64) {
doc = PDDocument.load(new ByteArrayInputStream(Base64.decodeBase64(data)));
doc = PDDocument.load(new ByteArrayInputStream(seekConversion(Base64.decodeBase64(data), rawOpts)));
} else {
doc = PDDocument.load(ConnectionUtilities.getInputStream(data));
}
Expand All @@ -189,9 +205,9 @@ private ImageWrapper getPdfWrapper(String data, JSONObject opt, PrintingUtilitie
return getWrapper(bi, opt, pxlOpts);
}

private ImageWrapper getHtmlWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Pixel pxlOpts) throws IOException {
private ImageWrapper getHtmlWrapper(String data, JSONObject opt, PrintingUtilities.Flavor flavor, PrintOptions.Raw rawOpts, PrintOptions.Pixel pxlOpts) throws IOException {
if (flavor == PrintingUtilities.Flavor.BASE64) {
data = new String(Base64.decodeBase64(data), StandardCharsets.UTF_8);
data = new String(seekConversion(Base64.decodeBase64(data), rawOpts), rawOpts.getDestEncoding());
}

double density = (pxlOpts.getDensity() * pxlOpts.getUnits().as1Inch());
Expand Down Expand Up @@ -241,14 +257,14 @@ private ImageWrapper getHtmlWrapper(String data, JSONObject opt, PrintingUtiliti

private ImageWrapper getWrapper(BufferedImage img, JSONObject opt, PrintOptions.Pixel pxlOpts) {
// Rotate image using orientation or rotation before sending to ImageWrapper
if(pxlOpts.getOrientation() != null && pxlOpts.getOrientation() != PrintOptions.Orientation.PORTRAIT) {
if (pxlOpts.getOrientation() != null && pxlOpts.getOrientation() != PrintOptions.Orientation.PORTRAIT) {
img = PrintImage.rotate(img, pxlOpts.getOrientation().getDegreesRot(), pxlOpts.getDithering(), pxlOpts.getInterpolation());
} else if(pxlOpts.getRotation() % 360 != 0) {
} else if (pxlOpts.getRotation() % 360 != 0) {
img = PrintImage.rotate(img, pxlOpts.getRotation(), pxlOpts.getDithering(), pxlOpts.getInterpolation());
}

ImageWrapper iw = new ImageWrapper(img, LanguageType.getType(opt.optString("language")));
iw.setCharset(Charset.forName(encoding));
iw.setCharset(Charset.forName(destEncoding));

//ESC/POS only
int density = opt.optInt("dotDensity", -1);
Expand Down Expand Up @@ -280,7 +296,7 @@ public void print(PrintOutput output, PrintOptions options) throws PrintExceptio
List<ByteArrayBuilder> pages;
if (rawOpts.getSpoolSize() > 0 && rawOpts.getSpoolEnd() != null && !rawOpts.getSpoolEnd().isEmpty()) {
try {
pages = ByteUtilities.splitByteArray(commands.getByteArray(), rawOpts.getSpoolEnd().getBytes(encoding), rawOpts.getSpoolSize());
pages = ByteUtilities.splitByteArray(commands.getByteArray(), rawOpts.getSpoolEnd().getBytes(destEncoding), rawOpts.getSpoolSize());
}
catch(UnsupportedEncodingException e) {
throw new PrintException(e);
Expand Down Expand Up @@ -435,7 +451,7 @@ public void printToAlternate(NativePrinter printer, byte[] cmds) throws IOExcept
@Override
public void cleanup() {
commands.clear();
encoding = null;
destEncoding = null;
}

}

0 comments on commit 2aa773e

Please sign in to comment.