PyPDFForm 6.0.2__tar.gz → 6.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. {pypdfform-6.0.2 → pypdfform-6.1.1}/PKG-INFO +2 -2
  2. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/__init__.py +2 -3
  3. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/common.py +16 -2
  4. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/create.py +8 -2
  5. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/update.py +18 -7
  6. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/adapter.py +17 -9
  7. pypdfform-6.1.1/PyPDFForm/lib/annotations/link.py +98 -0
  8. pypdfform-6.1.1/PyPDFForm/lib/clone.py +643 -0
  9. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/constants.py +27 -0
  10. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/deprecation.py +47 -2
  11. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/base.py +53 -1
  12. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/checkbox.py +2 -0
  13. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/dropdown.py +2 -0
  14. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/text.py +12 -0
  15. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/image.py +4 -3
  16. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/template.py +51 -8
  17. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/utils.py +108 -26
  18. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/watermark.py +52 -83
  19. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/wrapper.py +154 -26
  20. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/PKG-INFO +2 -2
  21. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/SOURCES.txt +1 -1
  22. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/requires.txt +1 -1
  23. {pypdfform-6.0.2 → pypdfform-6.1.1}/pyproject.toml +2 -1
  24. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_functional.py +894 -4
  25. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_signature.py +14 -3
  26. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_widget_attr_trigger.py +61 -0
  27. pypdfform-6.0.2/PyPDFForm/lib/annotations/link.py +0 -68
  28. pypdfform-6.0.2/PyPDFForm/lib/types.py +0 -64
  29. {pypdfform-6.0.2 → pypdfform-6.1.1}/LICENSE +0 -0
  30. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/__init__.py +0 -0
  31. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/entry.py +0 -0
  32. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/inspect.py +0 -0
  33. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/remove.py +0 -0
  34. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/root.py +0 -0
  35. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/schemas/__init__.py +0 -0
  36. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/schemas/create.py +0 -0
  37. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/cli/schemas/update.py +0 -0
  38. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/__init__.py +0 -0
  39. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/annotations/__init__.py +0 -0
  40. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/annotations/base.py +0 -0
  41. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/annotations/stamp.py +0 -0
  42. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/annotations/text.py +0 -0
  43. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/annotations/text_markup.py +0 -0
  44. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/assets/__init__.py +0 -0
  45. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/assets/blank.py +0 -0
  46. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/coordinate.py +0 -0
  47. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/egress.py +0 -0
  48. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/filler.py +0 -0
  49. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/font.py +0 -0
  50. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/hooks.py +0 -0
  51. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/image.py +0 -0
  52. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/__init__.py +0 -0
  53. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/image.py +0 -0
  54. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/radio.py +0 -0
  55. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/middleware/signature.py +0 -0
  56. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/patterns.py +0 -0
  57. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/__init__.py +0 -0
  58. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/circle.py +0 -0
  59. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/ellipse.py +0 -0
  60. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/line.py +0 -0
  61. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/rect.py +0 -0
  62. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/raw/text.py +0 -0
  63. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/__init__.py +0 -0
  64. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/base.py +0 -0
  65. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/checkbox.py +0 -0
  66. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/dropdown.py +0 -0
  67. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/image.py +0 -0
  68. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/radio.py +0 -0
  69. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/signature.py +0 -0
  70. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm/lib/widgets/text.py +0 -0
  71. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/dependency_links.txt +0 -0
  72. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/entry_points.txt +0 -0
  73. {pypdfform-6.0.2 → pypdfform-6.1.1}/PyPDFForm.egg-info/top_level.txt +0 -0
  74. {pypdfform-6.0.2 → pypdfform-6.1.1}/README.md +0 -0
  75. {pypdfform-6.0.2 → pypdfform-6.1.1}/setup.cfg +0 -0
  76. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_bulk_create_fields.py +0 -0
  77. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_create_widget.py +0 -0
  78. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_draw_elements.py +0 -0
  79. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_dropdown.py +0 -0
  80. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_extract_middleware_attributes.py +0 -0
  81. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_fill_max_length_text_field.py +0 -0
  82. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_font_related.py +0 -0
  83. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_generate_appearance_streams.py +0 -0
  84. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_js.py +0 -0
  85. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_need_appearances.py +0 -0
  86. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_paragraph.py +0 -0
  87. {pypdfform-6.0.2 → pypdfform-6.1.1}/tests/test_use_full_widget_name.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPDFForm
3
- Version: 6.0.2
3
+ Version: 6.1.1
4
4
  Summary: The Python library & CLI for PDF forms.
5
5
  Author: Jinge Li
6
6
  License-Expression: MIT
