13
13
* limitations under the License.
14
14
*/
15
15
16
- import { Dict , isName , Name , Ref } from "./primitives .js" ;
17
- import { stringToPDFString , warn } from "../shared/util .js" ;
16
+ import { AnnotationPrefix , stringToPDFString , warn } from "../shared/util .js" ;
17
+ import { Dict , isName , Name , Ref , RefSetCache } from "./primitives .js" ;
18
18
import { NumberTree } from "./name_number_tree.js" ;
19
19
20
20
const MAX_DEPTH = 40 ;
21
21
22
22
const StructElementType = {
23
- PAGE_CONTENT : "PAGE_CONTENT" ,
24
- STREAM_CONTENT : "STREAM_CONTENT" ,
25
- OBJECT : "OBJECT" ,
26
- ELEMENT : "ELEMENT" ,
23
+ PAGE_CONTENT : 1 ,
24
+ STREAM_CONTENT : 2 ,
25
+ OBJECT : 3 ,
26
+ ANNOTATION : 4 ,
27
+ ELEMENT : 5 ,
27
28
} ;
28
29
29
30
class StructTreeRoot {
30
31
constructor ( rootDict ) {
31
32
this . dict = rootDict ;
32
33
this . roleMap = new Map ( ) ;
34
+ this . structParentIds = null ;
33
35
}
34
36
35
37
init ( ) {
36
38
this . readRoleMap ( ) ;
37
39
}
38
40
41
+ #addIdToPage( pageRef , id , type ) {
42
+ if ( ! ( pageRef instanceof Ref ) || id < 0 ) {
43
+ return ;
44
+ }
45
+ this . structParentIds ||= new RefSetCache ( ) ;
46
+ let ids = this . structParentIds . get ( pageRef ) ;
47
+ if ( ! ids ) {
48
+ ids = [ ] ;
49
+ this . structParentIds . put ( pageRef , ids ) ;
50
+ }
51
+ ids . push ( [ id , type ] ) ;
52
+ }
53
+
54
+ addAnnotationIdToPage ( pageRef , id ) {
55
+ this . #addIdToPage( pageRef , id , StructElementType . ANNOTATION ) ;
56
+ }
57
+
39
58
readRoleMap ( ) {
40
59
const roleMapDict = this . dict . get ( "RoleMap" ) ;
41
60
if ( ! ( roleMapDict instanceof Dict ) ) {
@@ -129,12 +148,10 @@ class StructElementNode {
129
148
if ( this . tree . pageDict . objId !== pageObjId ) {
130
149
return null ;
131
150
}
151
+ const kidRef = kidDict . getRaw ( "Stm" ) ;
132
152
return new StructElement ( {
133
153
type : StructElementType . STREAM_CONTENT ,
134
- refObjId :
135
- kidDict . getRaw ( "Stm" ) instanceof Ref
136
- ? kidDict . getRaw ( "Stm" ) . toString ( )
137
- : null ,
154
+ refObjId : kidRef instanceof Ref ? kidRef . toString ( ) : null ,
138
155
pageObjId,
139
156
mcid : kidDict . get ( "MCID" ) ,
140
157
} ) ;
@@ -144,12 +161,10 @@ class StructElementNode {
144
161
if ( this . tree . pageDict . objId !== pageObjId ) {
145
162
return null ;
146
163
}
164
+ const kidRef = kidDict . getRaw ( "Obj" ) ;
147
165
return new StructElement ( {
148
166
type : StructElementType . OBJECT ,
149
- refObjId :
150
- kidDict . getRaw ( "Obj" ) instanceof Ref
151
- ? kidDict . getRaw ( "Obj" ) . toString ( )
152
- : null ,
167
+ refObjId : kidRef instanceof Ref ? kidRef . toString ( ) : null ,
153
168
pageObjId,
154
169
} ) ;
155
170
}
@@ -186,7 +201,7 @@ class StructTreePage {
186
201
this . nodes = [ ] ;
187
202
}
188
203
189
- parse ( ) {
204
+ parse ( pageRef ) {
190
205
if ( ! this . root || ! this . rootDict ) {
191
206
return ;
192
207
}
@@ -196,18 +211,42 @@ class StructTreePage {
196
211
return ;
197
212
}
198
213
const id = this . pageDict . get ( "StructParents" ) ;
199
- if ( ! Number . isInteger ( id ) ) {
214
+ const ids =
215
+ pageRef instanceof Ref && this . root . structParentIds ?. get ( pageRef ) ;
216
+ if ( ! Number . isInteger ( id ) && ! ids ) {
200
217
return ;
201
218
}
219
+
220
+ const map = new Map ( ) ;
202
221
const numberTree = new NumberTree ( parentTree , this . rootDict . xref ) ;
203
- const parentArray = numberTree . get ( id ) ;
204
- if ( ! Array . isArray ( parentArray ) ) {
222
+
223
+ if ( Number . isInteger ( id ) ) {
224
+ const parentArray = numberTree . get ( id ) ;
225
+ if ( Array . isArray ( parentArray ) ) {
226
+ for ( const ref of parentArray ) {
227
+ if ( ref instanceof Ref ) {
228
+ this . addNode ( this . rootDict . xref . fetch ( ref ) , map ) ;
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ if ( ! ids ) {
205
235
return ;
206
236
}
207
- const map = new Map ( ) ;
208
- for ( const ref of parentArray ) {
209
- if ( ref instanceof Ref ) {
210
- this . addNode ( this . rootDict . xref . fetch ( ref ) , map ) ;
237
+ for ( const [ elemId , type ] of ids ) {
238
+ const obj = numberTree . get ( elemId ) ;
239
+ if ( obj ) {
240
+ const elem = this . addNode ( this . rootDict . xref . fetchIfRef ( obj ) , map ) ;
241
+ if (
242
+ elem ?. kids ?. length === 1 &&
243
+ elem . kids [ 0 ] . type === StructElementType . OBJECT
244
+ ) {
245
+ // The node in the struct tree is wrapping an object (annotation
246
+ // or xobject), so we need to update the type of the node to match
247
+ // the type of the object.
248
+ elem . kids [ 0 ] . type = type ;
249
+ }
211
250
}
212
251
}
213
252
}
@@ -322,6 +361,11 @@ class StructTreePage {
322
361
type : "object" ,
323
362
id : kid . refObjId ,
324
363
} ) ;
364
+ } else if ( kid . type === StructElementType . ANNOTATION ) {
365
+ obj . children . push ( {
366
+ type : "annotation" ,
367
+ id : `${ AnnotationPrefix } ${ kid . refObjId } ` ,
368
+ } ) ;
325
369
}
326
370
}
327
371
}
0 commit comments