Merge pull request #15246 from Snuffleupagus/thumbnail-setImage-improvements

[api-minor] Improve `thumbnail` handling in documents that contain interactive forms
This commit is contained in:
Tim van der Meij 2022-07-31 11:42:55 +02:00 committed by GitHub
commit b8aa9c6221
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 185 additions and 101 deletions

View File

@ -881,7 +881,11 @@ class Annotation {
); );
if (!appearance) { if (!appearance) {
if (!isUsingOwnCanvas) { if (!isUsingOwnCanvas) {
return new OperatorList(); return {
opList: new OperatorList(),
separateForm: false,
separateCanvas: false,
};
} }
appearance = new StringStream(""); appearance = new StringStream("");
appearance.dict = new Dict(); appearance.dict = new Dict();
@ -930,7 +934,7 @@ class Annotation {
opList.addOp(OPS.endMarkedContent, []); opList.addOp(OPS.endMarkedContent, []);
} }
this.reset(); this.reset();
return opList; return { opList, separateForm: false, separateCanvas: isUsingOwnCanvas };
} }
async save(evaluator, task, annotationStorage) { async save(evaluator, task, annotationStorage) {
@ -1619,7 +1623,11 @@ class WidgetAnnotation extends Annotation {
// Do not render form elements on the canvas when interactive forms are // Do not render form elements on the canvas when interactive forms are
// enabled. The display layer is responsible for rendering them instead. // enabled. The display layer is responsible for rendering them instead.
if (renderForms && !(this instanceof SignatureWidgetAnnotation)) { if (renderForms && !(this instanceof SignatureWidgetAnnotation)) {
return new OperatorList(); return {
opList: new OperatorList(),
separateForm: true,
separateCanvas: false,
};
} }
if (!this._hasText) { if (!this._hasText) {
@ -1647,12 +1655,12 @@ class WidgetAnnotation extends Annotation {
); );
} }
const operatorList = new OperatorList(); const opList = new OperatorList();
// Even if there is an appearance stream, ignore it. This is the // Even if there is an appearance stream, ignore it. This is the
// behaviour used by Adobe Reader. // behaviour used by Adobe Reader.
if (!this._defaultAppearance || content === null) { if (!this._defaultAppearance || content === null) {
return operatorList; return { opList, separateForm: false, separateCanvas: false };
} }
const matrix = [1, 0, 0, 1, 0, 0]; const matrix = [1, 0, 0, 1, 0, 0];
@ -1672,10 +1680,10 @@ class WidgetAnnotation extends Annotation {
); );
} }
if (optionalContent !== undefined) { if (optionalContent !== undefined) {
operatorList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]); opList.addOp(OPS.beginMarkedContentProps, ["OC", optionalContent]);
} }
operatorList.addOp(OPS.beginAnnotation, [ opList.addOp(OPS.beginAnnotation, [
this.data.id, this.data.id,
this.data.rect, this.data.rect,
transform, transform,
@ -1688,14 +1696,14 @@ class WidgetAnnotation extends Annotation {
stream, stream,
task, task,
resources: this._fieldResources.mergedResources, resources: this._fieldResources.mergedResources,
operatorList, operatorList: opList,
}); });
operatorList.addOp(OPS.endAnnotation, []); opList.addOp(OPS.endAnnotation, []);
if (optionalContent !== undefined) { if (optionalContent !== undefined) {
operatorList.addOp(OPS.endMarkedContent, []); opList.addOp(OPS.endMarkedContent, []);
} }
return operatorList; return { opList, separateForm: false, separateCanvas: false };
} }
_getMKDict(rotation) { _getMKDict(rotation) {
@ -2477,7 +2485,11 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
} }
// No appearance // No appearance
return new OperatorList(); return {
opList: new OperatorList(),
separateForm: false,
separateCanvas: false,
};
} }
async save(evaluator, task, annotationStorage) { async save(evaluator, task, annotationStorage) {

View File

@ -455,7 +455,7 @@ class Page {
annotations.length === 0 || annotations.length === 0 ||
intent & RenderingIntentFlag.ANNOTATIONS_DISABLE intent & RenderingIntentFlag.ANNOTATIONS_DISABLE
) { ) {
pageOpList.flush(true); pageOpList.flush(/* lastChunk = */ true);
return { length: pageOpList.totalLength }; return { length: pageOpList.totalLength };
} }
const renderForms = !!(intent & RenderingIntentFlag.ANNOTATIONS_FORMS), const renderForms = !!(intent & RenderingIntentFlag.ANNOTATIONS_FORMS),
@ -493,10 +493,23 @@ class Page {
} }
return Promise.all(opListPromises).then(function (opLists) { return Promise.all(opListPromises).then(function (opLists) {
for (const opList of opLists) { let form = false,
canvas = false;
for (const { opList, separateForm, separateCanvas } of opLists) {
pageOpList.addOpList(opList); pageOpList.addOpList(opList);
if (separateForm) {
form = separateForm;
}
if (separateCanvas) {
canvas = separateCanvas;
}
} }
pageOpList.flush(true); pageOpList.flush(
/* lastChunk = */ true,
/* separateAnnots = */ { form, canvas }
);
return { length: pageOpList.totalLength }; return { length: pageOpList.totalLength };
}); });
}); });

