Merge pull request #14545 from brendandahl/output-scale

Generate test images at different output scales.
This commit is contained in:
Jonas Jenwald 2022-02-24 21:56:54 +01:00 committed by GitHub
commit 889b761f22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 101 additions and 34 deletions

View File

@ -61,7 +61,7 @@ function loadStyles(styles) {
return Promise.all(promises);
}
function writeSVG(svgElement, ctx) {
function writeSVG(svgElement, ctx, outputScale) {
// We need to have UTF-8 encoded XML.
const svg_xml = unescape(
encodeURIComponent(new XMLSerializer().serializeToString(svgElement))
@ -104,7 +104,7 @@ function inlineImages(images) {
return Promise.all(imagePromises);
}
async function convertCanvasesToImages(annotationCanvasMap) {
async function convertCanvasesToImages(annotationCanvasMap, outputScale) {
const results = new Map();
const promises = [];
for (const [key, canvas] of annotationCanvasMap) {
@ -112,7 +112,10 @@ async function convertCanvasesToImages(annotationCanvasMap) {
new Promise(resolve => {
canvas.toBlob(blob => {
const image = document.createElement("img");
image.onload = resolve;
image.onload = function () {
image.style.width = Math.floor(image.width / outputScale) + "px";
resolve();
};
results.set(key, image);
image.src = URL.createObjectURL(blob);
});
@ -200,6 +203,7 @@ class Rasterize {
static async annotationLayer(
ctx,
viewport,
outputScale,
annotations,
annotationCanvasMap,
page,
@ -215,7 +219,8 @@ class Rasterize {
const annotationViewport = viewport.clone({ dontFlip: true });
const annotationImageMap = await convertCanvasesToImages(
annotationCanvasMap
annotationCanvasMap,
outputScale
);
// Rendering annotation layer as HTML.
@ -608,13 +613,38 @@ class Driver {
ctx = this.canvas.getContext("2d", { alpha: false });
task.pdfDoc.getPage(task.pageNum).then(
page => {
const viewport = page.getViewport({
// Default to creating the test images at the devices pixel ratio,
// unless the test explicitly specifies an output scale.
const outputScale = task.outputScale || window.devicePixelRatio;
let viewport = page.getViewport({
scale: PixelsPerInch.PDF_TO_CSS_UNITS,
});
this.canvas.width = viewport.width;
this.canvas.height = viewport.height;
// Restrict the test from creating a canvas that is too big.
const MAX_CANVAS_PIXEL_DIMENSION = 4096;
const largestDimension = Math.max(viewport.width, viewport.height);
if (
Math.floor(largestDimension * outputScale) >
MAX_CANVAS_PIXEL_DIMENSION
) {
const rescale = MAX_CANVAS_PIXEL_DIMENSION / largestDimension;
viewport = viewport.clone({
scale: PixelsPerInch.PDF_TO_CSS_UNITS * rescale,
});
}
const pixelWidth = Math.floor(viewport.width * outputScale);
const pixelHeight = Math.floor(viewport.height * outputScale);
task.viewportWidth = Math.floor(viewport.width);
task.viewportHeight = Math.floor(viewport.height);
task.outputScale = outputScale;
this.canvas.width = pixelWidth;
this.canvas.height = pixelHeight;
this.canvas.style.width = Math.floor(viewport.width) + "px";
this.canvas.style.height = Math.floor(viewport.height) + "px";
this._clearCanvas();
const transform =
outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null;
// Initialize various `eq` test subtypes, see comment below.
let renderAnnotations = false,
renderForms = false,
@ -639,8 +669,8 @@ class Driver {
textLayerCanvas = document.createElement("canvas");
this.textLayerCanvas = textLayerCanvas;
}
textLayerCanvas.width = viewport.width;
textLayerCanvas.height = viewport.height;
textLayerCanvas.width = pixelWidth;
textLayerCanvas.height = pixelHeight;
const textLayerContext = textLayerCanvas.getContext("2d");
textLayerContext.clearRect(
0,
@ -648,6 +678,7 @@ class Driver {
textLayerCanvas.width,
textLayerCanvas.height
);
textLayerContext.scale(outputScale, outputScale);
const enhanceText = !!task.enhance;
// The text builder will draw its content on the test canvas
initPromise = page
@ -679,8 +710,8 @@ class Driver {
annotationLayerCanvas = document.createElement("canvas");
this.annotationLayerCanvas = annotationLayerCanvas;
}
annotationLayerCanvas.width = viewport.width;
annotationLayerCanvas.height = viewport.height;
annotationLayerCanvas.width = pixelWidth;
annotationLayerCanvas.height = pixelHeight;
annotationLayerContext = annotationLayerCanvas.getContext("2d");
annotationLayerContext.clearRect(
0,
@ -688,6 +719,7 @@ class Driver {
annotationLayerCanvas.width,
annotationLayerCanvas.height
);
annotationLayerContext.scale(outputScale, outputScale);
if (!renderXfa) {
// The annotation builder will draw its content
@ -716,6 +748,7 @@ class Driver {
viewport,
optionalContentConfigPromise: task.optionalContentConfigPromise,
annotationCanvasMap,
transform,
};
if (renderForms) {
renderContext.annotationMode = AnnotationMode.ENABLE_FORMS;
@ -732,7 +765,7 @@ class Driver {
ctx.save();
ctx.globalCompositeOperation = "screen";
ctx.fillStyle = "rgb(128, 255, 128)"; // making it green
ctx.fillRect(0, 0, viewport.width, viewport.height);
ctx.fillRect(0, 0, pixelWidth, pixelHeight);
ctx.restore();
ctx.drawImage(textLayerCanvas, 0, 0);
}
@ -762,6 +795,7 @@ class Driver {
Rasterize.annotationLayer(
annotationLayerContext,
viewport,
outputScale,
data,
annotationCanvasMap,
page,
@ -871,6 +905,9 @@ class Driver {
page: task.pageNum,
snapshot,
stats: task.stats.times,
viewportWidth: task.viewportWidth,
viewportHeight: task.viewportHeight,
outputScale: task.outputScale,
});
this._send("/submit_task_results", result, callback);
}

View File

@ -165,8 +165,8 @@ Original author: L. David Baron <dbaron@dbaron.org>
</filter>
</defs>
<g id="magnify">
<image x="0" y="0" width="100%" height="100%" id="image1" />
<image x="0" y="0" width="100%" height="100%" id="image2" />
<image x="0" y="0" id="image1" />
<image x="0" y="0" id="image2" />
</g>
<rect id="diffrect" filter="url(#showDifferences)" pointer-events="none" x="0" y="0" width="100%" height="100%" />
</svg>

View File

@ -228,10 +228,15 @@ window.onload = function () {
});
continue;
}
match = line.match(/^ {2}IMAGE[^:]*: (.*)$/);
match = line.match(/^ {2}IMAGE[^:]*\((\d+)x(\d+)x(\d+)\): (.*)$/);
if (match) {
const item = gTestItems[gTestItems.length - 1];
item.images.push(match[1]);
item.images.push({
width: parseFloat(match[1]),
height: parseFloat(match[2]),
outputScale: parseFloat(match[3]),
file: match[4],
});
}
}
buildViewer();
@ -335,16 +340,31 @@ window.onload = function () {
const cell = ID("images");
ID("image1").style.display = "";
const scale = item.images[0].outputScale / window.devicePixelRatio;
ID("image1").setAttribute("width", item.images[0].width * scale);
ID("image1").setAttribute("height", item.images[0].height * scale);
ID("svg").setAttribute("width", item.images[0].width * scale);
ID("svg").setAttribute("height", item.images[0].height * scale);
ID("image2").style.display = "none";
if (item.images[1]) {
ID("image2").setAttribute("width", item.images[1].width * scale);
ID("image2").setAttribute("height", item.images[1].height * scale);
}
ID("diffrect").style.display = "none";
ID("imgcontrols").reset();
ID("image1").setAttributeNS(XLINK_NS, "xlink:href", gPath + item.images[0]);
ID("image1").setAttributeNS(
XLINK_NS,
"xlink:href",
gPath + item.images[0].file
);
// Making the href be #image1 doesn't seem to work
ID("feimage1").setAttributeNS(
XLINK_NS,
"xlink:href",
gPath + item.images[0]
gPath + item.images[0].file
);
if (item.images.length === 1) {
ID("imgcontrols").style.display = "none";
@ -353,30 +373,24 @@ window.onload = function () {
ID("image2").setAttributeNS(
XLINK_NS,
"xlink:href",
gPath + item.images[1]
gPath + item.images[1].file
);
// Making the href be #image2 doesn't seem to work
ID("feimage2").setAttributeNS(
XLINK_NS,
"xlink:href",
gPath + item.images[1]
gPath + item.images[1].file
);
}
cell.style.display = "";
getImageData(item.images[0], function (data) {
getImageData(item.images[0].file, function (data) {
gImage1Data = data;
syncSVGSize(gImage1Data);
});
getImageData(item.images[1], function (data) {
getImageData(item.images[1].file, function (data) {
gImage2Data = data;
});
}
function syncSVGSize(imageData) {
ID("svg").setAttribute("width", imageData.width);
ID("svg").setAttribute("height", imageData.height);
}
function showImage(i) {
if (i === 1) {
ID("image1").style.display = "";
@ -414,7 +428,7 @@ window.onload = function () {
}
function canvasPixelAsHex(data, x, y) {
const offset = (y * data.width + x) * 4;
const offset = (y * data.width + x) * 4 * window.devicePixelRatio;
const r = data.data[offset];
const g = data.data[offset + 1];
const b = data.data[offset + 2];

View File

@ -451,7 +451,8 @@ function checkEq(task, results, browser, masterMode) {
if (!pageResults[page]) {
continue;
}
var testSnapshot = pageResults[page].snapshot;
const pageResult = pageResults[page];
let testSnapshot = pageResult.snapshot;
if (testSnapshot && testSnapshot.startsWith("data:image/png;base64,")) {
testSnapshot = Buffer.from(testSnapshot.substring(22), "base64");
} else {
@ -492,8 +493,8 @@ function checkEq(task, results, browser, masterMode) {
refSnapshot
);
// NB: this follows the format of Mozilla reftest output so that
// we can reuse its reftest-analyzer script
// This no longer follows the format of Mozilla reftest output.
const viewportString = `(${pageResult.viewportWidth}x${pageResult.viewportHeight}x${pageResult.outputScale})`;
fs.appendFileSync(
eqLog,
"REFTEST TEST-UNEXPECTED-FAIL | " +
@ -503,10 +504,10 @@ function checkEq(task, results, browser, masterMode) {
"-page" +
(page + 1) +
" | image comparison (==)\n" +
"REFTEST IMAGE 1 (TEST): " +
`REFTEST IMAGE 1 (TEST)${viewportString}: ` +
path.join(testSnapshotDir, page + 1 + ".png") +
"\n" +
"REFTEST IMAGE 2 (REFERENCE): " +
`REFTEST IMAGE 2 (REFERENCE)${viewportString}: ` +
path.join(testSnapshotDir, page + 1 + "_ref.png") +
"\n"
);
@ -735,6 +736,9 @@ function refTestPostHandler(req, res) {
taskResults[round][page] = {
failure,
snapshot,
viewportWidth: data.viewportWidth,
viewportHeight: data.viewportHeight,
outputScale: data.outputScale,
};
if (stats) {
stats.push({

View File

@ -6142,6 +6142,18 @@
"forms": true,
"lastPage": 1
},
{
"id": "issue12716-hidpi",
"file": "pdfs/issue12716.pdf",
"md5": "9bdc9c552bcfccd629f5f97385e79ca5",
"rounds": 1,
"link": true,
"type": "eq",
"forms": true,
"lastPage": 1,
"outputScale": 2,
"about": "This tests draws to another canvas for the button, so it's a good test to ensure output scale is working."
},
{ "id": "xfa_issue13500",
"file": "pdfs/xfa_issue13500.pdf",
"md5": "b81274a19f5a95c1466db3648f1be491",