Skip to content

Commit

Permalink
MAINT: Refactor Fit / Zoom parameters
Browse files Browse the repository at this point in the history
This is a breaking change that needs a major version bump
  • Loading branch information
MartinThoma committed Nov 19, 2022
1 parent 1842c21 commit bf95314
Show file tree
Hide file tree
Showing 12 changed files with 273 additions and 142 deletions.
36 changes: 26 additions & 10 deletions PyPDF2/_merger.py
Expand Up @@ -66,6 +66,7 @@
TextStringObject,
TreeObject,
)
from .generic._fit import Fit
from .pagerange import PageRange, PageRangeSpec
from .types import FitType, LayoutType, OutlineType, PagemodeType, ZoomArgType

Expand Down Expand Up @@ -188,7 +189,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:
Expand Down Expand Up @@ -628,8 +629,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 = Fit.fit(),
) -> IndirectObject:
"""
Add an outline item (commonly referred to as a "Bookmark") to this PDF file.
Expand All @@ -642,14 +642,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()<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(
Expand All @@ -669,7 +674,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(
Expand All @@ -689,7 +700,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
Expand All @@ -710,8 +727,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)

Expand Down
10 changes: 4 additions & 6 deletions PyPDF2/_reader.py
Expand Up @@ -95,6 +95,7 @@
TreeObject,
read_object,
)
from .generic._fit import Fit
from .types import OutlineType, PagemodeType
from .xmp import XmpInformation

Expand Down Expand Up @@ -874,23 +875,20 @@ 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:
raise
# 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
Expand Down
35 changes: 20 additions & 15 deletions PyPDF2/_writer.py
Expand Up @@ -90,6 +90,7 @@
DecodedStreamObject,
Destination,
DictionaryObject,
Fit,
FloatObject,
IndirectObject,
NameObject,
Expand Down Expand Up @@ -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 = Fit.fit(),
) -> IndirectObject:
"""
Add an outline item (commonly referred to as a "Bookmark") to this PDF file.
Expand All @@ -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()<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(
Expand Down Expand Up @@ -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(
Expand All @@ -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:
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions PyPDF2/generic/__init__.py
Expand Up @@ -58,6 +58,7 @@
TreeObject,
read_object,
)
from ._fit import Fit
from ._outline import Bookmark, OutlineItem
from ._rectangle import RectangleObject
from ._utils import (
Expand Down Expand Up @@ -109,6 +110,8 @@ def createStringObject(
"ByteStringObject",
# Annotations
"AnnotationBuilder",
# Fit
"Fit",
# Data structures
"ArrayObject",
"DictionaryObject",
Expand Down
37 changes: 5 additions & 32 deletions PyPDF2/generic/_annotations.py
Expand Up @@ -4,11 +4,11 @@
BooleanObject,
FloatObject,
NameObject,
NullObject,
NumberObject,
TextStringObject,
)
from ._data_structures import ArrayObject, DictionaryObject
from ._fit import Fit
from ._rectangle import RectangleObject
from ._utils import hex_to_rgb

Expand Down Expand Up @@ -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 = Fit.fit(),
) -> DictionaryObject:
"""
Add a link to the document.
Expand All @@ -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 str fit: Page fit or 'zoom' option.
"""
from ..types import BorderArrayType

Expand Down Expand Up @@ -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
Expand Down
30 changes: 7 additions & 23 deletions PyPDF2/generic/_data_structures.py
Expand Up @@ -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__)
Expand Down Expand Up @@ -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<PyPDF2.generic.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
Expand Down

0 comments on commit bf95314

Please sign in to comment.