From e0e71b7b6d459bbfaecb18a3a14acce6f85834c5 Mon Sep 17 00:00:00 2001 From: Martin Thoma Date: Sat, 19 Nov 2022 16:19:32 +0100 Subject: [PATCH] MAINT: Refactor Fit / Zoom parameters This is a breaking change that needs a major version bump --- PyPDF2/_merger.py | 37 ++++++--- PyPDF2/_reader.py | 10 +-- PyPDF2/_writer.py | 37 +++++---- PyPDF2/generic/__init__.py | 7 ++ PyPDF2/generic/_annotations.py | 37 ++------- PyPDF2/generic/_data_structures.py | 30 ++----- PyPDF2/generic/_fit.py | 121 +++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/modules/Fit.rst | 7 ++ tests/test_generic.py | 26 ++----- tests/test_merger.py | 52 +++++++++---- tests/test_writer.py | 60 ++++++++------ 12 files changed, 282 insertions(+), 143 deletions(-) create mode 100644 PyPDF2/generic/_fit.py create mode 100644 docs/modules/Fit.rst diff --git a/PyPDF2/_merger.py b/PyPDF2/_merger.py index 5a512ac68..49fd54065 100644 --- a/PyPDF2/_merger.py +++ b/PyPDF2/_merger.py @@ -54,9 +54,11 @@ from .constants import PagesAttributes as PA from .constants import TypArguments, TypFitArguments from .generic import ( + DEFAULT_FIT, ArrayObject, Destination, DictionaryObject, + Fit, FloatObject, IndirectObject, NameObject, @@ -188,7 +190,7 @@ def merge( outline_item_typ = OutlineItem( TextStringObject(outline_item), NumberObject(self.id_count), - NameObject(TypFitArguments.FIT), + Fit.fit(), ) self.outline += [outline_item_typ, outline] # type: ignore else: @@ -628,8 +630,7 @@ def add_outline_item( color: Optional[Tuple[float, float, float]] = None, bold: bool = False, italic: bool = False, - fit: FitType = "/Fit", - *args: ZoomArgType, + fit: Fit = DEFAULT_FIT, ) -> IndirectObject: """ Add an outline item (commonly referred to as a "Bookmark") to this PDF file. @@ -642,14 +643,19 @@ def add_outline_item( from 0.0 to 1.0 :param bool bold: Outline item font is bold :param bool italic: Outline item font is italic - :param str fit: The fit of the destination page. See - :meth:`add_link()` for details. + :param Fit fit: The fit of the destination page. """ writer = self.output if writer is None: raise RuntimeError(ERR_CLOSED_WRITER) return writer.add_outline_item( - title, pagenum, parent, color, bold, italic, fit, *args + title, + pagenum, + parent, + color, + bold, + italic, + fit, ) def addBookmark( @@ -669,7 +675,13 @@ def addBookmark( """ deprecate_with_replacement("addBookmark", "add_outline_item") return self.add_outline_item( - title, pagenum, parent, color, bold, italic, fit, *args + title, + pagenum, + parent, + color, + bold, + italic, + Fit(fit_type=fit, fit_args=args), ) def add_bookmark( @@ -689,7 +701,13 @@ def add_bookmark( """ deprecate_with_replacement("addBookmark", "add_outline_item") return self.add_outline_item( - title, pagenum, parent, color, bold, italic, fit, *args + title, + pagenum, + parent, + color, + bold, + italic, + Fit(fit_type=fit, fit_args=args), ) def addNamedDestination(self, title: str, pagenum: int) -> None: # pragma: no cover @@ -710,8 +728,7 @@ def add_named_destination(self, title: str, pagenum: int) -> None: dest = Destination( TextStringObject(title), NumberObject(pagenum), - NameObject(TypFitArguments.FIT_H), - NumberObject(826), + Fit.fit_horizontally(top=826), ) self.named_dests.append(dest) diff --git a/PyPDF2/_reader.py b/PyPDF2/_reader.py index 655278b8d..a0bbb9654 100644 --- a/PyPDF2/_reader.py +++ b/PyPDF2/_reader.py @@ -85,6 +85,7 @@ DictionaryObject, EncodedStreamObject, Field, + Fit, FloatObject, IndirectObject, NameObject, @@ -874,13 +875,12 @@ def _build_destination( ): page = NullObject() - typ = TextStringObject("/Fit") - return Destination(title, page, typ) + return Destination(title, page, Fit.fit()) else: page, typ = array[0:2] # type: ignore array = array[2:] try: - return Destination(title, page, typ, *array) # type: ignore + return Destination(title, page, Fit(fit_type=typ, fit_args=array)) # type: ignore except PdfReadError: logger_warning(f"Unknown destination: {title} {array}", __name__) if self.strict: @@ -888,9 +888,7 @@ def _build_destination( # create a link to first Page tmp = self.pages[0].indirect_ref indirect_ref = NullObject() if tmp is None else tmp - return Destination( - title, indirect_ref, TextStringObject("/Fit") # type: ignore - ) + return Destination(title, indirect_ref, Fit.fit()) # type: ignore def _build_outline_item(self, node: DictionaryObject) -> Optional[Destination]: dest, title, outline_item = None, None, None diff --git a/PyPDF2/_writer.py b/PyPDF2/_writer.py index 9ebda1182..e2f71dcad 100644 --- a/PyPDF2/_writer.py +++ b/PyPDF2/_writer.py @@ -82,6 +82,7 @@ from .constants import TrailerKeys as TK from .constants import TypFitArguments, UserAccessPermissions from .generic import ( + DEFAULT_FIT, AnnotationBuilder, ArrayObject, BooleanObject, @@ -90,6 +91,7 @@ DecodedStreamObject, Destination, DictionaryObject, + Fit, FloatObject, IndirectObject, NameObject, @@ -109,7 +111,6 @@ LayoutType, OutlineItemType, PagemodeType, - ZoomArgsType, ZoomArgType, ) @@ -1209,8 +1210,7 @@ def add_outline_item( color: Optional[Union[Tuple[float, float, float], str]] = None, bold: bool = False, italic: bool = False, - fit: FitType = "/Fit", - *args: ZoomArgType, + fit: Fit = DEFAULT_FIT, ) -> IndirectObject: """ Add an outline item (commonly referred to as a "Bookmark") to this PDF file. @@ -1223,18 +1223,13 @@ def add_outline_item( from 0.0 to 1.0 or as a Hex String (#RRGGBB) :param bool bold: Outline item font is bold :param bool italic: Outline item font is italic - :param str fit: The fit of the destination page. See - :meth:`add_link()` for details. + :param Fit fit: The fit of the destination page. """ page_ref = NumberObject(pagenum) - zoom_args: ZoomArgsType = [ - NullObject() if a is None else NumberObject(a) for a in args - ] dest = Destination( NameObject("/" + title + " outline item"), page_ref, - NameObject(fit), - *zoom_args, + fit, ) action_ref = self._add_object( @@ -1269,7 +1264,13 @@ def add_bookmark( """ deprecate_with_replacement("add_bookmark", "add_outline_item") return self.add_outline_item( - title, pagenum, parent, color, bold, italic, fit, *args + title, + pagenum, + parent, + color, + bold, + italic, + Fit(fit_type=fit, fit_args=args), ) def addBookmark( @@ -1290,7 +1291,13 @@ def addBookmark( """ deprecate_with_replacement("addBookmark", "add_outline_item") return self.add_outline_item( - title, pagenum, parent, color, bold, italic, fit, *args + title, + pagenum, + parent, + color, + bold, + italic, + Fit(fit_type=fit, fit_args=args), ) def add_outline(self) -> None: @@ -1616,8 +1623,7 @@ def add_link( rect=rect, border=border, target_page_index=pagedest, - fit=fit, - fit_args=args, + fit=Fit(fit_type=fit, fit_args=args), ) return self.add_annotation(page_number=pagenum, annotation=annotation) @@ -1869,8 +1875,7 @@ def add_annotation(self, page_number: int, annotation: Dict[str, Any]) -> None: dest = Destination( NameObject("/LinkName"), tmp["target_page_index"], - tmp["fit"], - *tmp["fit_args"], + Fit(fit_type=tmp["fit"], fit_args=tmp["fit_args"]), ) to_add[NameObject("/Dest")] = dest.dest_array diff --git a/PyPDF2/generic/__init__.py b/PyPDF2/generic/__init__.py index b0c60da88..2e9f1ed77 100644 --- a/PyPDF2/generic/__init__.py +++ b/PyPDF2/generic/__init__.py @@ -58,6 +58,7 @@ TreeObject, read_object, ) +from ._fit import Fit from ._outline import Bookmark, OutlineItem from ._rectangle import RectangleObject from ._utils import ( @@ -96,6 +97,9 @@ def createStringObject( return create_string_object(string, forced_encoding) +DEFAULT_FIT = Fit.fit() + + __all__ = [ # Base types "BooleanObject", @@ -109,6 +113,9 @@ def createStringObject( "ByteStringObject", # Annotations "AnnotationBuilder", + # Fit + "Fit", + "DEFAULT_FIT", # Data structures "ArrayObject", "DictionaryObject", diff --git a/PyPDF2/generic/_annotations.py b/PyPDF2/generic/_annotations.py index 003234d6b..bb46dd906 100644 --- a/PyPDF2/generic/_annotations.py +++ b/PyPDF2/generic/_annotations.py @@ -4,11 +4,11 @@ BooleanObject, FloatObject, NameObject, - NullObject, NumberObject, TextStringObject, ) from ._data_structures import ArrayObject, DictionaryObject +from ._fit import DEFAULT_FIT, Fit from ._rectangle import RectangleObject from ._utils import hex_to_rgb @@ -198,8 +198,7 @@ def link( border: Optional[ArrayObject] = None, url: Optional[str] = None, target_page_index: Optional[int] = None, - fit: FitType = "/Fit", - fit_args: Tuple[ZoomArgType, ...] = tuple(), + fit: Fit = DEFAULT_FIT, ) -> DictionaryObject: """ Add a link to the document. @@ -223,30 +222,7 @@ def link( :param str url: Link to a website (if you want to make an external link) :param int target_page_index: index of the page to which the link should go (if you want to make an internal link) - :param str fit: Page fit or 'zoom' option (see below). Additional arguments may need - to be supplied. Passing ``None`` will be read as a null value for that coordinate. - :param Tuple[int, ...] fit_args: Parameters for the fit argument. - - - .. list-table:: Valid ``fit`` arguments (see Table 8.2 of the PDF 1.7 reference for details) - :widths: 50 200 - - * - /Fit - - No additional arguments - * - /XYZ - - [left] [top] [zoomFactor] - * - /FitH - - [top] - * - /FitV - - [left] - * - /FitR - - [left] [bottom] [right] [top] - * - /FitB - - No additional arguments - * - /FitBH - - [top] - * - /FitBV - - [left] + :param Fit fit: Page fit or 'zoom' option. """ from ..types import BorderArrayType @@ -287,15 +263,12 @@ def link( } ) if is_internal: - fit_arg_ready = [ - NullObject() if a is None else NumberObject(a) for a in fit_args - ] # This needs to be updated later! dest_deferred = DictionaryObject( { "target_page_index": NumberObject(target_page_index), - "fit": NameObject(fit), - "fit_args": ArrayObject(fit_arg_ready), + "fit": NameObject(fit.fit_type), + "fit_args": fit.fit_args, } ) link_obj[NameObject("/Dest")] = dest_deferred diff --git a/PyPDF2/generic/_data_structures.py b/PyPDF2/generic/_data_structures.py index b5056ae14..8e6557bc4 100644 --- a/PyPDF2/generic/_data_structures.py +++ b/PyPDF2/generic/_data_structures.py @@ -65,6 +65,7 @@ PdfObject, TextStringObject, ) +from ._fit import Fit from ._utils import read_hex_string_from_stream, read_string_from_stream logger = logging.getLogger(__name__) @@ -1019,38 +1020,21 @@ class Destination(TreeObject): :param str title: Title of this destination. :param IndirectObject page: Reference to the page of this destination. Should be an instance of :class:`IndirectObject`. - :param str typ: How the destination is displayed. - :param args: Additional arguments may be necessary depending on the type. + :param Fit fit: How the destination is displayed. :raises PdfReadError: If destination type is invalid. - .. list-table:: Valid ``typ`` arguments (see PDF spec for details) - :widths: 50 50 - - * - /Fit - - No additional arguments - * - /XYZ - - [left] [top] [zoomFactor] - * - /FitH - - [top] - * - /FitV - - [left] - * - /FitR - - [left] [bottom] [right] [top] - * - /FitB - - No additional arguments - * - /FitBH - - [top] - * - /FitBV - - [left] + """ def __init__( self, title: str, page: Union[NumberObject, IndirectObject, NullObject, DictionaryObject], - typ: Union[str, NumberObject], - *args: Any, # ZoomArgType + fit: Fit, ) -> None: + typ = fit.fit_type + args = fit.fit_args + DictionaryObject.__init__(self) self[NameObject("/Title")] = TextStringObject(title) self[NameObject("/Page")] = page diff --git a/PyPDF2/generic/_fit.py b/PyPDF2/generic/_fit.py new file mode 100644 index 000000000..bae14e311 --- /dev/null +++ b/PyPDF2/generic/_fit.py @@ -0,0 +1,121 @@ +from typing import Literal, Tuple, TypeAlias, Union + +FitType: TypeAlias = Literal[ + "/Fit", "/XYZ", "/FitH", "/FitV", "/FitR", "/FitB", "/FitBH", "/FitBV" +] +ZoomArgType: TypeAlias = Union[None, float] # NumberObject, NullObject, + + +class Fit: + def __init__(self, fit_type: FitType, fit_args: Tuple[ZoomArgType, ...] = tuple()): + from ._base import NameObject, NullObject, NumberObject + + self.fit_type = NameObject(fit_type) + self.fit_args = [ + NullObject() if a is None or isinstance(a, NullObject) else NumberObject(a) + for a in fit_args + ] + + @classmethod + def xyz(cls, left=None, top=None, zoom=None) -> "Fit": + """ + Display the page designated by page, with the coordinates ( left , top ) + positioned at the upper-left corner of the window and the contents + of the page magnified by the factor zoom. + + A null value for any of the parameters left, top, or zoom specifies + that the current value of that parameter is to be retained unchanged. + + A zoom value of 0 has the same meaning as a null value. + """ + return Fit(fit_type="/XYZ", fit_args=(left, top, zoom)) + + @classmethod + def fit(cls) -> "Fit": + """ + Display the page designated by page, with its contents magnified just + enough to fit the entire page within the window both horizontally and + vertically. If the required horizontal and vertical magnification + factors are different, use the smaller of the two, centering the page + within the window in the other dimension. + """ + return Fit(fit_type="/Fit") + + @classmethod + def fit_horizontally(cls, top=None) -> "Fit": + """ + Display the page designated by page , with the vertical coordinate top + positioned at the top edge of the window and the contents of the page + magnified just enough to fit the entire width of the page within the + window. + + A null value for `top` specifies that the current value of that + parameter is to be retained unchanged. + """ + return Fit(fit_type="/FitH", fit_args=(top,)) + + @classmethod + def fit_vertically(cls, left=None) -> "Fit": + return Fit(fit_type="/FitV", fit_args=(left,)) + + @classmethod + def fit_rectangle(cls, left=None, bottom=None, right=None, top=None) -> "Fit": + """ + Display the page designated by page , with its contents magnified + just enough to fit the rectangle specified by the coordinates + left , bottom , right , and top entirely within the window + both horizontally and vertically. + + If the required horizontal and vertical magnification factors are + different, use the smaller of the two, centering the rectangle within + the window in the other dimension. + + A null value for any of the parameters may result in unpredictable + behavior. + """ + return Fit(fit_type="/FitR", fit_args=(left, bottom, right, top)) + + @classmethod + def fit_box(cls) -> "Fit": + """ + Display the page designated by page , with its contents magnified + just enough to fit its bounding box entirely within the window both + horizontally and vertically. If the required horizontal and vertical + magnification factors are different, use the smaller of the two, + centering the bounding box within the window in the other dimension. + """ + return Fit(fit_type="/FitB") + + @classmethod + def fit_box_horizontally(cls, top=None) -> "Fit": + """ + Display the page designated by page , with the vertical coordinate + top positioned at the top edge of the window and the contents of the + page magnified just enough to fit the entire width of its bounding box + within the window. + + A null value for top specifies that the current value of that parameter + is to be retained unchanged. + """ + return Fit(fit_type="/FitBH", fit_args=(top,)) + + @classmethod + def fit_box_vertically(cls, left=None) -> "Fit": + """ + Display the page designated by page , with the horizontal coordinate + left positioned at the left edge of the window and the contents of + the page magnified just enough to fit the entire height of its + bounding box within the window. + + A null value for left specifies that the current value of that + parameter is to be retained unchanged. + """ + return Fit(fit_type="/FitBV", fit_args=(left,)) + + def __str__(self): + if not self.fit_args: + return f"Fit({self.fit_type})" + return f"Fit({self.fit_type}, {self.fit_args})" + + +DEFAULT_FIT = Fit.fit() diff --git a/docs/index.rst b/docs/index.rst index 7ea2da726..d49314846 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -53,6 +53,7 @@ You can contribute to `PyPDF2 on GitHub `_. modules/Field modules/PageRange modules/AnnotationBuilder + modules/Fit .. toctree:: :caption: Developer Guide diff --git a/docs/modules/Fit.rst b/docs/modules/Fit.rst new file mode 100644 index 000000000..caec874bc --- /dev/null +++ b/docs/modules/Fit.rst @@ -0,0 +1,7 @@ +The Fit Class +------------- + +.. autoclass:: PyPDF2.generic.Fit + :members: + :undoc-members: + :show-inheritance: diff --git a/tests/test_generic.py b/tests/test_generic.py index 2bcc733d4..72a1000e8 100644 --- a/tests/test_generic.py +++ b/tests/test_generic.py @@ -7,7 +7,6 @@ from PyPDF2 import PdfMerger, PdfReader, PdfWriter from PyPDF2.constants import CheckboxRadioButtonAttributes -from PyPDF2.constants import TypFitArguments as TF from PyPDF2.errors import PdfReadError, PdfStreamError from PyPDF2.generic import ( AnnotationBuilder, @@ -16,6 +15,7 @@ ByteStringObject, Destination, DictionaryObject, + Fit, FloatObject, IndirectObject, NameObject, @@ -234,13 +234,7 @@ def test_NameObject(caplog): def test_destination_fit_r(): d = Destination( - TextStringObject("title"), - NullObject(), - NameObject(TF.FIT_R), - FloatObject(0), - FloatObject(0), - FloatObject(0), - FloatObject(0), + TextStringObject("title"), NullObject(), Fit.fit_rectangle(0, 0, 0, 0) ) assert d.title == NameObject("title") assert d.typ == "/FitR" @@ -254,25 +248,15 @@ def test_destination_fit_r(): def test_destination_fit_v(): - Destination(NameObject("title"), NullObject(), NameObject(TF.FIT_V), FloatObject(0)) + Destination(NameObject("title"), NullObject(), Fit.fit_vertically(left=0)) # Trigger Exception - Destination(NameObject("title"), NullObject(), NameObject(TF.FIT_V), None) - - -def test_destination_exception(): - with pytest.raises(PdfReadError) as exc: - Destination( - NameObject("title"), NullObject(), NameObject("foo"), FloatObject(0) - ) - assert exc.value.args[0] == "Unknown Destination Type: 'foo'" + Destination(NameObject("title"), NullObject(), Fit.fit_vertically(left=None)) def test_outline_item_write_to_stream(): stream = BytesIO() - oi = OutlineItem( - NameObject("title"), NullObject(), NameObject(TF.FIT_V), FloatObject(0) - ) + oi = OutlineItem(NameObject("title"), NullObject(), Fit.fit_vertically(left=0)) oi.write_to_stream(stream, None) stream.seek(0, 0) assert stream.read() == b"<<\n/Title (title)\n/Dest [ null /FitV 0 ]\n>>" diff --git a/tests/test_merger.py b/tests/test_merger.py index 6170bbba4..3e56005cd 100644 --- a/tests/test_merger.py +++ b/tests/test_merger.py @@ -7,7 +7,7 @@ import PyPDF2 from PyPDF2 import PdfMerger, PdfReader -from PyPDF2.generic import Destination +from PyPDF2.generic import Destination, Fit from . import get_pdf_from_url @@ -59,16 +59,34 @@ def merger_operate(merger): "deeper", 0, parent=outline_item, italic=True, bold=True ) merger.add_outline_item( - "Let's see", 2, oi2, (255, 255, 0), True, True, "/FitBV", 12 + "Let's see", 2, oi2, (255, 255, 0), True, True, Fit.fit_box_vertically(left=12) ) merger.add_outline_item( - "The XYZ fit", 0, outline_item, (255, 0, 15), True, True, "/XYZ", 10, 20, 3 + "The XYZ fit", + 0, + outline_item, + (255, 0, 15), + True, + True, + Fit.xyz(left=10, top=20, zoom=3), ) merger.add_outline_item( - "The FitH fit", 0, outline_item, (255, 0, 15), True, True, "/FitH", 10 + "The FitH fit", + 0, + outline_item, + (255, 0, 15), + True, + True, + Fit.fit_horizontally(top=10), ) merger.add_outline_item( - "The FitV fit", 0, outline_item, (255, 0, 15), True, True, "/FitV", 10 + "The FitV fit", + 0, + outline_item, + (255, 0, 15), + True, + True, + Fit.fit_vertically(left=10), ) merger.add_outline_item( "The FitR fit", @@ -77,20 +95,28 @@ def merger_operate(merger): (255, 0, 15), True, True, - "/FitR", - 10, - 20, - 30, - 40, + Fit.fit_rectangle(left=10, bottom=20, right=30, top=40), ) merger.add_outline_item( - "The FitB fit", 0, outline_item, (255, 0, 15), True, True, "/FitB" + "The FitB fit", 0, outline_item, (255, 0, 15), True, True, Fit.fit_box() ) merger.add_outline_item( - "The FitBH fit", 0, outline_item, (255, 0, 15), True, True, "/FitBH", 10 + "The FitBH fit", + 0, + outline_item, + (255, 0, 15), + True, + True, + Fit.fit_box_horizontally(top=10), ) merger.add_outline_item( - "The FitBV fit", 0, outline_item, (255, 0, 15), True, True, "/FitBV", 10 + "The FitBV fit", + 0, + outline_item, + (255, 0, 15), + True, + True, + Fit.fit_box_vertically(left=10), ) found_oi = merger.find_outline_item("nothing here") diff --git a/tests/test_writer.py b/tests/test_writer.py index 79bfd6f46..24112716e 100644 --- a/tests/test_writer.py +++ b/tests/test_writer.py @@ -7,6 +7,7 @@ from PyPDF2 import PageObject, PdfMerger, PdfReader, PdfWriter from PyPDF2.errors import PageSizeNotDefinedError from PyPDF2.generic import ( + Fit, IndirectObject, NameObject, RectangleObject, @@ -66,26 +67,46 @@ def writer_operate(writer): writer.remove_links() writer.add_outline_item_destination(page) oi = writer.add_outline_item( - "An outline item", 0, None, (255, 0, 15), True, True, "/FitBV", 10 + "An outline item", 0, None, (255, 0, 15), True, True, Fit.fit_box_vertically(10) ) writer.add_outline_item( - "The XYZ fit", 0, oi, (255, 0, 15), True, True, "/XYZ", 10, 20, 3 + "The XYZ fit", 0, oi, (255, 0, 15), True, True, Fit.xyz(left=10, top=20, zoom=3) ) writer.add_outline_item( - "The FitH fit", 0, oi, (255, 0, 15), True, True, "/FitH", 10 + "The FitH fit", 0, oi, (255, 0, 15), True, True, Fit.fit_horizontally(top=10) ) writer.add_outline_item( - "The FitV fit", 0, oi, (255, 0, 15), True, True, "/FitV", 10 + "The FitV fit", 0, oi, (255, 0, 15), True, True, Fit.fit_vertically(left=10) ) writer.add_outline_item( - "The FitR fit", 0, oi, (255, 0, 15), True, True, "/FitR", 10, 20, 30, 40 + "The FitR fit", + 0, + oi, + (255, 0, 15), + True, + True, + Fit.fit_rectangle(left=10, bottom=20, right=30, top=40), ) - writer.add_outline_item("The FitB fit", 0, oi, (255, 0, 15), True, True, "/FitB") writer.add_outline_item( - "The FitBH fit", 0, oi, (255, 0, 15), True, True, "/FitBH", 10 + "The FitB fit", 0, oi, (255, 0, 15), True, True, Fit.fit_box() ) writer.add_outline_item( - "The FitBV fit", 0, oi, (255, 0, 15), True, True, "/FitBV", 10 + "The FitBH fit", + 0, + oi, + (255, 0, 15), + True, + True, + Fit.fit_box_horizontally(top=10), + ) + writer.add_outline_item( + "The FitBV fit", + 0, + oi, + (255, 0, 15), + True, + True, + Fit.fit_box_vertically(left=10), ) writer.add_blank_page() writer.add_uri(2, "https://example.com", RectangleObject([0, 0, 100, 100])) @@ -454,11 +475,9 @@ def test_add_outline_item(): writer.add_page(page) outline_item = writer.add_outline_item( - "An outline item", 1, None, (255, 0, 15), True, True, "/Fit", 200, 0, None - ) - writer.add_outline_item( - "Another", 2, outline_item, None, False, False, "/Fit", 0, 0, None + "An outline item", 1, None, (255, 0, 15), True, True, Fit.fit() ) + writer.add_outline_item("Another", 2, outline_item, None, False, False, Fit.fit()) # write "output" to PyPDF2-output.pdf tmp_filename = "dont_commit_outline_item.pdf" @@ -558,20 +577,17 @@ def test_add_link(): 2, RectangleObject([0, 0, 100, 100]), border=[1, 2, 3, [4]], - fit="/Fit", + fit=Fit.fit(), ) writer.add_link( - 2, 3, RectangleObject([20, 30, 50, 80]), [1, 2, 3], "/FitH", None + 2, + 3, + RectangleObject([20, 30, 50, 80]), + [1, 2, 3], + Fit.fit_horizontally(top=None), ) writer.add_link( - 3, - 0, - "[ 200 300 250 350 ]", - [0, 0, 0], - "/XYZ", - 0, - 0, - 2, + 3, 0, "[ 200 300 250 350 ]", [0, 0, 0], Fit.xyz(left=0, top=0, zoom=2) ) writer.add_link( 3,