@@ -22,18 +22,20 @@ import {
22
22
AnnotationType ,
23
23
assert ,
24
24
escapeString ,
25
+ getModificationDate ,
25
26
isString ,
26
27
OPS ,
27
28
stringToPDFString ,
28
29
Util ,
29
30
warn ,
30
31
} from "../shared/util.js" ;
31
32
import { Catalog , FileSpec , ObjectLoader } from "./obj.js" ;
32
- import { Dict , isDict , isName , isRef , isStream } from "./primitives.js" ;
33
+ import { Dict , isDict , isName , isRef , isStream , Name } from "./primitives.js" ;
33
34
import { ColorSpace } from "./colorspace.js" ;
34
35
import { getInheritableProperty } from "./core_utils.js" ;
35
36
import { OperatorList } from "./operator_list.js" ;
36
37
import { StringStream } from "./stream.js" ;
38
+ import { writeDict } from "./writer.js" ;
37
39
38
40
class AnnotationFactory {
39
41
/**
@@ -68,6 +70,7 @@ class AnnotationFactory {
68
70
if ( ! isDict ( dict ) ) {
69
71
return undefined ;
70
72
}
73
+
71
74
const id = isRef ( ref ) ? ref . toString ( ) : `annot_${ idFactory . createObjId ( ) } ` ;
72
75
73
76
// Determine the annotation's subtype.
@@ -77,6 +80,7 @@ class AnnotationFactory {
77
80
// Return the right annotation object based on the subtype and field type.
78
81
const parameters = {
79
82
xref,
83
+ ref,
80
84
dict,
81
85
subtype,
82
86
id,
@@ -550,6 +554,10 @@ class Annotation {
550
554
} ) ;
551
555
} ) ;
552
556
}
557
+
558
+ async save ( evaluator , task , annotationStorage ) {
559
+ return null ;
560
+ }
553
561
}
554
562
555
563
/**
@@ -791,6 +799,7 @@ class WidgetAnnotation extends Annotation {
791
799
792
800
const dict = params . dict ;
793
801
const data = this . data ;
802
+ this . ref = params . ref ;
794
803
795
804
data . annotationType = AnnotationType . WIDGET ;
796
805
data . fieldName = this . _constructFieldName ( dict ) ;
@@ -953,6 +962,75 @@ class WidgetAnnotation extends Annotation {
953
962
) ;
954
963
}
955
964
965
+ async save ( evaluator , task , annotationStorage ) {
966
+ if ( this . data . fieldValue === annotationStorage [ this . data . id ] ) {
967
+ return null ;
968
+ }
969
+
970
+ let appearance = await this . _getAppearance (
971
+ evaluator ,
972
+ task ,
973
+ annotationStorage
974
+ ) ;
975
+ if ( appearance !== null ) {
976
+ const dict = evaluator . xref . fetchIfRef ( this . ref ) ;
977
+ if ( ! isDict ( dict ) ) {
978
+ return null ;
979
+ }
980
+
981
+ const bbox = [
982
+ 0 ,
983
+ 0 ,
984
+ this . data . rect [ 2 ] - this . data . rect [ 0 ] ,
985
+ this . data . rect [ 3 ] - this . data . rect [ 1 ] ,
986
+ ] ;
987
+
988
+ const newRef = evaluator . xref . getNewRef ( ) ;
989
+ const AP = new Dict ( null ) ;
990
+ AP . set ( "N" , newRef ) ;
991
+
992
+ const annotationString = annotationStorage [ this . data . id ] ;
993
+ const encrypt = evaluator . xref . encrypt ;
994
+ let transfOriginal = null ;
995
+ let transfNew = null ;
996
+ if ( encrypt ) {
997
+ transfOriginal = encrypt . createCipherTransform (
998
+ this . ref . num ,
999
+ this . ref . gen
1000
+ ) ;
1001
+ transfNew = encrypt . createCipherTransform ( newRef . num , newRef . gen ) ;
1002
+ appearance = transfNew . encryptString ( appearance ) ;
1003
+ }
1004
+
1005
+ dict . set ( "V" , annotationString ) ;
1006
+ dict . set ( "AP" , AP ) ;
1007
+ dict . set ( "M" , `D:${ getModificationDate ( ) } ` ) ;
1008
+
1009
+ const appearanceDict = new Dict ( null ) ;
1010
+ appearanceDict . set ( "Length" , appearance . length ) ;
1011
+ appearanceDict . set ( "Subtype" , Name . get ( "Form" ) ) ;
1012
+ appearanceDict . set ( "Resources" , this . fieldResources ) ;
1013
+ appearanceDict . set ( "BBox" , bbox ) ;
1014
+ appearanceDict . set ( "M" , `D:${ getModificationDate ( ) } ` ) ;
1015
+
1016
+ const bufferOriginal = [ `${ this . ref . num } 0 obj\n` ] ;
1017
+ writeDict ( dict , bufferOriginal , transfOriginal ) ;
1018
+ bufferOriginal . push ( "\nendobj\n" ) ;
1019
+
1020
+ const bufferNew = [ `${ newRef . num } ${ newRef . gen } obj\n` ] ;
1021
+ writeDict ( appearanceDict , bufferNew , transfNew ) ;
1022
+ bufferNew . push ( " stream\n" ) ;
1023
+ bufferNew . push ( appearance ) ;
1024
+ bufferNew . push ( "\nendstream\nendobj\n" ) ;
1025
+
1026
+ return [
1027
+ { ref : this . ref . num , data : bufferOriginal . join ( "" ) } ,
1028
+ { ref : newRef . num , data : bufferNew . join ( "" ) } ,
1029
+ ] ;
1030
+ }
1031
+ return null ;
1032
+ }
1033
+
956
1034
async _getAppearance ( evaluator , task , annotationStorage ) {
957
1035
const isPassword = this . hasFieldFlag ( AnnotationFieldFlag . PASSWORD ) ;
958
1036
if ( ! annotationStorage || isPassword ) {
@@ -1312,6 +1390,46 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
1312
1390
) ;
1313
1391
}
1314
1392
1393
+ async save ( evaluator , task , annotationStorage ) {
1394
+ if ( ! this . data . checkBox && ! this . data . radioButton ) {
1395
+ return null ;
1396
+ }
1397
+
1398
+ const defaultValue = this . data . fieldValue && this . data . fieldValue !== "Off" ;
1399
+ const isChecked = annotationStorage [ this . data . id ] ;
1400
+ if ( defaultValue === isChecked ) {
1401
+ return null ;
1402
+ }
1403
+
1404
+ const dict = evaluator . xref . fetchIfRef ( this . ref ) ;
1405
+ if ( ! isDict ( dict ) ) {
1406
+ return null ;
1407
+ }
1408
+
1409
+ const value = this . data . checkBox
1410
+ ? this . data . exportValue
1411
+ : this . data . buttonValue ;
1412
+ const name = Name . get ( isChecked ? value : "Off" ) ;
1413
+ dict . set ( "V" , name ) ;
1414
+ dict . set ( "AS" , name ) ;
1415
+ dict . set ( "M" , `D:${ getModificationDate ( ) } ` ) ;
1416
+
1417
+ const encrypt = evaluator . xref . encrypt ;
1418
+ let transfOriginal = null ;
1419
+ if ( encrypt ) {
1420
+ transfOriginal = encrypt . createCipherTransform (
1421
+ this . ref . num ,
1422
+ this . ref . gen
1423
+ ) ;
1424
+ }
1425
+
1426
+ const buffer = [ `${ this . ref . num } 0 obj\n` ] ;
1427
+ writeDict ( dict , buffer , transfOriginal ) ;
1428
+ buffer . push ( "\nendobj\n" ) ;
1429
+
1430
+ return [ { ref : this . ref . num , data : buffer . join ( "" ) } ] ;
1431
+ }
1432
+
1315
1433
_processCheckBox ( params ) {
1316
1434
if ( isName ( this . data . fieldValue ) ) {
1317
1435
this . data . fieldValue = this . data . fieldValue . name ;
0 commit comments