View File

@ -690,7 +690,7 @@ class OperatorList {
return transfers; return transfers;
} }
flush(lastChunk = false) { flush(lastChunk = false, separateAnnots = null) {
this.optimizer.flush(); this.optimizer.flush();
const length = this.length; const length = this.length;
this._totalLength += length; this._totalLength += length;
@ -700,6 +700,7 @@ class OperatorList {
fnArray: this.fnArray, fnArray: this.fnArray,
argsArray: this.argsArray, argsArray: this.argsArray,
lastChunk, lastChunk,
separateAnnots,
length, length,
}, },
1, 1,

View File

@ -1477,6 +1477,7 @@ class PDFPageProxy {
fnArray: [], fnArray: [],
argsArray: [], argsArray: [],
lastChunk: false, lastChunk: false,
separateAnnots: null,
}; };
if (this._stats) { if (this._stats) {
@ -1599,6 +1600,7 @@ class PDFPageProxy {
fnArray: [], fnArray: [],
argsArray: [], argsArray: [],
lastChunk: false, lastChunk: false,
separateAnnots: null,
}; };
if (this._stats) { if (this._stats) {
@ -1795,6 +1797,7 @@ class PDFPageProxy {
intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]); intentState.operatorList.argsArray.push(operatorListChunk.argsArray[i]);
} }
intentState.operatorList.lastChunk = operatorListChunk.lastChunk; intentState.operatorList.lastChunk = operatorListChunk.lastChunk;
intentState.operatorList.separateAnnots = operatorListChunk.separateAnnots;
// Notify all the rendering tasks there are more operators to be consumed. // Notify all the rendering tasks there are more operators to be consumed.
for (const internalRenderTask of intentState.renderTasks) { for (const internalRenderTask of intentState.renderTasks) {
@ -3194,8 +3197,10 @@ class PDFObjects {
* Allows controlling of the rendering tasks. * Allows controlling of the rendering tasks.
*/ */
class RenderTask { class RenderTask {
#internalRenderTask = null;
constructor(internalRenderTask) { constructor(internalRenderTask) {
this._internalRenderTask = internalRenderTask; this.#internalRenderTask = internalRenderTask;
/** /**
* Callback for incremental rendering -- a function that will be called * Callback for incremental rendering -- a function that will be called
@ -3211,7 +3216,7 @@ class RenderTask {
* @type {Promise<void>} * @type {Promise<void>}
*/ */
get promise() { get promise() {
return this._internalRenderTask.capability.promise; return this.#internalRenderTask.capability.promise;
} }
/** /**
@ -3220,7 +3225,23 @@ class RenderTask {
* this object extends will be rejected when cancelled. * this object extends will be rejected when cancelled.
*/ */
cancel() { cancel() {
this._internalRenderTask.cancel(); this.#internalRenderTask.cancel();
}
/**
* Whether form fields are rendered separately from the main operatorList.
* @type {boolean}
*/
get separateAnnots() {
const { separateAnnots } = this.#internalRenderTask.operatorList;
if (!separateAnnots) {
return false;
}
const { annotationCanvasMap } = this.#internalRenderTask;
return (
separateAnnots.form ||
(separateAnnots.canvas && annotationCanvasMap?.size > 0)
);
} }
} }

View File

@ -1682,29 +1682,27 @@ describe("annotation", function () {
); );
const annotationStorage = new Map(); const annotationStorage = new Map();
const operatorList = await annotation.getOperatorList( const { opList } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList.argsArray[0]).toEqual([
"271R", "271R",
[0, 0, 32, 10], [0, 0, 32, 10],
[32, 0, 0, 10, 0, 0], [32, 0, 0, 10, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList.argsArray[1]).toEqual(new Uint8ClampedArray([26, 51, 76]));
new Uint8ClampedArray([26, 51, 76])
);
}); });
it("should render auto-sized text for printing", async function () { it("should render auto-sized text for printing", async function () {
@ -2369,29 +2367,29 @@ describe("annotation", function () {
const annotationStorage = new Map(); const annotationStorage = new Map();
annotationStorage.set(annotation.data.id, { value: true }); annotationStorage.set(annotation.data.id, { value: true });
const operatorList = await annotation.getOperatorList( const { opList } = await annotation.getOperatorList(
checkboxEvaluator, checkboxEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(5); expect(opList.argsArray.length).toEqual(5);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.dependency, OPS.dependency,
OPS.setFont, OPS.setFont,
OPS.showText, OPS.showText,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[3][0][0].unicode).toEqual("4"); expect(opList.argsArray[3][0][0].unicode).toEqual("4");
}); });
it("should render checkboxes for printing", async function () { it("should render checkboxes for printing", async function () {
@ -2430,55 +2428,51 @@ describe("annotation", function () {
const annotationStorage = new Map(); const annotationStorage = new Map();
annotationStorage.set(annotation.data.id, { value: true }); annotationStorage.set(annotation.data.id, { value: true });
let operatorList = await annotation.getOperatorList( const { opList: opList1 } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList1.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList1.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList1.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList1.argsArray[1]).toEqual(new Uint8ClampedArray([26, 51, 76]));
new Uint8ClampedArray([26, 51, 76])
);
annotationStorage.set(annotation.data.id, { value: false }); annotationStorage.set(annotation.data.id, { value: false });
operatorList = await annotation.getOperatorList( const { opList: opList2 } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList2.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList2.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList2.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList2.argsArray[1]).toEqual(new Uint8ClampedArray([76, 51, 26]));
new Uint8ClampedArray([76, 51, 26])
);
}); });
it("should render checkboxes for printing twice", async function () { it("should render checkboxes for printing twice", async function () {
@ -2520,27 +2514,27 @@ describe("annotation", function () {
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
annotationStorage.set(annotation.data.id, { value: true }); annotationStorage.set(annotation.data.id, { value: true });
const operatorList = await annotation.getOperatorList( const { opList } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList.argsArray[0]).toEqual([
"1249R", "1249R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList.argsArray[1]).toEqual(
new Uint8ClampedArray([26, 51, 76]) new Uint8ClampedArray([26, 51, 76])
); );
} }
@ -2582,29 +2576,27 @@ describe("annotation", function () {
); );
const annotationStorage = new Map(); const annotationStorage = new Map();
const operatorList = await annotation.getOperatorList( const { opList } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList.argsArray[1]).toEqual(new Uint8ClampedArray([26, 51, 76]));
new Uint8ClampedArray([26, 51, 76])
);
}); });
it("should save checkboxes", async function () { it("should save checkboxes", async function () {
@ -2838,55 +2830,51 @@ describe("annotation", function () {
const annotationStorage = new Map(); const annotationStorage = new Map();
annotationStorage.set(annotation.data.id, { value: true }); annotationStorage.set(annotation.data.id, { value: true });
let operatorList = await annotation.getOperatorList( const { opList: opList1 } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList1.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList1.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList1.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList1.argsArray[1]).toEqual(new Uint8ClampedArray([26, 51, 76]));
new Uint8ClampedArray([26, 51, 76])
);
annotationStorage.set(annotation.data.id, { value: false }); annotationStorage.set(annotation.data.id, { value: false });
operatorList = await annotation.getOperatorList( const { opList: opList2 } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList2.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList2.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList2.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList2.argsArray[1]).toEqual(new Uint8ClampedArray([76, 51, 26]));
new Uint8ClampedArray([76, 51, 26])
);
}); });
it("should render radio buttons for printing using normal appearance", async function () { it("should render radio buttons for printing using normal appearance", async function () {
@ -2926,29 +2914,27 @@ describe("annotation", function () {
); );
const annotationStorage = new Map(); const annotationStorage = new Map();
const operatorList = await annotation.getOperatorList( const { opList } = await annotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
false, false,
annotationStorage annotationStorage
); );
expect(operatorList.argsArray.length).toEqual(3); expect(opList.argsArray.length).toEqual(3);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setFillRGBColor, OPS.setFillRGBColor,
OPS.endAnnotation, OPS.endAnnotation,
]); ]);
expect(operatorList.argsArray[0]).toEqual([ expect(opList.argsArray[0]).toEqual([
"124R", "124R",
[0, 0, 0, 0], [0, 0, 0, 0],
[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0],
false, false,
]); ]);
expect(operatorList.argsArray[1]).toEqual( expect(opList.argsArray[1]).toEqual(new Uint8ClampedArray([76, 51, 26]));
new Uint8ClampedArray([76, 51, 26])
);
}); });
it("should save radio buttons", async function () { it("should save radio buttons", async function () {
@ -4087,7 +4073,7 @@ describe("annotation", function () {
]) ])
)[0]; )[0];
const operatorList = await freetextAnnotation.getOperatorList( const { opList } = await freetextAnnotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
@ -4095,8 +4081,8 @@ describe("annotation", function () {
null null
); );
expect(operatorList.fnArray.length).toEqual(16); expect(opList.fnArray.length).toEqual(16);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.save, OPS.save,
OPS.constructPath, OPS.constructPath,
@ -4322,7 +4308,7 @@ describe("annotation", function () {
]) ])
)[0]; )[0];
const operatorList = await inkAnnotation.getOperatorList( const { opList } = await inkAnnotation.getOperatorList(
partialEvaluator, partialEvaluator,
task, task,
RenderingIntentFlag.PRINT, RenderingIntentFlag.PRINT,
@ -4330,8 +4316,8 @@ describe("annotation", function () {
null null
); );
expect(operatorList.argsArray.length).toEqual(8); expect(opList.argsArray.length).toEqual(8);
expect(operatorList.fnArray).toEqual([ expect(opList.fnArray).toEqual([
OPS.beginAnnotation, OPS.beginAnnotation,
OPS.setLineWidth, OPS.setLineWidth,
OPS.setLineCap, OPS.setLineCap,
@ -4343,20 +4329,18 @@ describe("annotation", function () {
]); ]);
// Linewidth. // Linewidth.
expect(operatorList.argsArray[1]).toEqual([3]); expect(opList.argsArray[1]).toEqual([3]);
// LineCap. // LineCap.
expect(operatorList.argsArray[2]).toEqual([1]); expect(opList.argsArray[2]).toEqual([1]);
// LineJoin. // LineJoin.
expect(operatorList.argsArray[3]).toEqual([1]); expect(opList.argsArray[3]).toEqual([1]);
// Color. // Color.
expect(operatorList.argsArray[4]).toEqual( expect(opList.argsArray[4]).toEqual(new Uint8ClampedArray([0, 255, 0]));
new Uint8ClampedArray([0, 255, 0])
);
// Path. // Path.
expect(operatorList.argsArray[5][0]).toEqual([OPS.moveTo, OPS.curveTo]); expect(opList.argsArray[5][0]).toEqual([OPS.moveTo, OPS.curveTo]);
expect(operatorList.argsArray[5][1]).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); expect(opList.argsArray[5][1]).toEqual([1, 2, 3, 4, 5, 6, 7, 8]);
// Min-max. // Min-max.
expect(operatorList.argsArray[5][2]).toEqual([1, 1, 2, 2]); expect(opList.argsArray[5][2]).toEqual([1, 1, 2, 2]);
}); });
}); });

