Skip to content

Commit 755d04a

Browse files
committed
Render not displayed annotations in using normal appearance when printing
1 parent c98046e commit 755d04a

File tree

6 files changed

+206
-6
lines changed

6 files changed

+206
-6
lines changed

src/core/annotation.js

+28-5
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,8 @@ class WidgetAnnotation extends Annotation {
10971097
}
10981098

10991099
async save(evaluator, task, annotationStorage) {
1100-
if (this.data.fieldValue === annotationStorage[this.data.id]) {
1100+
const value = annotationStorage[this.data.id];
1101+
if (value === this.data.fieldValue || value === undefined) {
11011102
return null;
11021103
}
11031104

@@ -1116,7 +1117,6 @@ class WidgetAnnotation extends Annotation {
11161117
return null;
11171118
}
11181119

1119-
const value = annotationStorage[this.data.id];
11201120
const bbox = [
11211121
0,
11221122
0,
@@ -1182,7 +1182,13 @@ class WidgetAnnotation extends Annotation {
11821182
return null;
11831183
}
11841184
const value = annotationStorage[this.data.id];
1185+
if (value === undefined) {
1186+
// The annotation hasn't been rendered so use the appearance
1187+
return null;
1188+
}
1189+
11851190
if (value === "") {
1191+
// the field is empty: nothing to render
11861192
return "";
11871193
}
11881194

@@ -1556,7 +1562,16 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
15561562
}
15571563

15581564
if (annotationStorage) {
1559-
const value = annotationStorage[this.data.id] || false;
1565+
const value = annotationStorage[this.data.id];
1566+
if (value === undefined) {
1567+
return super.getOperatorList(
1568+
evaluator,
1569+
task,
1570+
renderForms,
1571+
annotationStorage
1572+
);
1573+
}
1574+
15601575
let appearance;
15611576
if (value) {
15621577
appearance = this.checkedAppearance;
@@ -1602,9 +1617,13 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
16021617
}
16031618

16041619
async _saveCheckbox(evaluator, task, annotationStorage) {
1605-
const defaultValue = this.data.fieldValue && this.data.fieldValue !== "Off";
16061620
const value = annotationStorage[this.data.id];
1621+
if (value === undefined) {
1622+
// No change
1623+
return null;
1624+
}
16071625

1626+
const defaultValue = this.data.fieldValue && this.data.fieldValue !== "Off";
16081627
if (defaultValue === value) {
16091628
return null;
16101629
}
@@ -1641,9 +1660,13 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
16411660
}
16421661

16431662
async _saveRadioButton(evaluator, task, annotationStorage) {
1644-
const defaultValue = this.data.fieldValue === this.data.buttonValue;
16451663
const value = annotationStorage[this.data.id];
1664+
if (value === undefined) {
1665+
// No change
1666+
return null;
1667+
}
16461668

1669+
const defaultValue = this.data.fieldValue === this.data.buttonValue;
16471670
if (defaultValue === value) {
16481671
return null;
16491672
}

src/display/annotation_layer.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
678678
// used and the full array of field values is stored.
679679
storage.getOrCreateValue(
680680
id,
681-
this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : null
681+
this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : undefined
682682
);
683683

684684
const selectElement = document.createElement("select");

test/pdfs/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
!bug766086.pdf
108108
!bug793632.pdf
109109
!bug1020858.pdf
110+
!prefilled_f1040.pdf
110111
!bug1050040.pdf
111112
!bug1200096.pdf
112113
!bug1068432.pdf

test/pdfs/prefilled_f1040.pdf

295 KB
Binary file not shown.

test/test_manifest.json

+10
Original file line numberDiff line numberDiff line change
@@ -3637,6 +3637,16 @@
36373637
"type": "eq",
36383638
"about": "CFF font that is drawn with clipping."
36393639
},
3640+
{ "id": "prefilled_f1040",
3641+
"file": "pdfs/prefilled_f1040.pdf",
3642+
"md5": "6c45b2c43e365bb7c88b9cddca0a4865",
3643+
"rounds": 1,
3644+
"type": "eq",
3645+
"print": true,
3646+
"annotationStorage": {
3647+
"1605R": true
3648+
}
3649+
},
36403650
{ "id": "clippath",
36413651
"file": "pdfs/clippath.pdf",
36423652
"md5": "7ab95c0f106dccd90d6569f241fe8771",

test/unit/annotation_spec.js

+166
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,55 @@ describe("annotation", function () {
16071607
}, done.fail);
16081608
});
16091609

1610+
it("should render regular text for printing using normal appearance", function (done) {
1611+
const textWidgetRef = Ref.get(271, 0);
1612+
1613+
const appearanceStatesDict = new Dict();
1614+
const normalAppearanceDict = new Dict();
1615+
1616+
const normalAppearanceStream = new StringStream("0.1 0.2 0.3 rg");
1617+
normalAppearanceStream.dict = normalAppearanceDict;
1618+
1619+
appearanceStatesDict.set("N", normalAppearanceStream);
1620+
textWidgetDict.set("AP", appearanceStatesDict);
1621+
1622+
const xref = new XRefMock([
1623+
{ ref: textWidgetRef, data: textWidgetDict },
1624+
fontRefObj,
1625+
]);
1626+
const task = new WorkerTask("test print");
1627+
partialEvaluator.xref = xref;
1628+
1629+
AnnotationFactory.create(
1630+
xref,
1631+
textWidgetRef,
1632+
pdfManagerMock,
1633+
idFactoryMock
1634+
)
1635+
.then(annotation => {
1636+
const annotationStorage = {};
1637+
return annotation.getOperatorList(
1638+
partialEvaluator,
1639+
task,
1640+
false,
1641+
annotationStorage
1642+
);
1643+
})
1644+
.then(opList => {
1645+
expect(opList.argsArray.length).toEqual(3);
1646+
expect(opList.fnArray).toEqual([
1647+
OPS.beginAnnotation,
1648+
OPS.setFillRGBColor,
1649+
OPS.endAnnotation,
1650+
]);
1651+
expect(opList.argsArray[1]).toEqual(
1652+
new Uint8ClampedArray([26, 51, 76])
1653+
);
1654+
done();
1655+
})
1656+
.catch(done.fail);
1657+
});
1658+
16101659
it("should render auto-sized text for printing", function (done) {
16111660
textWidgetDict.set("DA", "/Helv 0 Tf");
16121661

@@ -2045,6 +2094,64 @@ describe("annotation", function () {
20452094
}, done.fail);
20462095
});
20472096

2097+
it("should render checkboxes for printing using normal appearance", function (done) {
2098+
const appearanceStatesDict = new Dict();
2099+
const normalAppearanceDict = new Dict();
2100+
const checkedAppearanceDict = new Dict();
2101+
const uncheckedAppearanceDict = new Dict();
2102+
2103+
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
2104+
checkedStream.dict = checkedAppearanceDict;
2105+
2106+
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
2107+
uncheckedStream.dict = uncheckedAppearanceDict;
2108+
2109+
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
2110+
checkedAppearanceDict.set("FormType", 1);
2111+
checkedAppearanceDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
2112+
normalAppearanceDict.set("Checked", checkedStream);
2113+
normalAppearanceDict.set("Off", uncheckedStream);
2114+
appearanceStatesDict.set("N", normalAppearanceDict);
2115+
2116+
buttonWidgetDict.set("AP", appearanceStatesDict);
2117+
buttonWidgetDict.set("AS", Name.get("Checked"));
2118+
2119+
const buttonWidgetRef = Ref.get(124, 0);
2120+
const xref = new XRefMock([
2121+
{ ref: buttonWidgetRef, data: buttonWidgetDict },
2122+
]);
2123+
const task = new WorkerTask("test print");
2124+
2125+
AnnotationFactory.create(
2126+
xref,
2127+
buttonWidgetRef,
2128+
pdfManagerMock,
2129+
idFactoryMock
2130+
)
2131+
.then(annotation => {
2132+
const annotationStorage = {};
2133+
return annotation.getOperatorList(
2134+
partialEvaluator,
2135+
task,
2136+
false,
2137+
annotationStorage
2138+
);
2139+
})
2140+
.then(opList => {
2141+
expect(opList.argsArray.length).toEqual(3);
2142+
expect(opList.fnArray).toEqual([
2143+
OPS.beginAnnotation,
2144+
OPS.setFillRGBColor,
2145+
OPS.endAnnotation,
2146+
]);
2147+
expect(opList.argsArray[1]).toEqual(
2148+
new Uint8ClampedArray([26, 51, 76])
2149+
);
2150+
done();
2151+
})
2152+
.catch(done.fail);
2153+
});
2154+
20482155
it("should save checkboxes", function (done) {
20492156
const appearanceStatesDict = new Dict();
20502157
const normalAppearanceDict = new Dict();
@@ -2280,6 +2387,65 @@ describe("annotation", function () {
22802387
}, done.fail);
22812388
});
22822389

2390+
it("should render radio buttons for printing using normal appearance", function (done) {
2391+
const appearanceStatesDict = new Dict();
2392+
const normalAppearanceDict = new Dict();
2393+
const checkedAppearanceDict = new Dict();
2394+
const uncheckedAppearanceDict = new Dict();
2395+
2396+
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
2397+
checkedStream.dict = checkedAppearanceDict;
2398+
2399+
const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
2400+
uncheckedStream.dict = uncheckedAppearanceDict;
2401+
2402+
checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
2403+
checkedAppearanceDict.set("FormType", 1);
2404+
checkedAppearanceDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
2405+
normalAppearanceDict.set("Checked", checkedStream);
2406+
normalAppearanceDict.set("Off", uncheckedStream);
2407+
appearanceStatesDict.set("N", normalAppearanceDict);
2408+
2409+
buttonWidgetDict.set("Ff", AnnotationFieldFlag.RADIO);
2410+
buttonWidgetDict.set("AP", appearanceStatesDict);
2411+
buttonWidgetDict.set("AS", Name.get("Off"));
2412+
2413+
const buttonWidgetRef = Ref.get(124, 0);
2414+
const xref = new XRefMock([
2415+
{ ref: buttonWidgetRef, data: buttonWidgetDict },
2416+
]);
2417+
const task = new WorkerTask("test print");
2418+
2419+
AnnotationFactory.create(
2420+
xref,
2421+
buttonWidgetRef,
2422+
pdfManagerMock,
2423+
idFactoryMock
2424+
)
2425+
.then(annotation => {
2426+
const annotationStorage = {};
2427+
return annotation.getOperatorList(
2428+
partialEvaluator,
2429+
task,
2430+
false,
2431+
annotationStorage
2432+
);
2433+
})
2434+
.then(opList => {
2435+
expect(opList.argsArray.length).toEqual(3);
2436+
expect(opList.fnArray).toEqual([
2437+
OPS.beginAnnotation,
2438+
OPS.setFillRGBColor,
2439+
OPS.endAnnotation,
2440+
]);
2441+
expect(opList.argsArray[1]).toEqual(
2442+
new Uint8ClampedArray([76, 51, 26])
2443+
);
2444+
done();
2445+
})
2446+
.catch(done.fail);
2447+
});
2448+
22832449
it("should save radio buttons", function (done) {
22842450
const appearanceStatesDict = new Dict();
22852451
const normalAppearanceDict = new Dict();

0 commit comments

Comments
 (0)