|
37 | 37 | TYPE_CHECKING, |
38 | 38 | Any, |
39 | 39 | Callable, |
| 40 | + Dict, |
40 | 41 | Optional, |
41 | 42 | Union, |
42 | 43 | cast, |
|
66 | 67 | ArrayObject, |
67 | 68 | ContentStream, |
68 | 69 | DecodedStreamObject, |
| 70 | + Destination, |
69 | 71 | DictionaryObject, |
70 | 72 | EncodedStreamObject, |
71 | 73 | IndirectObject, |
|
75 | 77 | PdfObject, |
76 | 78 | StreamObject, |
77 | 79 | TextStringObject, |
| 80 | + TreeObject, |
78 | 81 | is_null_or_none, |
79 | 82 | read_object, |
80 | 83 | ) |
@@ -138,6 +141,9 @@ def __init__( |
138 | 141 | elif password is not None: |
139 | 142 | raise PdfReadError("Not an encrypted file") |
140 | 143 |
|
| 144 | + # cache so we don't have to parse this over and over |
| 145 | + self._named_destinations: Optional[Dict[str, Destination]] = None |
| 146 | + |
141 | 147 | def _initialize_stream(self, stream: Union[StrByteType, Path]) -> None: |
142 | 148 | if hasattr(stream, "mode") and "b" not in stream.mode: |
143 | 149 | logger_warning( |
@@ -1274,3 +1280,18 @@ def _repr_mimebundle_( |
1274 | 1280 | data = {k: v for k, v in data.items() if k not in exclude} |
1275 | 1281 |
|
1276 | 1282 | return data |
| 1283 | + |
| 1284 | + def _get_named_destinations( |
| 1285 | + self, |
| 1286 | + tree: Union[TreeObject, None] = None, |
| 1287 | + retval: Optional[Dict[str, Destination]] = None, |
| 1288 | + ) -> Dict[str, Destination]: |
| 1289 | + """Override from PdfDocCommon. In the reader we can assume this is |
| 1290 | + static, but not in the writer. |
| 1291 | + """ |
| 1292 | + if tree or retval: |
| 1293 | + return PdfDocCommon._get_named_destinations(self, tree, retval) |
| 1294 | + |
| 1295 | + if self._named_destinations is None: |
| 1296 | + self._named_destinations = PdfDocCommon._get_named_destinations(self) |
| 1297 | + return self._named_destinations |
0 commit comments