Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2.1 html scaling #649

Merged
merged 6 commits into from
Jun 2, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sample.html
Original file line number Diff line number Diff line change
Expand Up @@ -2656,9 +2656,9 @@ <h4 class="panel-title">Options</h4>
if (ifClean !== undefined) {
var lbl = checkElm.siblings("label").text();
displayMessage("Forced " + lbl + " " + ifClean + ".", 'alert-warning');
}

return ifClean;
return ifClean;
}
}

return checkElm.prop("checked");
Expand Down
70 changes: 45 additions & 25 deletions src/qz/printer/action/WebApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,6 @@ public class WebApp extends Application {
base.getAttributes().setNamedItem(applied);
}

//width was resized earlier (for responsive html), then calculate the best fit height
// FIXME: Should only be needed when height is unknown but fixes blank vector prints
String heightText = webView.getEngine().executeScript("Math.max(document.body.offsetHeight, document.body.scrollHeight)").toString();
if (pageHeight <= 0) {
pageHeight = Double.parseDouble(heightText);
log.trace("Setting HTML page height to {}", pageHeight);
}

// find and set page zoom for increased quality
double usableZoom = calculateSupportedZoom(pageWidth, pageHeight);
if (usableZoom < pageZoom) {
Expand All @@ -100,9 +92,26 @@ public class WebApp extends Application {
webView.setZoom(pageZoom);
log.trace("Zooming in by x{} for increased quality", pageZoom);

webView.setMinSize(pageWidth * pageZoom, pageHeight * pageZoom);
webView.setPrefSize(pageWidth * pageZoom, pageHeight * pageZoom);
webView.setMaxSize(pageWidth * pageZoom, pageHeight * pageZoom);
//width was resized earlier (for responsive html), then calculate the best fit height
// FIXME: Should only be needed when height is unknown but fixes blank vector prints
double fittedHeight = findHeight();
boolean heightNeeded = pageHeight <= 0;

if (heightNeeded) {
pageHeight = fittedHeight;
}

adjustSize(pageWidth * pageZoom, pageHeight * pageZoom);

//need to check for height again as resizing can cause partial results
if (heightNeeded) {
fittedHeight = findHeight();
if (fittedHeight != pageHeight) {
adjustSize(pageWidth * pageZoom, fittedHeight * pageZoom);
}
}

log.trace("Set HTML page height to {}", pageHeight);

autosize(webView);

Expand Down Expand Up @@ -145,7 +154,7 @@ public static synchronized void initialize() throws IOException {
// JavaFX native libs
if (SystemUtilities.isJar()) {
SystemUtilities.appendProperty("java.library.path", new File(SystemUtilities.detectJarPath()).getParent() + "/libs/");
} else if(hasConflictingLib()) {
} else if (hasConflictingLib()) {
// IDE helper for "no suitable pipeline found" errors
System.err.println("\n=== WARNING ===\nWrong javafx platform detected. Delete lib/javafx/<platform> to correct this.\n");
}
Expand Down Expand Up @@ -227,13 +236,19 @@ public static synchronized void print(final PrinterJob job, final WebAppModel mo

load(model, (int frames) -> {
try {
double printScale = 72d / 96d;
webView.getTransforms().add(new Scale(printScale, printScale));

PageLayout layout = job.getJobSettings().getPageLayout();
if (model.isScaled()) {
double viewWidth = webView.getWidth() * printScale;
double viewHeight = webView.getHeight() * printScale;

double scale;
if ((webView.getWidth() / webView.getHeight()) >= (layout.getPrintableWidth() / layout.getPrintableHeight())) {
scale = (layout.getPrintableWidth() / webView.getWidth());
if ((viewWidth / viewHeight) >= (layout.getPrintableWidth() / layout.getPrintableHeight())) {
scale = (layout.getPrintableWidth() / viewWidth);
} else {
scale = (layout.getPrintableHeight() / webView.getHeight());
scale = (layout.getPrintableHeight() / viewHeight);
}
webView.getTransforms().add(new Scale(scale, scale));
}
Expand Down Expand Up @@ -296,11 +311,6 @@ public static synchronized BufferedImage raster(final WebAppModel model) throws
stage.toBack();
});

//adjust raster prints to web dpi
double increase = 96d / 72d;
model.setWebWidth(model.getWebWidth() * increase);
model.setWebHeight(model.getWebHeight() * increase);

raster = true;

load(model, (int frames) -> {
Expand All @@ -324,6 +334,7 @@ public void pulse() {
}
}
});
Toolkit.getToolkit().requestNextPulse();
}

return frames >= 2;
Expand Down Expand Up @@ -354,9 +365,7 @@ private static synchronized void load(WebAppModel model, IntPredicate action) {
pageHeight = model.getWebHeight();

log.trace("Setting starting size {}:{}", pageWidth, pageHeight);
webView.setMinSize(pageWidth * pageZoom, pageHeight * pageZoom);
webView.setPrefSize(pageWidth * pageZoom, pageHeight * pageZoom);
webView.setMaxSize(pageWidth * pageZoom, pageHeight * pageZoom);
adjustSize(pageWidth * pageZoom, pageHeight * pageZoom);

if (pageHeight == 0) {
webView.setMinHeight(1);
Expand All @@ -376,6 +385,17 @@ private static synchronized void load(WebAppModel model, IntPredicate action) {
});
}

private static double findHeight() {
String heightText = webView.getEngine().executeScript("Math.max(document.body.offsetHeight, document.body.scrollHeight)").toString();
return Double.parseDouble(heightText);
}

private static void adjustSize(double toWidth, double toHeight) {
webView.setMinSize(toWidth, toHeight);
webView.setPrefSize(toWidth, toHeight);
webView.setMaxSize(toWidth, toHeight);
}

/**
* Fix blank page after autosize is called
*/
Expand Down Expand Up @@ -430,9 +450,9 @@ public static boolean hasConflictingLib() {
URL url = Application.class.getResource("/" + Application.class.getName().replace('.', '/') + ".class");
String graphicsJar = url.toString().replaceAll("file:/|jar:", "").replaceAll("!.*", "");
log.trace("JavaFX will startup using {}", graphicsJar);
if(SystemUtilities.isWindows()) {
if (SystemUtilities.isWindows()) {
return !graphicsJar.contains("windows");
} else if(SystemUtilities.isMac()) {
} else if (SystemUtilities.isMac()) {
return !graphicsJar.contains("osx") && !graphicsJar.contains("mac");
}
return !graphicsJar.contains("linux");
Expand Down
28 changes: 23 additions & 5 deletions src/qz/printer/action/WebAppModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ public class WebAppModel {
private String source;
private boolean plainText;

private double webWidth;
private double webHeight;
private double width, webWidth;
private double height, webHeight;
private boolean isScaled;
private double zoom;

public WebAppModel(String source, boolean plainText, double webWidth, double webHeight, boolean isScaled, double zoom) {
public WebAppModel(String source, boolean plainText, double width, double height, boolean isScaled, double zoom) {
this.source = source;
this.plainText = plainText;
this.webWidth = webWidth;
this.webHeight = webHeight;
this.width = width;
this.height = height;
this.webWidth = width * (96d/72d);
this.webHeight = height * (96d / 72d);
this.isScaled = isScaled;
this.zoom = zoom;
}
Expand All @@ -35,6 +37,22 @@ public void setPlainText(boolean plainText) {
this.plainText = plainText;
}

public double getWidth() {
return width;
}

public void setWidth(double width) {
this.width = width;
}

public double getHeight() {
return height;
}

public void setHeight(double height) {
this.height = height;
}

public double getWebWidth() {
return webWidth;
}
Expand Down
66 changes: 40 additions & 26 deletions test/qz/printer/action/WebAppTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,39 @@
import javafx.print.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import qz.common.Constants;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

public class WebAppTest {

private static final Logger log = LoggerFactory.getLogger(WebAppTest.class);
private static final int SPOOLER_WAIT = 2000; // millis
private static final Path RASTER_OUTPUT_DIR = Paths.get("./out"); // see ant ${out.dir}
private static final String RASTER_OUTPUT_FORMAT = "png";

public static void main(String[] args) throws Throwable {
WebApp.initialize();

// RASTER//

boolean audit = false;
if (args.length > 0) { audit = Boolean.parseBoolean(args[0]) || "1".equals(args[0]); }
int knownHeightTests = 1000;
if (args.length > 1) { knownHeightTests = Integer.parseInt(args[1]); }
int fitToHeightTests = 1000;
if (args.length > 2) { fitToHeightTests = Integer.parseInt(args[2]); }
cleanup();
int rasterKnownHeightTests = 1000;
if (args.length > 0) { rasterKnownHeightTests = Integer.parseInt(args[1]); }
int rasterFittedHeightTests = 1000;
if (args.length > 1) { rasterFittedHeightTests = Integer.parseInt(args[2]); }

if (!testKnownSize(knownHeightTests, audit)) {
if (!testRasterKnownSize(rasterKnownHeightTests)) {
log.error("Testing well defined sizes failed");
} else if (!testFittedSize(fitToHeightTests, audit)) {
} else if (!testRasterFittedSize(rasterFittedHeightTests)) {
log.error("Testing fit to height sizing failed");
} else {
log.info("All raster tests passed");
Expand All @@ -58,7 +62,7 @@ public static void main(String[] args) throws Throwable {
}


public static boolean testKnownSize(int trials, boolean enableAuditing) throws Throwable {
public static boolean testRasterKnownSize(int trials) throws Throwable {
for(int i = 0; i < trials; i++) {
//new size every run
double printW = Math.max(2, (int)(Math.random() * 110) / 10d) * 72d;
Expand All @@ -78,23 +82,19 @@ public static boolean testKnownSize(int trials, boolean enableAuditing) throws T
//check capture for dimensional accuracy within 1 pixel of expected (due to int rounding)
int expectedWidth = (int)Math.round(printW * (96d / 72d) * zoom);
int expectedHeight = (int)Math.round(printH * (96d / 72d) * zoom);
boolean audit = enableAuditing && Math.random() < 0.1;
boolean passed = true;

if (!Arrays.asList(expectedWidth, expectedWidth + 1, expectedWidth - 1).contains(sample.getWidth())) {
log.error("Expected width to be {} but got {}", expectedWidth, sample.getWidth());
audit = true;
passed = false;
}
if (!Arrays.asList(expectedHeight, expectedHeight + 1, expectedHeight - 1).contains(sample.getHeight())) {
log.error("Expected height to be {} but got {}", expectedHeight, sample.getHeight());
audit = true;
passed = false;
}

if (audit) {
saveAudit(passed? id:"invalid", sample);
}
saveAudit(passed? id:"invalid", sample);

if (!passed) {
return false;
}
Expand All @@ -103,7 +103,7 @@ public static boolean testKnownSize(int trials, boolean enableAuditing) throws T
return true;
}

public static boolean testFittedSize(int trials, boolean enableAuditing) throws Throwable {
public static boolean testRasterFittedSize(int trials) throws Throwable {
for(int i = 0; i < trials; i++) {
//new size every run (height always starts at 0)
double printW = Math.max(2, (int)(Math.random() * 110) / 10d) * 72d;
Expand All @@ -122,18 +122,15 @@ public static boolean testFittedSize(int trials, boolean enableAuditing) throws
//check capture for dimensional accuracy within 1 pixel of expected (due to int rounding)
//expected height is not known for these tests
int expectedWidth = (int)Math.round(printW * (96d / 72d) * zoom);
boolean audit = enableAuditing && Math.random() < 0.1;
boolean passed = true;

if (!Arrays.asList(expectedWidth, expectedWidth + 1, expectedWidth - 1).contains(sample.getWidth())) {
log.error("Expected width to be {} but got {}", expectedWidth, sample.getWidth());
audit = true;
passed = false;
}

if (audit) {
saveAudit(passed? id:"invalid", sample);
}
saveAudit(passed? id:"invalid", sample);

if (!passed) {
return false;
}
Expand Down Expand Up @@ -201,6 +198,10 @@ private static WebAppModel buildModel(String index, double width, double height,
" <td>" + width + "x" + height + "</td>" +
" </tr>" +
" <tr>" +
" <td>Physical size:</td>" +
" <td>" + (width / 72d) + "x" + (height / 72d) + "</td>" +
" </tr>" +
" <tr>" +
" <td>Zoomed to</td>" +
" <td>x " + zoom + "</td>" +
" </tr>" +
Expand All @@ -209,7 +210,7 @@ private static WebAppModel buildModel(String index, double width, double height,
"</html>",
true, width, height, scale, zoom);

log.trace("Generating #{} = [({},{}), x{}]", index, model.getWebWidth(), model.getWebHeight(), model.getZoom());
log.trace("Generating #{} = [({},{}), x{}]", index, model.getWidth(), model.getHeight(), model.getZoom());

return model;
}
Expand All @@ -236,11 +237,24 @@ private static PrinterJob buildVectorJob(String name) throws Throwable {
return job;
}

private static void saveAudit(String id, BufferedImage capture) throws IOException {
File temp = File.createTempFile("qz-" + id, ".png");
ImageIO.write(capture, "png", temp);
private static void cleanup() {
File[] files;
if ((files = RASTER_OUTPUT_DIR.toFile().listFiles()).length > 0) {
for(File file : files) {
if (file.getName().endsWith("." + RASTER_OUTPUT_FORMAT)
&& file.getName().startsWith(String.format("%s-", Constants.DATA_DIR))) {
if(!file.delete()) {
log.warn("Could not delete {}", file);
}
}
}
}
}

log.info("Sampled {}: {}", id, temp.getName());
private static void saveAudit(String id, BufferedImage capture) throws IOException {
Path image = RASTER_OUTPUT_DIR.resolve(String.format("%s-%s.%s", Constants.DATA_DIR, id, RASTER_OUTPUT_FORMAT));
ImageIO.write(capture, RASTER_OUTPUT_FORMAT, image.toFile());
log.info("Wrote {}: {}", id, image);
}

}