View File

@ -501,6 +501,7 @@ describe("api", function () {
expect(opList.fnArray.length).toEqual(0); expect(opList.fnArray.length).toEqual(0);
expect(opList.argsArray.length).toEqual(0); expect(opList.argsArray.length).toEqual(0);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
await loadingTask.destroy(); await loadingTask.destroy();
}); });
@ -521,6 +522,7 @@ describe("api", function () {
expect(opList.fnArray.length).toEqual(0); expect(opList.fnArray.length).toEqual(0);
expect(opList.argsArray.length).toEqual(0); expect(opList.argsArray.length).toEqual(0);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
await loadingTask.destroy(); await loadingTask.destroy();
}); });
@ -588,6 +590,7 @@ describe("api", function () {
expect(opList.fnArray.length).toBeGreaterThan(5); expect(opList.fnArray.length).toBeGreaterThan(5);
expect(opList.argsArray.length).toBeGreaterThan(5); expect(opList.argsArray.length).toBeGreaterThan(5);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
try { try {
await pdfDocument2.getPage(1); await pdfDocument2.getPage(1);
@ -631,6 +634,7 @@ describe("api", function () {
expect(opList.fnArray.length).toBeGreaterThan(5); expect(opList.fnArray.length).toBeGreaterThan(5);
expect(opList.argsArray.length).toBeGreaterThan(5); expect(opList.argsArray.length).toBeGreaterThan(5);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
} }
await Promise.all([loadingTask1.destroy(), loadingTask2.destroy()]); await Promise.all([loadingTask1.destroy(), loadingTask2.destroy()]);
@ -2402,6 +2406,10 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(operatorList.fnArray.length).toBeGreaterThan(100); expect(operatorList.fnArray.length).toBeGreaterThan(100);
expect(operatorList.argsArray.length).toBeGreaterThan(100); expect(operatorList.argsArray.length).toBeGreaterThan(100);
expect(operatorList.lastChunk).toEqual(true); expect(operatorList.lastChunk).toEqual(true);
expect(operatorList.separateAnnots).toEqual({
form: false,
canvas: false,
});
}); });
it("gets operatorList with JPEG image (issue 4888)", async function () { it("gets operatorList with JPEG image (issue 4888)", async function () {
@ -2442,6 +2450,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opList.fnArray.length).toBeGreaterThan(100); expect(opList.fnArray.length).toBeGreaterThan(100);
expect(opList.argsArray.length).toBeGreaterThan(100); expect(opList.argsArray.length).toBeGreaterThan(100);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
return loadingTask1.destroy(); return loadingTask1.destroy();
}); });
@ -2454,6 +2463,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opList.fnArray.length).toEqual(0); expect(opList.fnArray.length).toEqual(0);
expect(opList.argsArray.length).toEqual(0); expect(opList.argsArray.length).toEqual(0);
expect(opList.lastChunk).toEqual(true); expect(opList.lastChunk).toEqual(true);
expect(opList.separateAnnots).toEqual(null);
return loadingTask2.destroy(); return loadingTask2.destroy();
}); });
@ -2475,6 +2485,10 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(operatorList.fnArray.length).toBeGreaterThan(20); expect(operatorList.fnArray.length).toBeGreaterThan(20);
expect(operatorList.argsArray.length).toBeGreaterThan(20); expect(operatorList.argsArray.length).toBeGreaterThan(20);
expect(operatorList.lastChunk).toEqual(true); expect(operatorList.lastChunk).toEqual(true);
expect(operatorList.separateAnnots).toEqual({
form: false,
canvas: false,
});
// The `getOperatorList` method, similar to the `render` method, // The `getOperatorList` method, similar to the `render` method,
// is supposed to include any existing Annotation-operatorLists. // is supposed to include any existing Annotation-operatorLists.
@ -2498,6 +2512,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opListAnnotDisable.fnArray.length).toEqual(0); expect(opListAnnotDisable.fnArray.length).toEqual(0);
expect(opListAnnotDisable.argsArray.length).toEqual(0); expect(opListAnnotDisable.argsArray.length).toEqual(0);
expect(opListAnnotDisable.lastChunk).toEqual(true); expect(opListAnnotDisable.lastChunk).toEqual(true);
expect(opListAnnotDisable.separateAnnots).toEqual(null);
const opListAnnotEnable = await pdfPage.getOperatorList({ const opListAnnotEnable = await pdfPage.getOperatorList({
annotationMode: AnnotationMode.ENABLE, annotationMode: AnnotationMode.ENABLE,
@ -2505,6 +2520,10 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opListAnnotEnable.fnArray.length).toBeGreaterThan(140); expect(opListAnnotEnable.fnArray.length).toBeGreaterThan(140);
expect(opListAnnotEnable.argsArray.length).toBeGreaterThan(140); expect(opListAnnotEnable.argsArray.length).toBeGreaterThan(140);
expect(opListAnnotEnable.lastChunk).toEqual(true); expect(opListAnnotEnable.lastChunk).toEqual(true);
expect(opListAnnotEnable.separateAnnots).toEqual({
form: false,
canvas: true,
});
let firstAnnotIndex = opListAnnotEnable.fnArray.indexOf( let firstAnnotIndex = opListAnnotEnable.fnArray.indexOf(
OPS.beginAnnotation OPS.beginAnnotation
@ -2518,6 +2537,10 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opListAnnotEnableForms.fnArray.length).toBeGreaterThan(30); expect(opListAnnotEnableForms.fnArray.length).toBeGreaterThan(30);
expect(opListAnnotEnableForms.argsArray.length).toBeGreaterThan(30); expect(opListAnnotEnableForms.argsArray.length).toBeGreaterThan(30);
expect(opListAnnotEnableForms.lastChunk).toEqual(true); expect(opListAnnotEnableForms.lastChunk).toEqual(true);
expect(opListAnnotEnableForms.separateAnnots).toEqual({
form: true,
canvas: true,
});
firstAnnotIndex = opListAnnotEnableForms.fnArray.indexOf( firstAnnotIndex = opListAnnotEnableForms.fnArray.indexOf(
OPS.beginAnnotation OPS.beginAnnotation
@ -2531,6 +2554,10 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(opListAnnotEnableStorage.fnArray.length).toBeGreaterThan(170); expect(opListAnnotEnableStorage.fnArray.length).toBeGreaterThan(170);
expect(opListAnnotEnableStorage.argsArray.length).toBeGreaterThan(170); expect(opListAnnotEnableStorage.argsArray.length).toBeGreaterThan(170);
expect(opListAnnotEnableStorage.lastChunk).toEqual(true); expect(opListAnnotEnableStorage.lastChunk).toEqual(true);
expect(opListAnnotEnableStorage.separateAnnots).toEqual({
form: false,
canvas: true,
});
firstAnnotIndex = opListAnnotEnableStorage.fnArray.indexOf( firstAnnotIndex = opListAnnotEnableStorage.fnArray.indexOf(
OPS.beginAnnotation OPS.beginAnnotation
@ -2635,8 +2662,9 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(renderTask instanceof RenderTask).toEqual(true); expect(renderTask instanceof RenderTask).toEqual(true);
await renderTask.promise; await renderTask.promise;
const stats = pdfPage.stats; expect(renderTask.separateAnnots).toEqual(false);
const { stats } = pdfPage;
expect(stats instanceof StatTimer).toEqual(true); expect(stats instanceof StatTimer).toEqual(true);
expect(stats.times.length).toEqual(3); expect(stats.times.length).toEqual(3);
@ -2719,6 +2747,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(reRenderTask instanceof RenderTask).toEqual(true); expect(reRenderTask instanceof RenderTask).toEqual(true);
await reRenderTask.promise; await reRenderTask.promise;
expect(reRenderTask.separateAnnots).toEqual(false);
CanvasFactory.destroy(canvasAndCtx); CanvasFactory.destroy(canvasAndCtx);
}); });
@ -2785,8 +2814,9 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
expect(renderTask instanceof RenderTask).toEqual(true); expect(renderTask instanceof RenderTask).toEqual(true);
await renderTask.promise; await renderTask.promise;
await pdfDoc.cleanup(); expect(renderTask.separateAnnots).toEqual(false);
await pdfDoc.cleanup();
expect(true).toEqual(true); expect(true).toEqual(true);
CanvasFactory.destroy(canvasAndCtx); CanvasFactory.destroy(canvasAndCtx);
@ -2831,6 +2861,7 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
); );
} }
await renderTask.promise; await renderTask.promise;
expect(renderTask.separateAnnots).toEqual(false);
CanvasFactory.destroy(canvasAndCtx); CanvasFactory.destroy(canvasAndCtx);
await loadingTask.destroy(); await loadingTask.destroy();
@ -2918,6 +2949,8 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
}); });
await renderTask.promise; await renderTask.promise;
expect(renderTask.separateAnnots).toEqual(false);
const printData = canvasAndCtx.canvas.toDataURL(); const printData = canvasAndCtx.canvas.toDataURL();
CanvasFactory.destroy(canvasAndCtx); CanvasFactory.destroy(canvasAndCtx);
@ -3002,6 +3035,8 @@ Caron Broadcasting, Inc., an Ohio corporation (“Lessee”).`)
viewport, viewport,
}); });
await renderTask.promise; await renderTask.promise;
expect(renderTask.separateAnnots).toEqual(false);
const data = canvasAndCtx.canvas.toDataURL(); const data = canvasAndCtx.canvas.toDataURL();
CanvasFactory.destroy(canvasAndCtx); CanvasFactory.destroy(canvasAndCtx);
return data; return data;

View File

@ -99,7 +99,10 @@ const MAX_CANVAS_PIXELS = compatibilityParams.maxCanvasPixels || 16777216;
class PDFPageView { class PDFPageView {
#annotationMode = AnnotationMode.ENABLE_FORMS; #annotationMode = AnnotationMode.ENABLE_FORMS;
#useThumbnailCanvas = true; #useThumbnailCanvas = {
initialOptionalContent: true,
regularAnnotations: true,
};
/** /**
* @param {PDFPageViewOptions} options * @param {PDFPageViewOptions} options
@ -190,14 +193,15 @@ class PDFPageView {
const { optionalContentConfigPromise } = options; const { optionalContentConfigPromise } = options;
if (optionalContentConfigPromise) { if (optionalContentConfigPromise) {
// Ensure that the thumbnails always display the *initial* document // Ensure that the thumbnails always display the *initial* document
// state. // state, for documents with optional content.
optionalContentConfigPromise.then(optionalContentConfig => { optionalContentConfigPromise.then(optionalContentConfig => {
if ( if (
optionalContentConfigPromise !== this._optionalContentConfigPromise optionalContentConfigPromise !== this._optionalContentConfigPromise
) { ) {
return; return;
} }
this.#useThumbnailCanvas = optionalContentConfig.hasInitialVisibility; this.#useThumbnailCanvas.initialOptionalContent =
optionalContentConfig.hasInitialVisibility;
}); });
} }
} }
@ -408,14 +412,16 @@ class PDFPageView {
if (optionalContentConfigPromise instanceof Promise) { if (optionalContentConfigPromise instanceof Promise) {
this._optionalContentConfigPromise = optionalContentConfigPromise; this._optionalContentConfigPromise = optionalContentConfigPromise;
// Ensure that the thumbnails always display the *initial* document state. // Ensure that the thumbnails always display the *initial* document state,
// for documents with optional content.
optionalContentConfigPromise.then(optionalContentConfig => { optionalContentConfigPromise.then(optionalContentConfig => {
if ( if (
optionalContentConfigPromise !== this._optionalContentConfigPromise optionalContentConfigPromise !== this._optionalContentConfigPromise
) { ) {
return; return;
} }
this.#useThumbnailCanvas = optionalContentConfig.hasInitialVisibility; this.#useThumbnailCanvas.initialOptionalContent =
optionalContentConfig.hasInitialVisibility;
}); });
} }
@ -772,6 +778,10 @@ class PDFPageView {
} }
this._resetZoomLayer(/* removeFromDOM = */ true); this._resetZoomLayer(/* removeFromDOM = */ true);
// Ensure that the thumbnails won't become partially (or fully) blank,
// for documents that contain interactive form elements.
this.#useThumbnailCanvas.regularAnnotations = !paintTask.separateAnnots;
this.eventBus.dispatch("pagerendered", { this.eventBus.dispatch("pagerendered", {
source: this, source: this,
pageNumber: this.id, pageNumber: this.id,
@ -888,6 +898,9 @@ class PDFPageView {
cancel() { cancel() {
renderTask.cancel(); renderTask.cancel();
}, },
get separateAnnots() {
return renderTask.separateAnnots;
},
}; };
const viewport = this.viewport; const viewport = this.viewport;
@ -1029,6 +1042,9 @@ class PDFPageView {
cancel() { cancel() {
cancelled = true; cancelled = true;
}, },
get separateAnnots() {
return false;
},
}; };
} }
@ -1050,7 +1066,9 @@ class PDFPageView {
* @ignore * @ignore
*/ */
get thumbnailCanvas() { get thumbnailCanvas() {
return this.#useThumbnailCanvas ? this.canvas : null; const { initialOptionalContent, regularAnnotations } =
this.#useThumbnailCanvas;
return initialOptionalContent && regularAnnotations ? this.canvas : null;
} }
} }