@@ -28,7 +28,7 @@ Requires-Dist: cryptography<51.0.0,>=50.0.0
28
28
  Requires-Dist: fonttools<5.0.0,>=4.63.0
29
29
  Requires-Dist: pikepdf<11.0.0,>=10.7.2
30
30
  Requires-Dist: pillow<14.0.0,>=12.2.0
31
- Requires-Dist: pypdf<7.0.0,>=6.12.2
31
+ Requires-Dist: pypdf<7.0.0,>=6.19.0
32
32
  Requires-Dist: reportlab<6.0.0,>=4.5.1
33
33
  Provides-Extra: cli
34
34
  Requires-Dist: typer<1.0.0,>=0.26.1; extra == "cli"
@@ -16,15 +16,14 @@ PyPDFForm aims to make PDF form automation straightforward whether it is used
16
16
  from Python code or from the command line.
17
17
  """
18
18
 
19
- __version__ = "6.0.2"
19
+ __version__ = "6.1.1"
20
20
 
21
21
  from .lib.annotations import Annotations
22
22
  from .lib.assets.blank import BlankPage
23
23
  from .lib.middleware import Widgets
24
24
  from .lib.raw import RawElements
25
- from .lib.types import PdfArray
26
25
  from .lib.widgets import Fields
27
- from .lib.wrapper import PdfWrapper
26
+ from .lib.wrapper import PdfArray, PdfWrapper
28
27
 
29
28
  __all__ = [
30
29
  "PdfWrapper",
@@ -312,6 +312,7 @@ def create_elements_from_file(
312
312
  options_param_hint: str,
313
313
  output: Path | None = None,
314
314
  element_type: str | None = None,
315
+ input_errors: tuple[type[Exception], ...] = (),
315
316
  ) -> None:
316
317
  """
317
318
  Creates PDF elements from a data file or command-line options.
