Skip to content

Commit

Permalink
Adding optional title parameter to text_annotation() (#1302)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas-C authored Nov 14, 2024
1 parent 304d5ca commit c3ae742
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 9 deletions.
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[MESSAGES CONTROL]
max-line-length=150
max-line-length=155

# Disable superflous / noisy rules:
disable = attribute-defined-outside-init, consider-using-max-builtin, consider-using-min-builtin, invalid-name, method-hidden, missing-docstring, multiple-imports, too-few-public-methods, too-many-arguments, too-many-instance-attributes, too-many-nested-blocks, too-many-branches, too-many-lines, too-many-locals, too-many-positional-arguments, too-many-public-methods, too-many-statements, use-dict-literal, wrong-import-order
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This can also be enabled programmatically with `warnings.simplefilter('default',
* new optional parameter `border` for table cells [issue #1192](https://github.com/py-pdf/fpdf2/issues/1192) users can define specific borders (left, right, top, bottom) for individual cells
* [`FPDF.write_html()`](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.write_html): now parses `<title>` tags to set the [document title](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.set_title). By default, it is added as PDF metadata, but not rendered in the document body. However, this can be enabled by passing `render_title_tag=True` to `FPDF.write_html()`.
* support for LZWDecode compression [issue #1271](https://github.com/py-pdf/fpdf2/issues/1271)
* [text_annotation()](https://py-pdf.github.io/fpdf2/fpdf/fpdf.html#fpdf.fpdf.FPDF.text_annotation) has a new optional `title` parameter
### Fixed
* `FPDF.set_text_shaping(False)` was broken since version 2.7.8 and is now working properly - [issue #1287](https://github.com/py-pdf/fpdf2/issues/1287)
* fixed bug where cells with `rowspan`, `colspan` > 1 and null text were not displayed properly - [issue #1293](https://github.com/py-pdf/fpdf2/issues/1293)
Expand Down
2 changes: 1 addition & 1 deletion docs/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ There is a useful one-page example Python module with docstrings illustrating ho

To preview the Markdown documentation, launch a local rendering server with:

mkdocs serve
mkdocs serve --open

To preview the API documentation, launch a local rendering server with:

Expand Down
6 changes: 4 additions & 2 deletions docs/Metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ from fpdf import FPDF_VERSION
with pikepdf.open(sys.argv[1], allow_overwriting_input=True) as pdf:
with pdf.open_metadata(set_pikepdf_as_editor=False) as meta:
meta["dc:title"] = "Title"
meta["dc:description"] = "Description"
meta["dc:language"] = "en-US"
meta["dc:creator"] = ["Author1", "Author2"]
meta["dc:description"] = "Description"
meta["dc:subject"] = "keyword1 keyword2 keyword3"
meta["pdf:Keywords"] = "keyword1 keyword2 keyword3"
meta["pdf:Producer"] = f"py-pdf/fpdf{FPDF_VERSION}"
meta["xmp:CreatorTool"] = __file__
meta["xmp:MetadataDate"] = datetime.now(datetime.utcnow().astimezone().tzinfo).isoformat()
meta["xmp:CreateDate"] = datetime.now(datetime.utcnow().astimezone().tzinfo).isoformat()
pdf.save()
```
22 changes: 22 additions & 0 deletions fpdf/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ class EncryptionMethod(Enum):

class TextDirection(CoerciveEnum):
"Text rendering direction for text shaping"

LTR = intern("LTR")
"left to right"

Expand All @@ -1006,3 +1007,24 @@ class TextDirection(CoerciveEnum):

BTT = intern("BTT")
"bottom to top"


class Duplex(CoerciveEnum):
"The paper handling option that shall be used when printing the file from the print dialog."

Simplex = Name("Simplex")
"Print single-sided"

DuplexFlipShortEdge = Name("DuplexFlipShortEdge")
"Duplex and flip on the short edge of the sheet"

DuplexFlipLongEdge = Name("DuplexFlipLongEdge")
"Duplex and flip on the long edge of the sheet"


class PageBoundaries(CoerciveEnum):
ArtBox = Name("ArtBox")
BleedBox = Name("BleedBox")
CropBox = Name("CropBox")
MediaBox = Name("MediaBox")
TrimBox = Name("TrimBox")
5 changes: 4 additions & 1 deletion fpdf/fpdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -2320,7 +2320,7 @@ def file_attachment_annotation(

@check_page
def text_annotation(
self, x, y, text, w=1, h=1, name=None, flags=DEFAULT_ANNOT_FLAGS
self, x, y, text, w=1, h=1, name=None, flags=DEFAULT_ANNOT_FLAGS, title=""
):
"""
Puts a text annotation on a rectangular area of the page.
Expand All @@ -2333,6 +2333,8 @@ def text_annotation(
h (float): optional height of the link rectangle
name (fpdf.enums.AnnotationName, str): optional icon that shall be used in displaying the annotation
flags (Tuple[fpdf.enums.AnnotationFlag], Tuple[str]): optional list of flags defining annotation properties
title (str): the text label that shall be displayed in the title bar of the annotation’s
pop-up window when open and active. This entry shall identify the user who added the annotation.
"""
annotation = AnnotationDict(
"Text",
Expand All @@ -2343,6 +2345,7 @@ def text_annotation(
contents=text,
name=AnnotationName.coerce(name) if name else None,
flags=tuple(AnnotationFlag.coerce(flag) for flag in flags),
title=title,
)
self.pages[self.page].annots.append(annotation)
return annotation
Expand Down
128 changes: 124 additions & 4 deletions fpdf/prefs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .enums import PageMode
from .enums import TextDirection, Duplex, PageBoundaries, PageMode
from .syntax import build_obj_dict, create_dictionary_string


Expand All @@ -14,6 +14,14 @@ def __init__(
center_window=False,
display_doc_title=False,
non_full_screen_page_mode=PageMode.USE_NONE,
num_copies=None,
print_page_range=None,
direction=None,
duplex=None,
view_area=None,
view_clip=None,
print_area=None,
print_clip=None,
):
self.hide_toolbar = hide_toolbar
"A flag specifying whether to hide the conforming reader’s tool bars when the document is active"
Expand All @@ -34,14 +42,56 @@ def __init__(
taken from the Title entry of the document information dictionary.
If false, the title bar should instead display the name of the PDF file containing the document.
"""
self.non_full_screen_page_mode = PageMode.coerce(non_full_screen_page_mode)
self.non_full_screen_page_mode = non_full_screen_page_mode
if self.non_full_screen_page_mode in (
PageMode.FULL_SCREEN,
PageMode.USE_ATTACHMENTS,
):
raise ValueError(
f"{self.non_full_screen_page_mode} is not a support value for NonFullScreenPageMode"
f"{self.non_full_screen_page_mode} is not a supported value for NonFullScreenPageMode"
)
self.num_copies = num_copies
"""
The number of copies that shall be printed when the print dialog is opened for this file.
Values outside this range shall be ignored. Default value: as defined by the conforming reader, but typically 1
"""
self.print_page_range = print_page_range
"""
The page numbers used to initialize the print dialog box when the file is printed.
The array shall contain an even number of integers to be interpreted in pairs,
with each pair specifying the first and last pages in a sub-range of pages to be printed.
The first page of the PDF file shall be denoted by 1.
"""
self.direction = direction
"""
The predominant reading order for text.
_cf. `fpdf.enums.TextDirection`
"""
self.duplex = duplex
"""
The paper handling option that shall be used when printing the file from the print dialog.
_cf. `fpdf.enums.Duplex`
"""
self.view_area = view_area
"""
The name of the page boundary representing the area of a page that shall be displayed when viewing the document on the screen.
Default value: CropBox.
"""
self.view_clip = view_clip
"""
The name of the page boundary to which the contents of a page shall be clipped when viewing the document on the screen.
Default value: CropBox.
"""
self.print_area = print_area
"""
The name of the page boundary representing the area of a page that shall be rendered when printing the document.
Default value: CropBox.
"""
self.print_clip = print_clip
"""
The name of the page boundary to which the contents of a page shall be clipped when printing the document.
Default value: CropBox.
"""

@property
def non_full_screen_page_mode(self):
Expand All @@ -50,7 +100,77 @@ def non_full_screen_page_mode(self):

@non_full_screen_page_mode.setter
def non_full_screen_page_mode(self, page_mode):
self._non_full_screen_page_mode = PageMode.coerce(page_mode)
self._non_full_screen_page_mode = (
None if page_mode is None else PageMode.coerce(page_mode)
)

@property
def direction(self):
"(`fpdf.enums.TextDirection`) The predominant reading order for text"
return self._direction

@direction.setter
def direction(self, direction):
self._direction = None if direction is None else TextDirection.coerce(direction)

@property
def duplex(self):
"(`fpdf.enums.Duplexe`) The paper handling option that shall be used when printing the file from the print dialog"
return self._duplex

@duplex.setter
def duplex(self, duplex):
self._duplex = None if duplex is None else Duplex.coerce(duplex)

@property
def view_area(self):
"""
(`fpdf.enums.PageBoundaries`) The name of the page boundary representing the area of a page that shall be displayed
when viewing the document on the screen
"""
return self._view_area

@view_area.setter
def view_area(self, view_area):
self._view_area = (
None if view_area is None else PageBoundaries.coerce(view_area)
)

@property
def view_clip(self):
"""
(`fpdf.enums.PageBoundaries`) The name of the page boundary to which the contents of a page shall be clipped
when viewing the document on the screen.
"""
return self._view_clip

@view_clip.setter
def view_clip(self, view_clip):
self._view_clip = (
None if view_clip is None else PageBoundaries.coerce(view_clip)
)

@property
def print_area(self):
"(`fpdf.enums.PageBoundaries`) The name of the page boundary representing the area of a page that shall be rendered when printing the document"
return self._print_area

@print_area.setter
def print_area(self, print_area):
self._print_area = (
None if print_area is None else PageBoundaries.coerce(print_area)
)

@property
def print_clip(self):
"(`fpdf.enums.PageBoundaries`) The name of the page boundary to which the contents of a page shall be clipped when printing the document"
return self._print_clip

@print_clip.setter
def print_clip(self, print_clip):
self._print_clip = (
None if print_clip is None else PageBoundaries.coerce(print_clip)
)

def serialize(self, _security_handler=None, _obj_id=None):
obj_dict = build_obj_dict(
Expand Down

0 comments on commit c3ae742

Please sign in to comment.