Spaces:
Paused
Paused
| from typing import Optional, Tuple, Union | |
| from ._base import ( | |
| BooleanObject, | |
| FloatObject, | |
| NameObject, | |
| NumberObject, | |
| TextStringObject, | |
| ) | |
| from ._data_structures import ArrayObject, DictionaryObject | |
| from ._fit import DEFAULT_FIT, Fit | |
| from ._rectangle import RectangleObject | |
| from ._utils import hex_to_rgb | |
| class AnnotationBuilder: | |
| """ | |
| The AnnotationBuilder creates dictionaries representing PDF annotations. | |
| Those dictionaries can be modified before they are added to a PdfWriter | |
| instance via `writer.add_annotation`. | |
| See `adding PDF annotations <../user/adding-pdf-annotations.html>`_ for | |
| it's usage combined with PdfWriter. | |
| """ | |
| from ..types import FitType, ZoomArgType | |
| def text( | |
| rect: Union[RectangleObject, Tuple[float, float, float, float]], | |
| text: str, | |
| open: bool = False, | |
| flags: int = 0, | |
| ) -> DictionaryObject: | |
| """ | |
| Add text annotation. | |
| :param Tuple[int, int, int, int] rect: | |
| or array of four integers specifying the clickable rectangular area | |
| ``[xLL, yLL, xUR, yUR]`` | |
| :param bool open: | |
| :param int flags: | |
| """ | |
| # TABLE 8.23 Additional entries specific to a text annotation | |
| text_obj = DictionaryObject( | |
| { | |
| NameObject("/Type"): NameObject("/Annot"), | |
| NameObject("/Subtype"): NameObject("/Text"), | |
| NameObject("/Rect"): RectangleObject(rect), | |
| NameObject("/Contents"): TextStringObject(text), | |
| NameObject("/Open"): BooleanObject(open), | |
| NameObject("/Flags"): NumberObject(flags), | |
| } | |
| ) | |
| return text_obj | |
| def free_text( | |
| text: str, | |
| rect: Union[RectangleObject, Tuple[float, float, float, float]], | |
| font: str = "Helvetica", | |
| bold: bool = False, | |
| italic: bool = False, | |
| font_size: str = "14pt", | |
| font_color: str = "000000", | |
| border_color: str = "000000", | |
| background_color: str = "ffffff", | |
| ) -> DictionaryObject: | |
| """ | |
| Add text in a rectangle to a page. | |
| :param str text: Text to be added | |
| :param RectangleObject rect: or array of four integers | |
| specifying the clickable rectangular area ``[xLL, yLL, xUR, yUR]`` | |
| :param str font: Name of the Font, e.g. 'Helvetica' | |
| :param bool bold: Print the text in bold | |
| :param bool italic: Print the text in italic | |
| :param str font_size: How big the text will be, e.g. '14pt' | |
| :param str font_color: Hex-string for the color | |
| :param str border_color: Hex-string for the border color | |
| :param str background_color: Hex-string for the background of the annotation | |
| """ | |
| font_str = "font: " | |
| if bold is True: | |
| font_str = font_str + "bold " | |
| if italic is True: | |
| font_str = font_str + "italic " | |
| font_str = font_str + font + " " + font_size | |
| font_str = font_str + ";text-align:left;color:#" + font_color | |
| bg_color_str = "" | |
| for st in hex_to_rgb(border_color): | |
| bg_color_str = bg_color_str + str(st) + " " | |
| bg_color_str = bg_color_str + "rg" | |
| free_text = DictionaryObject() | |
| free_text.update( | |
| { | |
| NameObject("/Type"): NameObject("/Annot"), | |
| NameObject("/Subtype"): NameObject("/FreeText"), | |
| NameObject("/Rect"): RectangleObject(rect), | |
| NameObject("/Contents"): TextStringObject(text), | |
| # font size color | |
| NameObject("/DS"): TextStringObject(font_str), | |
| # border color | |
| NameObject("/DA"): TextStringObject(bg_color_str), | |
| # background color | |
| NameObject("/C"): ArrayObject( | |
| [FloatObject(n) for n in hex_to_rgb(background_color)] | |
| ), | |
| } | |
| ) | |
| return free_text | |
| def line( | |
| p1: Tuple[float, float], | |
| p2: Tuple[float, float], | |
| rect: Union[RectangleObject, Tuple[float, float, float, float]], | |
| text: str = "", | |
| title_bar: str = "", | |
| ) -> DictionaryObject: | |
| """ | |
| Draw a line on the PDF. | |
| :param Tuple[float, float] p1: First point | |
| :param Tuple[float, float] p2: Second point | |
| :param RectangleObject rect: or array of four | |
| integers specifying the clickable rectangular area | |
| ``[xLL, yLL, xUR, yUR]`` | |
| :param str text: Text to be displayed as the line annotation | |
| :param str title_bar: Text to be displayed in the title bar of the | |
| annotation; by convention this is the name of the author | |
| """ | |
| line_obj = DictionaryObject( | |
| { | |
| NameObject("/Type"): NameObject("/Annot"), | |
| NameObject("/Subtype"): NameObject("/Line"), | |
| NameObject("/Rect"): RectangleObject(rect), | |
| NameObject("/T"): TextStringObject(title_bar), | |
| NameObject("/L"): ArrayObject( | |
| [ | |
| FloatObject(p1[0]), | |
| FloatObject(p1[1]), | |
| FloatObject(p2[0]), | |
| FloatObject(p2[1]), | |
| ] | |
| ), | |
| NameObject("/LE"): ArrayObject( | |
| [ | |
| NameObject(None), | |
| NameObject(None), | |
| ] | |
| ), | |
| NameObject("/IC"): ArrayObject( | |
| [ | |
| FloatObject(0.5), | |
| FloatObject(0.5), | |
| FloatObject(0.5), | |
| ] | |
| ), | |
| NameObject("/Contents"): TextStringObject(text), | |
| } | |
| ) | |
| return line_obj | |
| def rectangle( | |
| rect: Union[RectangleObject, Tuple[float, float, float, float]], | |
| interiour_color: Optional[str] = None, | |
| ) -> DictionaryObject: | |
| """ | |
| Draw a rectangle on the PDF. | |
| :param RectangleObject rect: or array of four | |
| integers specifying the clickable rectangular area | |
| ``[xLL, yLL, xUR, yUR]`` | |
| """ | |
| square_obj = DictionaryObject( | |
| { | |
| NameObject("/Type"): NameObject("/Annot"), | |
| NameObject("/Subtype"): NameObject("/Square"), | |
| NameObject("/Rect"): RectangleObject(rect), | |
| } | |
| ) | |
| if interiour_color: | |
| square_obj[NameObject("/IC")] = ArrayObject( | |
| [FloatObject(n) for n in hex_to_rgb(interiour_color)] | |
| ) | |
| return square_obj | |
| def link( | |
| rect: Union[RectangleObject, Tuple[float, float, float, float]], | |
| border: Optional[ArrayObject] = None, | |
| url: Optional[str] = None, | |
| target_page_index: Optional[int] = None, | |
| fit: Fit = DEFAULT_FIT, | |
| ) -> DictionaryObject: | |
| """ | |
| Add a link to the document. | |
| The link can either be an external link or an internal link. | |
| An external link requires the URL parameter. | |
| An internal link requires the target_page_index, fit, and fit args. | |
| :param RectangleObject rect: or array of four | |
| integers specifying the clickable rectangular area | |
| ``[xLL, yLL, xUR, yUR]`` | |
| :param border: if provided, an array describing border-drawing | |
| properties. See the PDF spec for details. No border will be | |
| drawn if this argument is omitted. | |
| - horizontal corner radius, | |
| - vertical corner radius, and | |
| - border width | |
| - Optionally: Dash | |
| :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 Fit fit: Page fit or 'zoom' option. | |
| """ | |
| from ..types import BorderArrayType | |
| is_external = url is not None | |
| is_internal = target_page_index is not None | |
| if not is_external and not is_internal: | |
| raise ValueError( | |
| "Either 'url' or 'target_page_index' have to be provided. Both were None." | |
| ) | |
| if is_external and is_internal: | |
| raise ValueError( | |
| f"Either 'url' or 'target_page_index' have to be provided. url={url}, target_page_index={target_page_index}" | |
| ) | |
| border_arr: BorderArrayType | |
| if border is not None: | |
| border_arr = [NameObject(n) for n in border[:3]] | |
| if len(border) == 4: | |
| dash_pattern = ArrayObject([NameObject(n) for n in border[3]]) | |
| border_arr.append(dash_pattern) | |
| else: | |
| border_arr = [NumberObject(0)] * 3 | |
| link_obj = DictionaryObject( | |
| { | |
| NameObject("/Type"): NameObject("/Annot"), | |
| NameObject("/Subtype"): NameObject("/Link"), | |
| NameObject("/Rect"): RectangleObject(rect), | |
| NameObject("/Border"): ArrayObject(border_arr), | |
| } | |
| ) | |
| if is_external: | |
| link_obj[NameObject("/A")] = DictionaryObject( | |
| { | |
| NameObject("/S"): NameObject("/URI"), | |
| NameObject("/Type"): NameObject("/Action"), | |
| NameObject("/URI"): TextStringObject(url), | |
| } | |
| ) | |
| if is_internal: | |
| # This needs to be updated later! | |
| dest_deferred = DictionaryObject( | |
| { | |
| "target_page_index": NumberObject(target_page_index), | |
| "fit": NameObject(fit.fit_type), | |
| "fit_args": fit.fit_args, | |
| } | |
| ) | |
| link_obj[NameObject("/Dest")] = dest_deferred | |
| return link_obj | |