@@ -321,7 +322,8 @@ def create_elements_from_file(
321
322
  from the additional command-line options stored in ``ctx.args``. The data
322
323
  file takes precedence when both input forms are supplied. Each definition
323
324
  is constructed after optional font registration and passed to `method_name`
324
- on `PdfWrapper`.
325
+ on `PdfWrapper`. Errors of the `input_errors` types raised by that method
326
+ are reported against the input form that was used, without writing output.
325
327
 
326
328
  Args:
327
329
  pdf (Path): The path to the input PDF file.
@@ -342,6 +344,9 @@ def create_elements_from_file(
342
344
  omitted, the input PDF is overwritten. Defaults to None.
343
345
  element_type (str, optional): Element type selected for command-line
344
346
  input. Defaults to None.
347
+ input_errors (tuple[type[Exception], ...], optional): Exception types
348
+ raised by `method_name` for invalid element definitions. Defaults to
349
+ an empty tuple.
345
350
  """
346
351
  if data is not None:
347
352
  input_data = load_data_file(data, schema, file_param_hint)
@@ -370,4 +375,13 @@ def create_elements_from_file(
370
375
  handle_font_registration(obj, each, registered_font)
371
376
  ungrouped_input.append(element_map[k](**each))
372
377
 
373
- getattr(obj, method_name)(ungrouped_input).write(output or pdf)
378
+ try:
379
+ result = getattr(obj, method_name)(ungrouped_input)
380
+ except input_errors as exc:
381
+ cli_bad_parameter(
382
+ str(exc),
383
+ param_hint=file_param_hint if data is not None else options_param_hint,
384
+ cause=exc,
385
+ )
386
+
387
+ result.write(output or pdf)
@@ -126,7 +126,11 @@ def extract(
126
126
  The command validates that the requested end page does not precede the
127
127
  start page, converts the 1-based CLI page numbers into the slice expected
128
128
  by `PdfWrapper.pages`, and writes the extracted pages to the required
129
- output path.
129
+ output path. Each page is extracted separately, so links and other GoTo
130
+ actions to other pages are removed, and fields shared with other pages keep
131
+ only their widgets on each page. A `ValueError` from `PdfWrapper.pages`
132
+ for other references to another page's content is not converted, so the
133
+ command exits with an error before writing the output.
130
134
 
131
135
  Args:
132
136
  ctx (typer.Context): Typer context containing global `PdfWrapper`
@@ -332,7 +336,8 @@ def annotation(
332
336
  The command maps input groups such as `text`, `link`, and `highlight` to
333
337
  annotation classes, validates the input against the CLI annotation schema,
334
338
  creates the corresponding annotation objects, and calls
335
- `PdfWrapper.annotate` before writing the modified PDF. A data file can
339
+ `PdfWrapper.annotate` before writing the modified PDF. A link to a page
340
+ outside the PDF is reported as a parameter error. A data file can
336
341
  define multiple annotations grouped by type. Without `--file`, `--type` and
337
342
  the annotation options define one annotation. The data file takes
338
343
  precedence when both input forms are supplied.
@@ -368,6 +373,7 @@ def annotation(
368
373
  options_param_hint="annotation options",
369
374
  output=output,
370
375
  element_type=element_type,
376
+ input_errors=(ValueError,),
371
377
  )
372
378
 
373
379
 
@@ -297,9 +297,10 @@ def field(
297
297
 
298
298
  The command validates the input against the field update schema, loads the
299
299
  PDF with the global CLI options stored in `ctx.obj`, resolves each field
300
- name, registers any referenced fonts once per invocation, assigns the
301
- requested widget properties, and writes the modified PDF to the requested
302
- output path or back to the input file. A data file can update multiple
300
+ name, checks that each field type supports its requested properties,
301
+ registers any referenced fonts once per invocation, assigns the requested
302
+ widget properties, and writes the modified PDF to the requested output path
303
+ or back to the input file. A data file can update multiple
303
304
  fields. Without `--file`, `--field` and the property options update one
304
305
  field. The data file takes precedence when both input forms are supplied.
305
306
 
@@ -315,8 +316,9 @@ def field(
315
316
  Defaults to None.
316
317
 
317
318
  Raises:
318
- typer.BadParameter: Raised when the input file is invalid or a requested
319
- field does not exist.
319
+ typer.BadParameter: Raised when the input file is invalid, a requested
320
+ field does not exist, or a field type does not support a requested
321
+ property.
320
322
  """
321
323
  if data is not None:
322
324
  input_data = load_data_file(data, FIELD_SCHEMA, "--file")
@@ -337,12 +339,21 @@ def field(
337
339
  field_param_hint = "--field"
338
340
 
339
341
  obj = PdfWrapper(str(pdf), **ctx.obj)
340
- registered_font = {}
342
+ field_widgets = {}
341
343
  for k, each in input_data.items():
342
344
  field_widget = get_widget(obj, k, field_param_hint)
345
+ for param in each:
346
+ try:
347
+ field_widget.check_property_supported(param)
348
+ except AttributeError as exc:
349
+ cli_bad_parameter(str(exc), param_hint=field_param_hint, cause=exc)
350
+ field_widgets[k] = field_widget
351
+
352
+ registered_font = {}
353
+ for k, each in input_data.items():
343
354
  handle_font_registration(obj, each, registered_font)
344
355
  for param, v in each.items():
345
- setattr(field_widget, param, v)
356
+ setattr(field_widgets[k], param, v)
346
357
 
347
358
  obj.write(output or pdf)
348
359
 
@@ -10,6 +10,7 @@ forms. The module ensures that the input is properly converted into a byte
10
10
  stream before further processing.
11
11
  """
12
12
 
13
+ from os import PathLike
13
14
  from os.path import isfile
14
15
  from typing import Any, BinaryIO
15
16
 
@@ -32,7 +33,7 @@ def readable(obj: Any) -> bool:
32
33
 
33
34
 
34
35
  def fp_or_f_obj_or_stream_to_stream(
35
- fp_or_f_obj_or_stream: bytes | str | BinaryIO,
36
+ fp_or_f_obj_or_stream: bytes | str | PathLike | BinaryIO,
36
37
  ) -> bytes:
37
38
  """
38
39
  Adapt a file path, file object, or stream to a byte stream.
@@ -40,30 +41,37 @@ def fp_or_f_obj_or_stream_to_stream(
40
41
  This function takes a file path, a file object, or a byte stream and adapts it to a consistent byte stream.
41
42
  It handles different input types, including:
42
43
  - byte streams (bytes)
43
- - file paths (str)
44
+ - file paths (str or PathLike)
44
45
  - file-like objects with a read() method (BinaryIO)
45
- Unsupported inputs and string paths that do not point to files are treated
46
- as empty input and return ``b""``.
46
+ Paths are opened directly, so a missing path raises ``FileNotFoundError``.
47
+ Empty bytes and empty readable objects are returned as ``b""``.
47
48
 
48
49
  Args:
49
- fp_or_f_obj_or_stream (bytes | str | BinaryIO): The input to adapt.
50
- It can be a byte stream, a file path (string), or a file object.
50
+ fp_or_f_obj_or_stream (bytes | str | PathLike | BinaryIO): The input to adapt.
51
+ It can be a byte stream, a file path, or a file object.
51
52
 
52
53
  Returns:
53
54
  bytes: The byte stream representation of the input.
54
- Returns an empty byte string if the file path does not exist.
55
+
56
+ Raises:
57
+ OSError: If a file path cannot be opened, such as ``FileNotFoundError``
58
+ for a missing path.
59
+ TypeError: If the input is not bytes, a file path, or a readable object.
55
60
  """
56
61
  # not cached to handle writing to the same disk file
57
- result = b""
58
62
  if isinstance(fp_or_f_obj_or_stream, bytes):
59
63
  result = fp_or_f_obj_or_stream
60
64
 
61
65
  elif readable(fp_or_f_obj_or_stream):
62
66
  result = fp_or_f_obj_or_stream.read()
63
67
 
64
- elif isinstance(fp_or_f_obj_or_stream, str) and isfile(fp_or_f_obj_or_stream):
68
+ elif isinstance(fp_or_f_obj_or_stream, (str, PathLike)):
65
69
  with open(fp_or_f_obj_or_stream, "rb") as _file:
66
70
  result = _file.read()
71
+
72
+ else:
73
+ msg = f"Expected bytes, a file path, or a readable binary stream, got {type(fp_or_f_obj_or_stream).__name__}."
74
+ raise TypeError(msg)
67
75
  return result
68
76
 
69
77
 
@@ -0,0 +1,98 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ This module defines the class for link annotations in PyPDFForm.
4
+
5
+ It provides a structure for representing and interacting with PDF link
6
+ annotations, which allow users to click and navigate to a URI or an internal page.
7
+
8
+ Classes:
9
+ - `LinkAnnotation`: A dataclass representing the properties of a PDF link annotation.
10
+ """
11
+
12
+ from dataclasses import dataclass
13
+ from typing import Optional, Sequence
14
+
15
+ from pypdf.generic import (
16
+ ArrayObject,
17
+ DictionaryObject,
18
+ IndirectObject,
19
+ NameObject,
20
+ TextStringObject,
21
+ )
22
+
23
+ from ..constants import A, Link, S
24
+ from .base import Annotation
25
+
26
+
27
+ @dataclass
28
+ class LinkAnnotation(Annotation):
29
+ """
30
+ A dataclass representing the properties of a PDF link annotation.
31
+
32
+ This class extends the `Annotation` base class to specifically handle
33
+ link annotations, including the target URI or an internal page.
34
+
35
+ Attributes:
36
+ uri (str): The URI that the link annotation points to. Takes precedence
37
+ over `page` when both are set. Defaults to None.
38
+ page (int): The 1-based page number in the same PDF that the link
39
+ annotation points to. Defaults to None.
40
+ """
41
+
42
+ _annotation_type: str = Link
43
+
44
+ uri: Optional[str] = None
45
+ page: Optional[int] = None
46
+
47
+ def get_specific_properties(self) -> dict:
48
+ """
49
+ Gets properties specific to the link annotation.
50
+
51
+ This method extends the base properties with a URI action. A link to
52
+ an internal page needs the pages of the target PDF, so its destination
53
+ is built separately by `get_destination`.
54
+
55
+ Returns:
56
+ dict: A dictionary of PDF properties specific to the link annotation.
57
+ """
58
+ result = super().get_specific_properties()
59
+ if self.uri is not None:
60
+ result[NameObject(A)] = DictionaryObject(
61
+ {
62
+ NameObject(S): NameObject("/URI"),
63
+ NameObject("/URI"): TextStringObject(self.uri),
64
+ }
65
+ )
66
+
67
+ return result
68
+
69
+ def get_destination(
70
+ self, page_references: Sequence[IndirectObject]
71
+ ) -> Optional[ArrayObject]:
72
+ """
73
+ Gets the destination of a link to an internal page.
74
+
75
+ A destination in the same PDF must refer to the target page object
76
+ rather than a page index, which is reserved for destinations in other
77
+ PDFs. The 1-based `page` is resolved against the page references of the
78
+ PDF that will contain the link.
79
+
80
+ Args:
81
+ page_references (Sequence[IndirectObject]): References to the pages
82
+ of the PDF that will contain the link, in page order.
83
+
84
+ Returns:
85
+ Optional[ArrayObject]: The destination that fits the target page in
86
+ the window, or None if the link has a URI or no page.
87
+
88
+ Raises:
89
+ ValueError: If `page` is outside the pages of the PDF.
90
+ """
91
+ if self.uri is not None or self.page is None:
92
+ return None
93
+
94
+ if not 1 <= self.page <= len(page_references):
95
+ msg = f"Link page {self.page} must satisfy 1 <= page <= {len(page_references)}."
96
+ raise ValueError(msg)
97
+
98
+ return ArrayObject([page_references[self.page - 1], NameObject("/Fit")])