diff --git a/README.md b/README.md index 0bfbda220..18dbc247c 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ [![Text Extraction : 88.6%](https://img.shields.io/badge/text%20extraction-88.6%25-orange)]() [![Public Method Documentation : 100%](https://img.shields.io/badge/public%20method%20documentation-100%25-green)]() +[![Downloads](https://pepy.tech/badge/borb)](https://pepy.tech/project/borb) +[![Downloads](https://pepy.tech/badge/borb/month)](https://pepy.tech/project/borb) `borb` is a library for creating and manipulating PDF files in python. @@ -60,7 +62,7 @@ from pathlib import Path from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/borb/io/read/reference/xref_transformer.py b/borb/io/read/reference/xref_transformer.py index dc427941b..fa81acfe8 100644 --- a/borb/io/read/reference/xref_transformer.py +++ b/borb/io/read/reference/xref_transformer.py @@ -15,7 +15,7 @@ from borb.io.read.transformer import ReadTransformerState, Transformer from borb.io.read.types import AnyPDFType, Dictionary, Name from borb.pdf.canvas.event.event_listener import Event, EventListener -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.xref.plaintext_xref import PlainTextXREF from borb.pdf.xref.stream_xref import StreamXREF from borb.pdf.xref.xref import XREF diff --git a/borb/io/write/ascii_art/ascii_logo.txt b/borb/io/write/ascii_art/ascii_logo.txt index ee14723e7..4a020e485 100644 --- a/borb/io/write/ascii_art/ascii_logo.txt +++ b/borb/io/write/ascii_art/ascii_logo.txt @@ -1,2 +1,2 @@ -borb version 2.0.18 +borb version 2.0.19 Joris Schellekens diff --git a/borb/io/write/document/document_transformer.py b/borb/io/write/document/document_transformer.py index c58df27bc..64df50dc3 100644 --- a/borb/io/write/document/document_transformer.py +++ b/borb/io/write/document/document_transformer.py @@ -11,7 +11,7 @@ from borb.io.read.types import AnyPDFType, Dictionary, HexadecimalString, List, Name from borb.io.write.transformer import Transformer, WriteTransformerState -from borb.pdf.document import Document +from borb.pdf.document.document import Document logger = logging.getLogger(__name__) diff --git a/borb/io/write/document/information_dictionary_transformer.py b/borb/io/write/document/information_dictionary_transformer.py index f721c5cb9..aa8f46527 100644 --- a/borb/io/write/document/information_dictionary_transformer.py +++ b/borb/io/write/document/information_dictionary_transformer.py @@ -18,7 +18,7 @@ from borb.io.write.object.dictionary_transformer import DictionaryTransformer from borb.io.write.object.stream_transformer import StreamTransformer from borb.io.write.transformer import Transformer, WriteTransformerState -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.trailer.document_info import XMPDocumentInfo logger = logging.getLogger(__name__) diff --git a/borb/io/write/page/page_transformer.py b/borb/io/write/page/page_transformer.py index 8154749c7..171750d9c 100644 --- a/borb/io/write/page/page_transformer.py +++ b/borb/io/write/page/page_transformer.py @@ -11,7 +11,7 @@ from borb.io.read.types import AnyPDFType, Dictionary, Name from borb.io.write.object.dictionary_transformer import DictionaryTransformer from borb.io.write.transformer import WriteTransformerState -from borb.pdf.document import Document +from borb.pdf.document.document import Document logger = logging.getLogger(__name__) diff --git a/borb/pdf/canvas/layout/annotation/__init__.py b/borb/pdf/canvas/layout/annotation/__init__.py new file mode 100644 index 000000000..bcf77caad --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/__init__.py @@ -0,0 +1,43 @@ +""" + This file is part of the borb (R) project. + Copyright (c) 2020-2040 borb Group NV + Authors: Joris Schellekens, et al. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License version 3 + as published by the Free Software Foundation with the addition of the + following permission added to Section 15 as permitted in Section 7(a): + FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY + BORB GROUP. BORB GROUP DISCLAIMS THE WARRANTY OF NON INFRINGEMENT + OF THIRD PARTY RIGHTS + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program; if not, see http://www.gnu.org/licenses or write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA, 02110-1301 USA. + + The interactive user interfaces in modified source and object code versions + of this program must display Appropriate Legal Notices, as required under + Section 5 of the GNU Affero General Public License. + In accordance with Section 7(b) of the GNU Affero General Public License, + a covered work must retain the producer line in every PDF that is created + or manipulated using borb. + + You can be released from the requirements of the license by purchasing + a commercial license. Buying such a license is mandatory as soon as you + develop commercial activities involving the borb software without + disclosing the source code of your own applications. + + These activities include: offering paid services to customers as an ASP, + serving PDFs on the fly in a web application, shipping borb with a closed + source product. + + For more information, please contact borb Software Corp. at this + address: joris.schellekens.1989@gmail.com +""" diff --git a/borb/pdf/canvas/layout/annotation/annotation.py b/borb/pdf/canvas/layout/annotation/annotation.py new file mode 100644 index 000000000..96f468caf --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/annotation.py @@ -0,0 +1,126 @@ +import datetime +import typing +from decimal import Decimal + +from borb.io.read.types import Dictionary, Name, List, Decimal as bDecimal, String +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle + + +class Annotation(Dictionary): + @staticmethod + def _timestamp_to_str() -> str: + timestamp_str = "D:" + now = datetime.datetime.now() + for n in [now.year, now.month, now.day, now.hour, now.minute, now.second]: + timestamp_str += "{0:02}".format(n) + timestamp_str += "Z00" + return timestamp_str + + def __init__( + self, + bounding_box: Rectangle, + contents: typing.Optional[str] = None, + color: typing.Optional[Color] = None, + horizontal_corner_radius: typing.Optional[Decimal] = None, + vertical_corner_radius: typing.Optional[Decimal] = None, + border_width: typing.Optional[Decimal] = None, + ): + super(Annotation, self).__init__() + + # (Optional) The type of PDF object that this dictionary describes; if + # present, shall be Annot for an annotation dictionary. + self[Name("Type")] = Name("Annot") + + # (Required) The annotation rectangle, defining the location of the + # annotation on the page in default user space units. + self[Name("Rect")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["Rect"].append(bDecimal(bounding_box.get_x())) + self["Rect"].append(bDecimal(bounding_box.get_y())) + self["Rect"].append(bDecimal(bounding_box.get_x() + bounding_box.get_width())) + self["Rect"].append(bDecimal(bounding_box.get_y() + bounding_box.get_height())) + + # (Optional) Text that shall be displayed for the annotation or, if this type of + # annotation does not display text, an alternate description of the + # annotation’s contents in human-readable form. In either case, this text is + # useful when extracting the document’s contents in support of + # accessibility to users with disabilities or for other purposes (see 14.9.3, + # “Alternate Descriptions”). See 12.5.6, “Annotation Types” for more + # details on the meaning of this entry for each annotation type. + if contents is not None: + self[Name("Contents")] = String(contents) + + # (Optional; PDF 1.4) The annotation name, a text string uniquely + # identifying it among all the annotations on its page. + len_annots = len(self["Annots"]) if "Annots" in self else 0 + self[Name("NM")] = String("annotation-{0:03d}".format(len_annots)) + + # (Optional; PDF 1.1) The date and time when the annotation was most + # recently modified. The format should be a date string as described in + # 7.9.4, “Dates,” but conforming readers shall accept and display a string + # in any format. + self[Name("M")] = String(self._timestamp_to_str()) + + # (Optional; PDF 1.1) A set of flags specifying various characteristics of + # the annotation (see 12.5.3, “Annotation Flags”). Default value: 0. + self[Name("F")] = bDecimal(4) + + # (Optional; PDF 1.2) An appearance dictionary specifying how the + # annotation shall be presented visually on the page (see 12.5.5, + # “Appearance Streams”). Individual annotation handlers may ignore this + # entry and provide their own appearances. + # self[Name("AP")] = None + + # (Required if the appearance dictionary AP contains one or more + # subdictionaries; PDF 1.2) The annotation’s appearance state, which + # selects the applicable appearance stream from an appearance + # subdictionary (see Section 12.5.5, “Appearance Streams”). + # self[Name("AS")] = None + + # Optional) An array specifying the characteristics of the annotation’s + # border, which shall be drawn as a rounded rectangle. + # (PDF 1.0) The array consists of three numbers defining the horizontal + # corner radius, vertical corner radius, and border width, all in default user + # space units. If the corner radii are 0, the border has square (not rounded) + # corners; if the border width is 0, no border is drawn. + # (PDF 1.1) The array may have a fourth element, an optional dash array + # defining a pattern of dashes and gaps that shall be used in drawing the + # border. The dash array shall be specified in the same format as in the + # line dash pattern parameter of the graphics state (see 8.4.3.6, “Line + # Dash Pattern”). + if ( + horizontal_corner_radius is not None + and vertical_corner_radius is not None + and border_width is not None + ): + self[Name("Border")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["Border"].append(bDecimal(horizontal_corner_radius)) + self["Border"].append(bDecimal(vertical_corner_radius)) + self["Border"].append(bDecimal(border_width)) + + # (Optional; PDF 1.1) An array of numbers in the range 0.0 to 1.0, + # representing a colour used for the following purposes: + # The background of the annotation’s icon when closed + # The title bar of the annotation’s pop-up window + # The border of a link annotation + # The number of array elements determines the colour space in which the + # colour shall be defined + if color is not None: + self[Name("C")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["C"].append(bDecimal(color.to_rgb().red)) + self["C"].append(bDecimal(color.to_rgb().green)) + self["C"].append(bDecimal(color.to_rgb().blue)) + + # (Required if the annotation is a structural content item; PDF 1.3) The + # integer key of the annotation’s entry in the structural parent tree (see + # 14.7.4.4, “Finding Structure Elements from Content Items”) + # self[Name("StructParent")] = None + + # (Optional; PDF 1.5) An optional content group or optional content + # membership dictionary (see 8.11, “Optional Content”) specifying the + # optional content properties for the annotation. Before the annotation is + # drawn, its visibility shall be determined based on this entry as well as the + # annotation flags specified in the F entry (see 12.5.3, “Annotation Flags”). + # If it is determined to be invisible, the annotation shall be skipped, as if it + # were not in the document. + # self[Name("OC")] = None diff --git a/borb/pdf/canvas/layout/annotation/caret_annotation.py b/borb/pdf/canvas/layout/annotation/caret_annotation.py new file mode 100644 index 000000000..8fa17c64c --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/caret_annotation.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A caret annotation (PDF 1.5) is a visual symbol that indicates the presence of text edits. Table 180 lists the +entries specific to caret annotations. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class CaretAnnotation(Annotation): + """ + A caret annotation (PDF 1.5) is a visual symbol that indicates the presence of text edits. Table 180 lists the + entries specific to caret annotations. + """ + + def __init__(self): + super(CaretAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/circle_annotation.py b/borb/pdf/canvas/layout/annotation/circle_annotation.py new file mode 100644 index 000000000..e8b838e61 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/circle_annotation.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When +opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse +shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see +Table 168). +""" +import typing +from decimal import Decimal + +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class CircleAnnotation(Annotation): + """ + Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When + opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse + shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see + Table 168). + """ + + def __init__( + self, + bounding_box: Rectangle, + fill_color: Color, + stroke_color: Color, + rectangle_difference: typing.Optional[ + typing.Tuple[Decimal, Decimal, Decimal, Decimal] + ] = None, + ): + super(CircleAnnotation, self).__init__( + bounding_box=bounding_box, color=stroke_color + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Square or Circle for a square or circle annotation, respectively. + self[Name("Subtype")] = Name("Circle") + + # (Optional) A border style dictionary (see Table 166) specifying the line + # width and dash pattern that shall be used in drawing the rectangle or + # ellipse. + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the Rect and BS entries; see Table 168 and 12.5.5, “Appearance + # Streams.” + # self[Name("BS")] = None + + # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to + # 1.0 and shall specify the interior color with which to fill the annotation’s + # rectangle or ellipse. The number of array elements determines the colour + # space in which the colour shall be defined + if fill_color is not None: + self[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["IC"].append(bDecimal(fill_color.to_rgb().red)) + self["IC"].append(bDecimal(fill_color.to_rgb().green)) + self["IC"].append(bDecimal(fill_color.to_rgb().blue)) + + # (Optional; PDF 1.5) A border effect dictionary describing an effect applied + # to the border described by the BS entry (see Table 167). + # self[Name("BE")] = None + + # (Optional; PDF 1.5) A set of four numbers that shall describe the + # numerical differences between two rectangles: the Rect entry of the + # annotation and the actual boundaries of the underlying square or circle. + # Such a difference may occur in situations where a border effect + # (described by BE) causes the size of the Rect to increase beyond that of + # the square or circle. + # The four numbers shall correspond to the differences in default user + # space between the left, top, right, and bottom coordinates of Rect and + # those of the square or circle, respectively. Each value shall be greater + # than or equal to 0. The sum of the top and bottom differences shall be + # less than the height of Rect, and the sum of the left and right differences + # shall be less than the width of Rect. + if rectangle_difference is not None: + self[Name("RD")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["RD"].append(bDecimal(rectangle_difference[0])) + self["RD"].append(bDecimal(rectangle_difference[1])) + self["RD"].append(bDecimal(rectangle_difference[2])) + self["RD"].append(bDecimal(rectangle_difference[3])) diff --git a/borb/pdf/canvas/layout/annotation/file_attachment_annotation.py b/borb/pdf/canvas/layout/annotation/file_attachment_annotation.py new file mode 100644 index 000000000..6456ff4f5 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/file_attachment_annotation.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A file attachment annotation (PDF 1.3) contains a reference to a file, which typically shall be embedded in the +PDF file (see 7.11.4, “Embedded File Streams”). +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class FileAttachmentAnnotation(Annotation): + """ + A file attachment annotation (PDF 1.3) contains a reference to a file, which typically shall be embedded in the + PDF file (see 7.11.4, “Embedded File Streams”). + """ + + def __init__(self): + super(FileAttachmentAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/free_text_annotation.py b/borb/pdf/canvas/layout/annotation/free_text_annotation.py new file mode 100644 index 000000000..e0b2ba7a5 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/free_text_annotation.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A free text annotation (PDF 1.3) displays text directly on the page. Unlike an ordinary text annotation (see +12.5.6.4, “Text Annotations”), a free text annotation has no open or closed state; instead of being displayed in a +pop-up window, the text shall be always visible. Table 174 shows the annotation dictionary entries specific to +this type of annotation. 12.7.3.3, “Variable Text” describes the process of using these entries to generate the +appearance of the text in these annotations. +""" +import typing +from decimal import Decimal + +from borb.io.read.types import Name, Decimal as bDecimal, Dictionary, String +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.font.font import Font +from borb.pdf.canvas.font.simple_font.font_type_1 import StandardType1Font +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class FreeTextAnnotation(Annotation): + """ + A free text annotation (PDF 1.3) displays text directly on the page. Unlike an ordinary text annotation (see + 12.5.6.4, “Text Annotations”), a free text annotation has no open or closed state; instead of being displayed in a + pop-up window, the text shall be always visible. Table 174 shows the annotation dictionary entries specific to + this type of annotation. 12.7.3.3, “Variable Text” describes the process of using these entries to generate the + appearance of the text in these annotations. + """ + + def __init__( + self, + bounding_box: Rectangle, + contents: str, + background_color: typing.Optional[Color] = None, + font: Font = StandardType1Font("Helvetica"), + font_size: Decimal = Decimal(12), + font_color: Color = HexColor("000000"), + ): + + super(FreeTextAnnotation, self).__init__( + bounding_box=bounding_box, contents=contents, color=background_color + ) + self._font: Font = font + self._font_color_rgb: "RGBColor" = font_color.to_rgb() # type: ignore [name-defined] + self._font_size: Decimal = font_size + self._font_name: str = "F0" + + # specific for text annotations + self[Name("Subtype")] = Name("FreeText") + + # (Optional; PDF 1.1) A set of flags specifying various characteristics of + # the annotation (see 12.5.3, “Annotation Flags”). Default value: 0. + self[Name("F")] = bDecimal(20) + + # (Required) The default appearance string that shall be used in formatting + # the text (see 12.7.3.3, “Variable Text”). + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the DA entry; see Table 168 and 12.5.5, “Appearance Streams.” + self[Name("DA")] = String( + "/%s %f Tf %f %f %f rg" + % ( + self._font_name, + self._font_size, + self._font_color_rgb.red, + self._font_color_rgb.green, + self._font_color_rgb.blue, + ) + ) + + # (Optional; PDF 1.4) A code specifying the form of quadding (justification) + # that shall be used in displaying the annotation’s text: + # 0 Left-justified + # 1 Centered + # 2 Right-justified + # Default value: 0 (left-justified). + self[Name("Q")] = bDecimal(0) + + # (Optional; PDF 1.6) A name describing the intent of the free text + # annotation (see also the IT entry in Table 170). The following values shall + # be valid: + # FreeText + # The annotation is intended to function as a plain + # free-text annotation. A plain free-text annotation + # is also known as a text box comment. + # FreeTextCallout + # The annotation is intended to function as a + # callout. The callout is associated with an area on + # the page through the callout line specified in CL. + # FreeTextTypeWriter + # The annotation is intended to function as a click- + # to-type or typewriter object and no callout line is + # drawn. + # Default value: FreeText + self[Name("IT")] = Name("FreeTextTypeWriter") + + def _embed_font_in_page(self, page: "Page") -> None: + if "Resources" not in page: + page[Name("Resources")] = Dictionary() + if "Font" not in page["Resources"]: + page["Resources"][Name("Font")] = Dictionary() + font_number: int = len(page["Resources"]["Font"]) + font_name: str = "F%d" % font_number + while font_name in page["Resources"]["Font"]: + font_number += 1 + font_name = "F%d" % font_number + page["Resources"]["Font"][Name(font_name)] = self._font + + # (Required) The default appearance string that shall be used in formatting + # the text (see 12.7.3.3, “Variable Text”). + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the DA entry; see Table 168 and 12.5.5, “Appearance Streams.” + self[Name("DA")] = String( + "/%s %f Tf %f %f %f rg" + % ( + self._font_name, + self._font_size, + self._font_color_rgb.red, + self._font_color_rgb.green, + self._font_color_rgb.blue, + ) + ) diff --git a/borb/pdf/canvas/layout/annotation/highlight_annotation.py b/borb/pdf/canvas/layout/annotation/highlight_annotation.py new file mode 100644 index 000000000..b275f9601 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/highlight_annotation.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) +underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing +the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of +annotations. +""" +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class HighlightAnnotation(Annotation): + """ + Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) + underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing + the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of + annotations. + """ + + def __init__(self, bounding_box: Rectangle, color: Color = HexColor("faed27")): + + # create generic annotation + super(HighlightAnnotation, self).__init__( + bounding_box=bounding_box, color=color + ) + + # (Required) The type of annotation that this dictionary describes; shall + # be Highlight, Underline, Squiggly, or StrikeOut for a highlight, + # underline, squiggly-underline, or strikeout annotation, respectively. + self[Name("Subtype")] = Name("Highlight") + + # (Required) An array of 8 × n numbers specifying the coordinates of n + # quadrilaterals in default user space. Each quadrilateral shall + # encompasses a word or group of contiguous words in the text + # underlying the annotation. The coordinates for each quadrilateral shall + # be given in the order + # x1 y1 x2 y2 x3 y3 x4 y4 + self[Name("QuadPoints")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + # x1, y1 + self["QuadPoints"].append(bDecimal(bounding_box.get_x())) + self["QuadPoints"].append(bDecimal(bounding_box.get_y())) + # x4, y4 + self["QuadPoints"].append(bDecimal(bounding_box.get_x())) + self["QuadPoints"].append( + bDecimal(bounding_box.get_y() + bounding_box.get_height()) + ) + # x2, y2 + self["QuadPoints"].append( + bDecimal(bounding_box.get_x() + bounding_box.get_width()) + ) + self["QuadPoints"].append(bDecimal(bounding_box.get_y())) + # x3, y3 + self["QuadPoints"].append( + bDecimal(bounding_box.get_x() + bounding_box.get_width()) + ) + self["QuadPoints"].append( + bDecimal(bounding_box.get_y() + bounding_box.get_height()) + ) + + # border + self[Name("Border")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["Border"].append(bDecimal(0)) + self["Border"].append(bDecimal(0)) + self["Border"].append(bDecimal(1)) diff --git a/borb/pdf/canvas/layout/annotation/ink_annotation.py b/borb/pdf/canvas/layout/annotation/ink_annotation.py new file mode 100644 index 000000000..92f2edbfb --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/ink_annotation.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +An ink annotation (PDF 1.3) represents a freehand “scribble” composed of one or more disjoint paths. When +opened, it shall display a pop-up window containing the text of the associated note. Table 182 shows the +annotation dictionary entries specific to this type of annotation. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class InkAnnotation(Annotation): + """ + An ink annotation (PDF 1.3) represents a freehand “scribble” composed of one or more disjoint paths. When + opened, it shall display a pop-up window containing the text of the associated note. Table 182 shows the + annotation dictionary entries specific to this type of annotation. + """ + + def __init__(self): + super(InkAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/line_annotation.py b/borb/pdf/canvas/layout/annotation/line_annotation.py new file mode 100644 index 000000000..e444b383b --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/line_annotation.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +The purpose of a line annotation (PDF 1.3) is to display a single straight line on the page. When opened, it shall +display a pop-up window containing the text of the associated note. Table 175 shows the annotation dictionary +entries specific to this type of annotation. +""" +import typing +from decimal import Decimal + +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation +from borb.pdf.canvas.layout.annotation.polyline_annotation import LineEndStyleType + + +class LineAnnotation(Annotation): + """ + The purpose of a line annotation (PDF 1.3) is to display a single straight line on the page. When opened, it shall + display a pop-up window containing the text of the associated note. Table 175 shows the annotation dictionary + entries specific to this type of annotation. + """ + + def __init__( + self, + start_point: typing.Tuple[Decimal, Decimal], + end_point: typing.Tuple[Decimal, Decimal], + left_line_end_style: LineEndStyleType = LineEndStyleType.NONE, + right_line_end_style: LineEndStyleType = LineEndStyleType.NONE, + stroke_color: Color = HexColor("000000"), + ): + + x = min([start_point[0], end_point[0]]) + y = min([start_point[1], end_point[1]]) + w = max([start_point[0], end_point[0]]) - x + h = max([start_point[1], end_point[1]]) - y + + # create generic annotation + super(LineAnnotation, self).__init__( + bounding_box=Rectangle(x, y, w, h), color=stroke_color + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Line for a line annotation. + self[Name("Subtype")] = Name("Line") + + # (Required) An array of four numbers, [ x 1 y 1 x 2 y 2 ], specifying the + # starting and ending coordinates of the line in default user space. + # If the LL entry is present, this value shall represent the endpoints of the + # leader lines rather than the endpoints of the line itself; see Figure 60. + self[Name("L")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["L"].append(start_point[0]) + self["L"].append(start_point[1]) + self["L"].append(end_point[0]) + self["L"].append(end_point[1]) + + # (Optional; PDF 1.4) An array of two names specifying the line ending + # styles that shall be used in drawing the line. The first and second + # elements of the array shall specify the line ending styles for the endpoints + # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) + # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default + # value: [ /None /None ]. + self[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["LE"].append(left_line_end_style.value) + self["LE"].append(right_line_end_style) + + # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to + # 1.0 and shall specify the interior color with which to fill the annotation’s + # rectangle or ellipse. The number of array elements determines the colour + # space in which the colour shall be defined + if stroke_color is not None: + self[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["IC"].append(bDecimal(stroke_color.to_rgb().red)) + self["IC"].append(bDecimal(stroke_color.to_rgb().green)) + self["IC"].append(bDecimal(stroke_color.to_rgb().blue)) diff --git a/borb/pdf/canvas/layout/annotation/link_annotation.py b/borb/pdf/canvas/layout/annotation/link_annotation.py new file mode 100644 index 000000000..29d0fde0f --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/link_annotation.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, +“Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary +entries specific to this type of annotation. +""" +import enum +from decimal import Decimal + +import typing + +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation +from borb.io.read.types import Name, List, Decimal as bDecimal, String + + +class DestinationType(enum.Enum): + """ + This Enum represents all possible destination types (when adding a link annotation) + """ + + FIT = Name("Fit") + FIT_B = Name("FitB") + FIT_B_H = Name("FitBH") + FIT_B_V = Name("FitBV") + FIT_H = Name("FitH") + FIT_R = Name("FitR") + FIT_V = Name("FitV") + X_Y_Z = Name("XYZ") + + +class LinkAnnotation(Annotation): + """ + A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, + “Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary + entries specific to this type of annotation. + """ + + def __init__( + self, + bounding_box: Rectangle, + page: Decimal, + destination_type: DestinationType, + color: typing.Optional[Color] = None, + top: typing.Optional[Decimal] = None, + right: typing.Optional[Decimal] = None, + bottom: typing.Optional[Decimal] = None, + left: typing.Optional[Decimal] = None, + zoom: typing.Optional[Decimal] = None, + highlighting_mode: typing.Optional[str] = None, + ): + super(LinkAnnotation, self).__init__(bounding_box=bounding_box, color=color) + + # specific for text annotations + self[Name("Subtype")] = Name("Link") + + # (Optional; PDF 1.1) An action that shall be performed when the link + # annotation is activated (see 12.6, “Actions”). + # annot[Name("A")] = None + + # (Optional; not permitted if an A entry is present) A destination that shall + # be displayed when the annotation is activated (see 12.3.2, + # “Destinations”). + destination = List().set_can_be_referenced(False) # type: ignore [attr-defined] + destination.append(bDecimal(page)) + destination.append(destination_type.value) + if destination_type == DestinationType.X_Y_Z: + assert ( + left is not None + and bottom is None + and right is None + and top is not None + and zoom is not None + ) + destination.append(bDecimal(left)) + destination.append(bDecimal(top)) + destination.append(bDecimal(zoom)) + if destination_type == DestinationType.FIT: + assert ( + left is None + and bottom is None + and right is None + and top is None + and zoom is None + ) + if destination_type == DestinationType.FIT_H: + assert ( + left is None + and bottom is None + and right is None + and top is not None + and zoom is None + ) + destination.append(bDecimal(top)) + if destination_type == DestinationType.FIT_V: + assert ( + left is not None + and bottom is None + and right is None + and top is None + and zoom is None + ) + destination.append(bDecimal(left)) + if destination_type == DestinationType.FIT_R: + assert ( + left is not None + and bottom is not None + and right is not None + and top is not None + and zoom is None + ) + destination.append(bDecimal(left)) + destination.append(bDecimal(bottom)) + destination.append(bDecimal(right)) + destination.append(bDecimal(top)) + if destination_type == DestinationType.FIT_B_H: + assert ( + left is None + and bottom is None + and right is None + and top is not None + and zoom is None + ) + destination.append(bDecimal(top)) + if destination_type == DestinationType.FIT_B_V: + assert ( + left is not None + and bottom is None + and right is None + and top is None + and zoom is None + ) + destination.append(bDecimal(left)) + self[Name("Dest")] = destination + + # (Optional; PDF 1.2) The annotation’s highlighting mode, the visual effect + # that shall be used when the mouse button is pressed or held down + # inside its active area: + # N (None) No highlighting. + # I (Invert) Invert the contents of the annotation rectangle. + # O (Outline) Invert the annotation’s border. + # P (Push) Display the annotation as if it were being pushed below the surface of the page. + if highlighting_mode is not None: + assert highlighting_mode in ["N", "I", "O", "P"] + self[Name("H")] = String(highlighting_mode) diff --git a/borb/pdf/canvas/layout/annotation/movie_annotation.py b/borb/pdf/canvas/layout/annotation/movie_annotation.py new file mode 100644 index 000000000..51b6b4850 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/movie_annotation.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A movie annotation (PDF 1.2) contains animated graphics and sound to be presented on the computer screen +and through the speakers. When the annotation is activated, the movie shall be played. Table 186 shows the +annotation dictionary entries specific to this type of annotation. Movies are discussed in 13.4, “Movies.” +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class MovieAnnotation(Annotation): + """ + A movie annotation (PDF 1.2) contains animated graphics and sound to be presented on the computer screen + and through the speakers. When the annotation is activated, the movie shall be played. Table 186 shows the + annotation dictionary entries specific to this type of annotation. Movies are discussed in 13.4, “Movies.” + """ + + def __init__(self): + super(MovieAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/polygon_annotion.py b/borb/pdf/canvas/layout/annotation/polygon_annotion.py new file mode 100644 index 000000000..5beb30f65 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/polygon_annotion.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of +vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first +and last vertex are not implicitly connected. +""" +import typing +from decimal import Decimal + +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class PolygonAnnotation(Annotation): + """ + Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of + vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first + and last vertex are not implicitly connected. + """ + + def __init__( + self, + points: typing.List[typing.Tuple[Decimal]], + stroke_color: Color = HexColor("000000"), + ): + + # must be at least 3 points + assert len(points) >= 3 + + # bounding box + min_x = points[0][0] + min_y = points[0][1] + max_x = min_x + max_y = min_y + for p in points: + min_x = min(min_x, p[0]) + min_y = min(min_y, p[1]) + max_x = max(max_x, p[0]) + max_y = max(max_y, p[1]) + + super(PolygonAnnotation, self).__init__( + bounding_box=Rectangle(min_x, min_y, max_x - min_x, max_y - min_y), + color=stroke_color, + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Polygon or PolyLine for a polygon or polyline annotation, respectively. + self[Name("Subtype")] = Name("Polygon") + + # (Required) An array of numbers (see Table 174) specifying the width and + # dash pattern that shall represent the alternating horizontal and vertical + # coordinates, respectively, of each vertex, in default user space. + self[Name("Vertices")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + for p in points: + self["Vertices"].append(bDecimal(p[0])) + self["Vertices"].append(bDecimal(p[1])) + + # (Optional; PDF 1.4) An array of two names specifying the line ending + # styles that shall be used in drawing the line. The first and second + # elements of the array shall specify the line ending styles for the endpoints + # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) + # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default + # value: [ /None /None ]. + self[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["LE"].append(Name("None")) + self["LE"].append(Name("None")) diff --git a/borb/pdf/canvas/layout/annotation/polyline_annotation.py b/borb/pdf/canvas/layout/annotation/polyline_annotation.py new file mode 100644 index 000000000..aa204ab11 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/polyline_annotation.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of +vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first +and last vertex are not implicitly connected. +""" +import enum +import typing +from decimal import Decimal + +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class LineEndStyleType(enum.Enum): + """ + This Enum represents all possible line end styles + """ + + SQUARE = Name("Square") + CIRCLE = Name("Circle") + DIAMOND = Name("Diamond") + OPEN_ARROW = Name("OpenArrow") + CLOSED_ARROW = Name("ClosedArrow") + NONE = Name("None") + BUTT = Name("Butt") + RIGHT_OPEN_ARROW = Name("ROpenArrow") + RIGHT_CLOSED_ARROW = Name("RClosedArrow") + SLASH = Name("Slash") + + +class PolylineAnnotation(Annotation): + """ + Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of + vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first + and last vertex are not implicitly connected. + """ + + def __init__( + self, + points: typing.List[typing.Tuple[Decimal, Decimal]], + stroke_color: typing.Optional[Color] = HexColor("000000"), + fill_color: typing.Optional[Color] = None, + left_line_end_style: LineEndStyleType = LineEndStyleType.NONE, + right_line_end_style: LineEndStyleType = LineEndStyleType.NONE, + ): + + # must be at least 3 points + assert len(points) >= 3 + + # bounding box + min_x = points[0][0] + min_y = points[0][1] + max_x = min_x + max_y = min_y + for p in points: + min_x = min(min_x, p[0]) + min_y = min(min_y, p[1]) + max_x = max(max_x, p[0]) + max_y = max(max_y, p[1]) + + # create generic annotation + super(PolylineAnnotation, self).__init__( + bounding_box=Rectangle(min_x, min_y, max_x - min_x, max_y - min_y), + color=stroke_color, + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Polygon or PolyLine for a polygon or polyline annotation, respectively. + self[Name("Subtype")] = Name("PolyLine") + + # (Required) An array of numbers (see Table 174) specifying the width and + # dash pattern that shall represent the alternating horizontal and vertical + # coordinates, respectively, of each vertex, in default user space. + self[Name("Vertices")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + for p in points: + self["Vertices"].append(bDecimal(p[0])) + self["Vertices"].append(bDecimal(p[1])) + + # (Optional; PDF 1.4) An array of two names specifying the line ending + # styles that shall be used in drawing the line. The first and second + # elements of the array shall specify the line ending styles for the endpoints + # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) + # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default + # value: [ /None /None ]. + self[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["LE"].append(left_line_end_style) + self["LE"].append(right_line_end_style) + + if fill_color is not None: + self[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["IC"].append(bDecimal(fill_color.to_rgb().red)) + self["IC"].append(bDecimal(fill_color.to_rgb().green)) + self["IC"].append(bDecimal(fill_color.to_rgb().blue)) diff --git a/borb/pdf/canvas/layout/annotation/popup_annotation.py b/borb/pdf/canvas/layout/annotation/popup_annotation.py new file mode 100644 index 000000000..50d64d2e1 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/popup_annotation.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A pop-up annotation (PDF 1.3) displays text in a pop-up window for entry and editing. It shall not appear alone +but is associated with a markup annotation, its parent annotation, and shall be used for editing the parent’s text. +It shall have no appearance stream or associated actions of its own and shall be identified by the Popup entry +in the parent’s annotation dictionary (see Table 174). Table 183 shows the annotation dictionary entries specific +to this type of annotation. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class PopupAnnotation(Annotation): + """ + A pop-up annotation (PDF 1.3) displays text in a pop-up window for entry and editing. It shall not appear alone + but is associated with a markup annotation, its parent annotation, and shall be used for editing the parent’s text. + It shall have no appearance stream or associated actions of its own and shall be identified by the Popup entry + in the parent’s annotation dictionary (see Table 174). Table 183 shows the annotation dictionary entries specific + to this type of annotation. + """ + + def __init__(self): + super(PopupAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/printer_mark_annotation.py b/borb/pdf/canvas/layout/annotation/printer_mark_annotation.py new file mode 100644 index 000000000..35ff3dcd9 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/printer_mark_annotation.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A printer’s mark annotation (PDF 1.4) represents a graphic symbol, such as a registration target, colour bar, or +cut mark, that may be added to a page to assist production personnel in identifying components of a multiple- +plate job and maintaining consistent output during production. See 14.11.3, “Printer’s Marks,” for further +discussion. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class PrinterMarkAnnotation(Annotation): + """ + A printer’s mark annotation (PDF 1.4) represents a graphic symbol, such as a registration target, colour bar, or + cut mark, that may be added to a page to assist production personnel in identifying components of a multiple- + plate job and maintaining consistent output during production. See 14.11.3, “Printer’s Marks,” for further + discussion. + """ + + def __init__(self): + super(PrinterMarkAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/redact_annotation.py b/borb/pdf/canvas/layout/annotation/redact_annotation.py new file mode 100644 index 000000000..97190a5af --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/redact_annotation.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A redaction annotation (PDF 1.7) identifies content that is intended to be removed from the document. The +intent of redaction annotations is to enable the following process: + +a) Content identification. A user applies redact annotations that specify the pieces or regions of content that +should be removed. Up until the next step is performed, the user can see, move and redefine these +annotations. + +b) Content removal. The user instructs the viewer application to apply the redact annotations, after which the +content in the area specified by the redact annotations is removed. In the removed content’s place, some +marking appears to indicate the area has been redacted. Also, the redact annotations are removed from +the PDF document. + +Redaction annotations provide a mechanism for the first step in the redaction process (content identification). +This allows content to be marked for redaction in a non-destructive way, thus enabling a review process for +evaluating potential redactions prior to removing the specified content. +""" +import typing +import zlib +from decimal import Decimal + +from borb.io.read.types import ( + Name, + List, + Decimal as bDecimal, + String, + Boolean, + Dictionary, + Stream, +) +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class RedactAnnotation(Annotation): + """ + A redaction annotation (PDF 1.7) identifies content that is intended to be removed from the document. The + intent of redaction annotations is to enable the following process: + + a) Content identification. A user applies redact annotations that specify the pieces or regions of content that + should be removed. Up until the next step is performed, the user can see, move and redefine these + annotations. + + b) Content removal. The user instructs the viewer application to apply the redact annotations, after which the + content in the area specified by the redact annotations is removed. In the removed content’s place, some + marking appears to indicate the area has been redacted. Also, the redact annotations are removed from + the PDF document. + + Redaction annotations provide a mechanism for the first step in the redaction process (content identification). + This allows content to be marked for redaction in a non-destructive way, thus enabling a review process for + evaluating potential redactions prior to removing the specified content. + """ + + def __init__( + self, + bounding_box: Rectangle, + fill_color: typing.Optional[Color] = None, + stroke_color: typing.Optional[Color] = None, + stroke_width: Decimal = Decimal(1), + overlay_text: typing.Optional[str] = None, + repeat_overlay_text: typing.Optional[bool] = None, + ): + super(RedactAnnotation, self).__init__(bounding_box=bounding_box) + + # (Required) The type of annotation that this dictionary describes; shall + # be Redact for a redaction annotation. + self[Name("Subtype")] = Name("Redact") + + # (Optional) An array of three numbers in the range 0.0 to 1.0 + # specifying the components, in the DeviceRGB colour space, of the + # interior colour with which to fill the redacted region after the affected + # content has been removed. If this entry is absent, the interior of the + # redaction region is left transparent. This entry is ignored if the RO + # entry is present. + if fill_color is not None: + self[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["IC"].append(bDecimal(fill_color.to_rgb().red)) + self["IC"].append(bDecimal(fill_color.to_rgb().green)) + self["IC"].append(bDecimal(fill_color.to_rgb().blue)) + + # (Optional) A text string specifying the overlay text that should be + # drawn over the redacted region after the affected content has been + # removed. This entry is ignored if the RO entry is present. + if overlay_text is not None: + self[Name("OverlayText")] = String(overlay_text) + + # (Optional) If true, then the text specified by OverlayText should be + # repeated to fill the redacted region after the affected content has been + # removed. This entry is ignored if the RO entry is present. Default + # value: false. + if repeat_overlay_text is not None: + assert overlay_text is not None + self[Name("Repeat")] = Boolean(repeat_overlay_text) + + # (Optional; PDF 1.2) An appearance dictionary specifying how the + # annotation shall be presented visually on the page (see 12.5.5, + # “Appearance Streams”). Individual annotation handlers may ignore this + # entry and provide their own appearances. + self[Name("AP")] = Dictionary() + self["AP"][Name("N")] = Stream() + self["AP"]["N"][Name("Type")] = Name("XObject") + self["AP"]["N"][Name("Subtype")] = Name("Form") + appearance_stream_content = "q" + if stroke_color is not None: + appearance_stream_content += " %f %f %f RG" % ( + stroke_color.to_rgb().red, + stroke_color.to_rgb().green, + stroke_color.to_rgb().blue, + ) + if fill_color is not None: + appearance_stream_content += " %f %f %f rg" % ( + fill_color.to_rgb().red, + fill_color.to_rgb().green, + fill_color.to_rgb().blue, + ) + if stroke_color is not None and fill_color is not None: + appearance_stream_content += " %f w 0 0 100 100 re b" % stroke_width + elif stroke_color is not None: + appearance_stream_content += " %f w 0 0 100 100 re s" % stroke_width + elif fill_color is not None: + appearance_stream_content += " %f w 0 0 100 100 re f" % stroke_width + appearance_stream_content += " Q" + self["AP"]["N"][Name("DecodedBytes")] = bytes( + appearance_stream_content, "latin1" + ) + self["AP"]["N"][Name("Bytes")] = zlib.compress( + self["AP"]["N"][Name("DecodedBytes")] + ) + self["AP"]["N"][Name("Length")] = bDecimal(len(self["AP"]["N"][Name("Bytes")])) + self["AP"]["N"][Name("Filter")] = Name("FlateDecode") + + # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. + # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect + # entry in the widget annotation dictionary). + self["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(100)) + self["AP"]["N"]["BBox"].append(bDecimal(100)) diff --git a/borb/pdf/canvas/layout/annotation/remote_go_to_annotation.py b/borb/pdf/canvas/layout/annotation/remote_go_to_annotation.py new file mode 100644 index 000000000..a0cd47d66 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/remote_go_to_annotation.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, +“Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary +entries specific to this type of annotation. +This method adds a link annotation with an action that opens a remote URI. +""" +from borb.io.read.types import Name, String, Dictionary +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class RemoteGoToAnnotation(Annotation): + """ + A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, + “Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary + entries specific to this type of annotation. + This method adds a link annotation with an action that opens a remote URI. + """ + + def __init__(self, bounding_box: Rectangle, uri: str): + super(RemoteGoToAnnotation, self).__init__(bounding_box) + + # (Required) The type of annotation that this dictionary describes; shall be + # Link for a link annotation. + self[Name("Subtype")] = Name("Link") + + # (Optional; PDF 1.1) An action that shall be performed when the link + # annotation is activated (see 12.6, “Actions”). + self[Name("A")] = Dictionary() + self["A"][Name("Type")] = Name("Action") + self["A"][Name("S")] = Name("URI") + self["A"][Name("URI")] = String(uri) diff --git a/borb/pdf/canvas/layout/annotation/rubber_stamp_annotation.py b/borb/pdf/canvas/layout/annotation/rubber_stamp_annotation.py new file mode 100644 index 000000000..1153e0b1c --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/rubber_stamp_annotation.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A rubber stamp annotation (PDF 1.3) displays text or graphics intended to look as if they were stamped on the +page with a rubber stamp. When opened, it shall display a pop-up window containing the text of the associated +note. Table 181 shows the annotation dictionary entries specific to this type of annotation. +""" +import enum +import typing + +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.io.read.types import Name, Decimal as bDecimal +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class RubberStampAnnotationIconType(enum.Enum): + """ + This Enum represents all possible rubber stamp annotation icons + """ + + APPROVED = Name("Approved") + AS_IS = Name("AsIs") + CONFIDENTIAL = Name("Confidential") + DEPARTMENTAL = Name("Departmental") + DRAFT = Name("Draft") + EXPERIMENTAL = Name("Experimental") + EXPIRED = Name("Expired") + FINAL = Name("Final") + FOR_COMMENT = Name("ForComment") + FOR_PUBLIC_RELEASE = Name("ForPublicRelease") + NOT_APPROVED = Name("NotApproved") + NOT_FOR_PUBLIC_RELEASE = Name("NotForPublicRelease") + SOLD = Name("Sold") + TOP_SECRET = Name("TopSecret") + + +class RubberStampAnnotation(Annotation): + """ + A rubber stamp annotation (PDF 1.3) displays text or graphics intended to look as if they were stamped on the + page with a rubber stamp. When opened, it shall display a pop-up window containing the text of the associated + note. Table 181 shows the annotation dictionary entries specific to this type of annotation. + """ + + def __init__( + self, + bounding_box: Rectangle, + name: RubberStampAnnotationIconType = RubberStampAnnotationIconType.DRAFT, + contents: typing.Optional[str] = None, + color: typing.Optional[Color] = None, + ): + super(RubberStampAnnotation, self).__init__( + bounding_box=bounding_box, contents=contents, color=color + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Stamp for a rubber stamp annotation. + self[Name("Subtype")] = Name("Stamp") + + # (Optional) The name of an icon that shall be used in displaying the annotation. Conforming readers shall provide predefined icon + # appearances for at least the following standard names: + # Approved, Experimental, NotApproved, AsIs, + # Expired, NotForPublicRelease, Confidential, Final, Sold, + # Departmental, ForComment, TopSecret, Draft, ForPublicRelease + # Additional names may be supported as well. Default value: Draft. + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.” + self[Name("Name")] = name.value + + # (Optional; PDF 1.4) The constant opacity value that shall be used in + # painting the annotation (see Sections 11.2, “Overview of Transparency,” + # and 11.3.7, “Shape and Opacity Computations”). This value shall apply to + # all visible elements of the annotation in its closed state (including its + # background and border) but not to the pop-up window that appears when + # the annotation is opened. + self[Name("CA")] = bDecimal(1) diff --git a/borb/pdf/canvas/layout/annotation/screen_annotation.py b/borb/pdf/canvas/layout/annotation/screen_annotation.py new file mode 100644 index 000000000..cf3dc2b92 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/screen_annotation.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A screen annotation (PDF 1.5) specifies a region of a page upon which media clips may be played. It also +serves as an object from which actions can be triggered. 12.6.4.13, “Rendition Actions” discusses the +relationship between screen annotations and rendition actions. Table 187 shows the annotation dictionary +entries specific to this type of annotation. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class ScreenAnnotation(Annotation): + """ + A screen annotation (PDF 1.5) specifies a region of a page upon which media clips may be played. It also + serves as an object from which actions can be triggered. 12.6.4.13, “Rendition Actions” discusses the + relationship between screen annotations and rendition actions. Table 187 shows the annotation dictionary + entries specific to this type of annotation. + """ + + def __init__(self): + super(ScreenAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/sound_annotation.py b/borb/pdf/canvas/layout/annotation/sound_annotation.py new file mode 100644 index 000000000..b2105874f --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/sound_annotation.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A sound annotation (PDF 1.2) shall analogous to a text annotation except that instead of a text note, it contains +sound recorded from the computer’s microphone or imported from a file. When the annotation is activated, the +sound shall be played. The annotation shall behave like a text annotation in most ways, with a different icon (by +default, a speaker) to indicate that it represents a sound. Table 185 shows the annotation dictionary entries +specific to this type of annotation. Sound objects are discussed in 13.3, “Sounds.” +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class SoundAnnotation(Annotation): + """ + A sound annotation (PDF 1.2) shall analogous to a text annotation except that instead of a text note, it contains + sound recorded from the computer’s microphone or imported from a file. When the annotation is activated, the + sound shall be played. The annotation shall behave like a text annotation in most ways, with a different icon (by + default, a speaker) to indicate that it represents a sound. Table 185 shows the annotation dictionary entries + specific to this type of annotation. Sound objects are discussed in 13.3, “Sounds.” + """ + + def __init__(self): + super(SoundAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/square_annotation.py b/borb/pdf/canvas/layout/annotation/square_annotation.py new file mode 100644 index 000000000..59f25e328 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/square_annotation.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When +opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse +shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see +Table 168). +""" +import typing +from decimal import Decimal + +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class SquareAnnotation(Annotation): + """ + Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When + opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse + shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see + Table 168). + """ + + def __init__( + self, + bounding_box: Rectangle, + fill_color: typing.Optional[Color] = None, + stroke_color: typing.Optional[Color] = None, + rectangle_difference: typing.Optional[ + typing.Tuple[Decimal, Decimal, Decimal, Decimal] + ] = None, + ): + super(SquareAnnotation, self).__init__( + bounding_box=bounding_box, color=stroke_color + ) + + # (Required) The type of annotation that this dictionary describes; shall be + # Square or Circle for a square or circle annotation, respectively. + self[Name("Subtype")] = Name("Square") + + # (Optional) A border style dictionary (see Table 166) specifying the line + # width and dash pattern that shall be used in drawing the rectangle or + # ellipse. + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the Rect and BS entries; see Table 168 and 12.5.5, “Appearance + # Streams.” + # self[Name("BS")] = None + + # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to + # 1.0 and shall specify the interior color with which to fill the annotation’s + # rectangle or ellipse. The number of array elements determines the colour + # space in which the colour shall be defined + if fill_color is not None: + self[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["IC"].append(bDecimal(fill_color.to_rgb().red)) + self["IC"].append(bDecimal(fill_color.to_rgb().green)) + self["IC"].append(bDecimal(fill_color.to_rgb().blue)) + + # (Optional; PDF 1.5) A border effect dictionary describing an effect applied + # to the border described by the BS entry (see Table 167). + # self[Name("BE")] = None + + # (Optional; PDF 1.5) A set of four numbers that shall describe the + # numerical differences between two rectangles: the Rect entry of the + # annotation and the actual boundaries of the underlying square or circle. + # Such a difference may occur in situations where a border effect + # (described by BE) causes the size of the Rect to increase beyond that of + # the square or circle. + # The four numbers shall correspond to the differences in default user + # space between the left, top, right, and bottom coordinates of Rect and + # those of the square or circle, respectively. Each value shall be greater + # than or equal to 0. The sum of the top and bottom differences shall be + # less than the height of Rect, and the sum of the left and right differences + # shall be less than the width of Rect. + if rectangle_difference is not None: + self[Name("RD")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["RD"].append(bDecimal(rectangle_difference[0])) + self["RD"].append(bDecimal(rectangle_difference[1])) + self["RD"].append(bDecimal(rectangle_difference[2])) + self["RD"].append(bDecimal(rectangle_difference[3])) diff --git a/borb/pdf/canvas/layout/annotation/squiggly_annotation.py b/borb/pdf/canvas/layout/annotation/squiggly_annotation.py new file mode 100644 index 000000000..ac0af7179 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/squiggly_annotation.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) +underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing +the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of +annotations. +""" +import zlib +from decimal import Decimal + +from borb.io.read.types import Name, Stream, Dictionary, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class SquigglyAnnotation(Annotation): + """ + Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) + underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing + the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of + annotations. + """ + + def __init__( + self, + bounding_box: Rectangle, + stroke_width: Decimal = Decimal(1), + stroke_color: Color = HexColor("ff0000"), + ): + super(SquigglyAnnotation, self).__init__(bounding_box) + + # (Required) The type of annotation that this dictionary describes; shall + # be Redact for a redaction annotation. + self[Name("Subtype")] = Name("Squiggly") + + # (Optional; PDF 1.2) An appearance dictionary specifying how the + # annotation shall be presented visually on the page (see 12.5.5, + # “Appearance Streams”). Individual annotation handlers may ignore this + # entry and provide their own appearances. + self[Name("AP")] = Dictionary() + self["AP"][Name("N")] = Stream() + self["AP"]["N"][Name("Type")] = Name("XObject") + self["AP"]["N"][Name("Subtype")] = Name("Form") + + appearance_stream_content = "q %f %f %f RG %f w 0 0 m " % ( + stroke_color.to_rgb().red, + stroke_color.to_rgb().green, + stroke_color.to_rgb().blue, + stroke_width, + ) + for x in range(0, int(bounding_box.width), 5): + appearance_stream_content += "%f %f l %f %f l " % (x, 0, x + 2.5, 7) + appearance_stream_content += "%f %f l " % ( + bounding_box.width - bounding_box.width % 5 + 5, + 0, + ) + appearance_stream_content += "S Q" + self["AP"]["N"][Name("DecodedBytes")] = bytes( + appearance_stream_content, "latin1" + ) + self["AP"]["N"][Name("Bytes")] = zlib.compress( + self["AP"]["N"][Name("DecodedBytes")] + ) + self["AP"]["N"][Name("Length")] = bDecimal(len(self["AP"]["N"][Name("Bytes")])) + self["AP"]["N"][Name("Filter")] = Name("FlateDecode") + + # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. + # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect + # entry in the widget annotation dictionary). + self["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(bounding_box.width)) + self["AP"]["N"]["BBox"].append(bDecimal(100)) diff --git a/borb/pdf/canvas/layout/annotation/strike_out_annotation.py b/borb/pdf/canvas/layout/annotation/strike_out_annotation.py new file mode 100644 index 000000000..66d9fc696 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/strike_out_annotation.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) +underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing +the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of +annotations. +""" +import zlib +from decimal import Decimal + +from borb.io.read.types import Name, Dictionary, Stream, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import Color, HexColor +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class StrikeOutAnnotation(Annotation): + """ + Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) + underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing + the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of + annotations. + """ + + def __init__( + self, + bounding_box: Rectangle, + stroke_color: Color = HexColor("ff0000"), + stroke_width: Decimal = Decimal(1), + ): + super(StrikeOutAnnotation, self).__init__(bounding_box=bounding_box) + + # (Required) The type of annotation that this dictionary describes; shall + # be Redact for a redaction annotation. + self[Name("Subtype")] = Name("StrikeOut") + + # (Optional; PDF 1.2) An appearance dictionary specifying how the + # annotation shall be presented visually on the page (see 12.5.5, + # “Appearance Streams”). Individual annotation handlers may ignore this + # entry and provide their own appearances. + self[Name("AP")] = Dictionary() + self["AP"][Name("N")] = Stream() + self["AP"]["N"][Name("Type")] = Name("XObject") + self["AP"]["N"][Name("Subtype")] = Name("Form") + + appearance_stream_content = "q %f %f %f RG %f w 0 40 m %f 40 l S Q" % ( + stroke_color.to_rgb().red, + stroke_color.to_rgb().green, + stroke_color.to_rgb().blue, + stroke_width, + bounding_box.width, + ) + self["AP"]["N"][Name("DecodedBytes")] = bytes( + appearance_stream_content, "latin1" + ) + self["AP"]["N"][Name("Bytes")] = zlib.compress( + self["AP"]["N"][Name("DecodedBytes")] + ) + self["AP"]["N"][Name("Length")] = bDecimal(len(self["AP"]["N"][Name("Bytes")])) + self["AP"]["N"][Name("Filter")] = Name("FlateDecode") + + # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. + # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect + # entry in the widget annotation dictionary). + self["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(0)) + self["AP"]["N"]["BBox"].append(bDecimal(bounding_box.width)) + self["AP"]["N"]["BBox"].append(bDecimal(100)) diff --git a/borb/pdf/canvas/layout/annotation/text_annotation.py b/borb/pdf/canvas/layout/annotation/text_annotation.py new file mode 100644 index 000000000..b5bb70586 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/text_annotation.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A text annotation represents a “sticky note” attached to a point in the PDF document. When closed, the +annotation shall appear as an icon; when open, it shall display a pop-up window containing the text of the note +in a font and size chosen by the conforming reader. Text annotations shall not scale and rotate with the page; +they shall behave as if the NoZoom and NoRotate annotation flags (see Table 165) were always set. Table 172 +shows the annotation dictionary entries specific to this type of annotation. +""" +import enum +import typing + +from borb.io.read.types import Name, Boolean +from borb.pdf.canvas.color.color import Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class TextAnnotationIconType(enum.Enum): + """ + This Enum represents all possible text annotation icon types + """ + + COMMENT = Name("Comment") + HELP = Name("Help") + INSERT = Name("Insert") + KEY = Name("Key") + NEW_PARAGRAPH = Name("NewParagraph") + NOTE = Name("Note") + PARAGRAPH = Name("Paragraph") + + +class TextAnnotation(Annotation): + """ + A text annotation represents a “sticky note” attached to a point in the PDF document. When closed, the + annotation shall appear as an icon; when open, it shall display a pop-up window containing the text of the note + in a font and size chosen by the conforming reader. Text annotations shall not scale and rotate with the page; + they shall behave as if the NoZoom and NoRotate annotation flags (see Table 165) were always set. Table 172 + shows the annotation dictionary entries specific to this type of annotation. + """ + + def __init__( + self, + bounding_box: Rectangle, + contents: str, + color: typing.Optional[Color] = None, + text_annotation_icon: TextAnnotationIconType = TextAnnotationIconType.COMMENT, + open: typing.Optional[bool] = None, + ): + super(TextAnnotation, self).__init__( + bounding_box=bounding_box, contents=contents, color=color + ) + + # (Optional) A flag specifying whether the annotation shall initially be + # displayed open. Default value: false (closed). + if open is not None: + self[Name("Open")] = Boolean(open) + + # (Optional) The name of an icon that shall be used in displaying the + # annotation. Conforming readers shall provide predefined icon + # appearances for at least the following standard names: + # Comment, Key, Note, Help, NewParagraph, Paragraph, Insert + # Additional names may be supported as well. Default value: Note. + # The annotation dictionary’s AP entry, if present, shall take precedence + # over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.” + self[Name("Name")] = text_annotation_icon.value diff --git a/borb/pdf/canvas/layout/annotation/three_d_annotation.py b/borb/pdf/canvas/layout/annotation/three_d_annotation.py new file mode 100644 index 000000000..ed98d657f --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/three_d_annotation.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +3D annotations (PDF 1.6) are the means by which 3D artwork shall be represented in a PDF document. +Table 298 shows the entries specific to a 3D annotation dictionary. Table 164 describes the entries common to +all annotation dictionaries. + +In addition to these entries, a 3D annotation shall provide an appearance stream in its AP entry (see Table 164) +that has a normal appearance (the N entry in Table 168). This appearance may be used by applications that do +not support 3D annotations and by all applications for the initial display of the annotation. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class ThreeDAnnotation(Annotation): + """ + 3D annotations (PDF 1.6) are the means by which 3D artwork shall be represented in a PDF document. + Table 298 shows the entries specific to a 3D annotation dictionary. Table 164 describes the entries common to + all annotation dictionaries. + + In addition to these entries, a 3D annotation shall provide an appearance stream in its AP entry (see Table 164) + that has a normal appearance (the N entry in Table 168). This appearance may be used by applications that do + not support 3D annotations and by all applications for the initial display of the annotation. + """ + + def __init__(self): + super(ThreeDAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/trap_net_annotation.py b/borb/pdf/canvas/layout/annotation/trap_net_annotation.py new file mode 100644 index 000000000..cad65e4a9 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/trap_net_annotation.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A trap network annotation (PDF 1.3) may be used to define the trapping characteristics for a page of a PDF +document. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class TrapNetAnnotation(Annotation): + """ + A trap network annotation (PDF 1.3) may be used to define the trapping characteristics for a page of a PDF + document. + """ + + def __init__(self): + super(TrapNetAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/underline_annotation.py b/borb/pdf/canvas/layout/annotation/underline_annotation.py new file mode 100644 index 000000000..2e8e664d4 --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/underline_annotation.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) +underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing +the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of +annotations. +""" +from borb.io.read.types import Name, List, Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class UnderlineAnnotation(Annotation): + """ + Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) + underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing + the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of + annotations. + """ + + def __init__( + self, bounding_box: Rectangle, stroke_color: Color = HexColor("faed27") + ): + + super(UnderlineAnnotation, self).__init__( + bounding_box=bounding_box, color=stroke_color + ) + + # (Required) The type of annotation that this dictionary describes; shall + # be Redact for a redaction annotation. + self[Name("Subtype")] = Name("Underline") + + # (Required) An array of 8 × n numbers specifying the coordinates of n + # quadrilaterals in default user space. Each quadrilateral shall + # encompasses a word or group of contiguous words in the text + # underlying the annotation. The coordinates for each quadrilateral shall + # be given in the order + self[Name("QuadPoints")] = List() + self["QuadPoints"].append(bDecimal(bounding_box.get_x())) + self["QuadPoints"].append( + bDecimal(bounding_box.get_y() + bounding_box.get_height()) + ) + self["QuadPoints"].append( + bDecimal(bounding_box.get_x() + bounding_box.get_width()) + ) + self["QuadPoints"].append( + bDecimal(bounding_box.get_y() + bounding_box.get_height()) + ) + self["QuadPoints"].append(bDecimal(bounding_box.get_x())) + self["QuadPoints"].append(bDecimal(bounding_box.get_y())) + self["QuadPoints"].append( + bDecimal(bounding_box.get_x() + bounding_box.get_width()) + ) + self["QuadPoints"].append(bDecimal(bounding_box.get_y())) + + # (PDF 1.0) The array consists of three numbers defining the horizontal + # corner radius, vertical corner radius, and border width, all in default user + # space units. If the corner radii are 0, the border has square (not rounded) + # corners; if the border width is 0, no border is drawn. + self[Name("Border")] = List() + self["Border"].append(bDecimal(0)) + self["Border"].append(bDecimal(0)) + self["Border"].append(bDecimal(1)) diff --git a/borb/pdf/canvas/layout/annotation/watermark_annotation.py b/borb/pdf/canvas/layout/annotation/watermark_annotation.py new file mode 100644 index 000000000..cf09932cc --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/watermark_annotation.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +A watermark annotation (PDF 1.6) shall be used to represent graphics that shall be printed at a fixed size and +position on a page, regardless of the dimensions of the printed page. The FixedPrint entry of a watermark +annotation dictionary (see Table 190) shall be a dictionary that contains values for specifying the size and +position of the annotation (see Table 191). +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class WatermarkAnnotation(Annotation): + """ + A watermark annotation (PDF 1.6) shall be used to represent graphics that shall be printed at a fixed size and + position on a page, regardless of the dimensions of the printed page. The FixedPrint entry of a watermark + annotation dictionary (see Table 190) shall be a dictionary that contains values for specifying the size and + position of the annotation (see Table 191). + """ + + def __init__(self): + super(WatermarkAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/annotation/widget_annotation.py b/borb/pdf/canvas/layout/annotation/widget_annotation.py new file mode 100644 index 000000000..0e6cd207a --- /dev/null +++ b/borb/pdf/canvas/layout/annotation/widget_annotation.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Interactive forms (see 12.7, “Interactive Forms”) use widget annotations (PDF 1.2) to represent the appearance +of fields and to manage user interactions. As a convenience, when a field has only a single associated widget +annotation, the contents of the field dictionary (12.7.3, “Field Dictionaries”) and the annotation dictionary may +be merged into a single dictionary containing entries that pertain to both a field and an annotation. +""" +from borb.pdf.canvas.layout.annotation.annotation import Annotation + + +class WidgetAnnotation(Annotation): + """ + Interactive forms (see 12.7, “Interactive Forms”) use widget annotations (PDF 1.2) to represent the appearance + of fields and to manage user interactions. As a convenience, when a field has only a single associated widget + annotation, the contents of the field dictionary (12.7.3, “Field Dictionaries”) and the annotation dictionary may + be merged into a single dictionary containing entries that pertain to both a field and an annotation. + """ + + def __init__(self): + super(WidgetAnnotation, self).__init__() + # TODO diff --git a/borb/pdf/canvas/layout/forms/country_drop_down_list.py b/borb/pdf/canvas/layout/forms/country_drop_down_list.py index 5dd750dba..c8ad24420 100644 --- a/borb/pdf/canvas/layout/forms/country_drop_down_list.py +++ b/borb/pdf/canvas/layout/forms/country_drop_down_list.py @@ -216,17 +216,33 @@ class CountryDropDownList(DropDownList): def __init__( self, - font_size: Decimal = Decimal(12), - font_color: Color = HexColor("000000"), - value: str = "", default_value: str = "", field_name: typing.Optional[str] = None, + font_color: Color = HexColor("000000"), + font_size: Decimal = Decimal(12), + margin_bottom: typing.Optional[Decimal] = None, + margin_left: typing.Optional[Decimal] = None, + margin_right: typing.Optional[Decimal] = None, + margin_top: typing.Optional[Decimal] = None, + padding_bottom: Decimal = Decimal(0), + padding_left: Decimal = Decimal(0), + padding_right: Decimal = Decimal(0), + padding_top: Decimal = Decimal(0), + value: str = "", ): super(CountryDropDownList, self).__init__( - possible_values=CountryDropDownList.COUNTRIES, - font_size=font_size, - font_color=font_color, - value=value, default_value=default_value, field_name=field_name, + font_color=font_color, + font_size=font_size, + margin_bottom=margin_bottom, + margin_left=margin_left, + margin_right=margin_right, + margin_top=margin_top, + padding_bottom=padding_bottom, + padding_left=padding_left, + padding_right=padding_right, + padding_top=padding_top, + possible_values=CountryDropDownList.COUNTRIES, + value=value, ) diff --git a/borb/pdf/canvas/layout/forms/drop_down_list.py b/borb/pdf/canvas/layout/forms/drop_down_list.py index f31f5cf73..fd5051120 100644 --- a/borb/pdf/canvas/layout/forms/drop_down_list.py +++ b/borb/pdf/canvas/layout/forms/drop_down_list.py @@ -24,12 +24,20 @@ class DropDownList(FormField): def __init__( self, - possible_values: typing.List[str], - font_size: Decimal = Decimal(12), - font_color: Color = HexColor("000000"), - value: str = "", default_value: str = "", field_name: typing.Optional[str] = None, + font_color: Color = HexColor("000000"), + font_size: Decimal = Decimal(12), + margin_bottom: typing.Optional[Decimal] = None, + margin_left: typing.Optional[Decimal] = None, + margin_right: typing.Optional[Decimal] = None, + margin_top: typing.Optional[Decimal] = None, + padding_bottom: Decimal = Decimal(0), + padding_left: Decimal = Decimal(0), + padding_right: Decimal = Decimal(0), + padding_top: Decimal = Decimal(0), + possible_values: typing.List[str] = [], + value: str = "", ): super(DropDownList, self).__init__() assert font_size >= 0 diff --git a/borb/pdf/canvas/layout/forms/form_field.py b/borb/pdf/canvas/layout/forms/form_field.py index 1ea71ef28..4ee490b39 100644 --- a/borb/pdf/canvas/layout/forms/form_field.py +++ b/borb/pdf/canvas/layout/forms/form_field.py @@ -40,7 +40,7 @@ def _get_auto_generated_field_name(self, page: Page) -> str: if isinstance(d, List): for c in d: stk.append(c) - return "Field %d" % (number_of_fields + 1) + return "field-{0:03d}".format(number_of_fields) def _get_font_resource_name(self, font: Font, page: Page): # create resources if needed diff --git a/borb/pdf/canvas/layout/forms/push_button.py b/borb/pdf/canvas/layout/forms/push_button.py new file mode 100644 index 000000000..773f15bba --- /dev/null +++ b/borb/pdf/canvas/layout/forms/push_button.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +This implementation of FormField represents a push button. +""" +import typing +import zlib +from decimal import Decimal + +from borb.io.read.types import Dictionary, Name, List, String, Stream, Boolean +from borb.io.read.types import Decimal as bDecimal +from borb.pdf.canvas.color.color import HexColor, Color, X11Color +from borb.pdf.canvas.font.simple_font.font_type_1 import StandardType1Font +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation +from borb.pdf.canvas.layout.forms.form_field import FormField +from borb.pdf.canvas.layout.layout_element import Alignment +from borb.pdf.canvas.layout.text.line_of_text import LineOfText +from borb.pdf.page.page import Page + + +class PushButton(FormField): + """ + This implementation of FormField represents a push button. + """ + + def __init__( + self, + text: str, + background_color: typing.Optional[Color] = HexColor("efefef"), + border_bottom: bool = True, + border_color: Color = HexColor("767676"), + border_left: bool = True, + border_right: bool = True, + border_top: bool = True, + border_width: Decimal = Decimal(1), + field_name: typing.Optional[str] = None, + font_size: typing.Optional[Decimal] = Decimal(12), + font_color: Color = HexColor("000000"), + horizontal_alignment: Alignment = Alignment.LEFT, + margin_bottom: typing.Optional[Decimal] = Decimal(0), + margin_left: typing.Optional[Decimal] = Decimal(0), + margin_right: typing.Optional[Decimal] = Decimal(0), + margin_top: typing.Optional[Decimal] = Decimal(0), + padding_bottom: Decimal = Decimal(2), + padding_left: Decimal = Decimal(6), + padding_right: Decimal = Decimal(6), + padding_top: Decimal = Decimal(2), + ): + super(PushButton, self).__init__() + assert len(text) > 0 + self._text = text + self._background_color = background_color + self._border_bottom = border_bottom + self._border_color = border_color + self._border_left = border_left + self._border_right = border_right + self._border_top = border_top + assert border_width >= 0 + self._border_width = border_width + self._field_name: typing.Optional[str] = field_name + assert font_size >= 0 + self._font_size = font_size + self._font_color = font_color + self._horizontal_alignment = horizontal_alignment + assert margin_bottom >= 0 + self._margin_bottom = margin_bottom + assert margin_left >= 0 + self._margin_left = margin_left + assert margin_right >= 0 + self._margin_right = margin_right + assert margin_top >= 0 + self._margin_top = margin_top + assert padding_bottom >= 0 + self._padding_bottom = padding_bottom + assert padding_left >= 0 + self._padding_left = padding_left + assert padding_right >= 0 + self._padding_right = padding_right + assert padding_top >= 0 + self._padding_top = padding_top + self._widget_dictionary: typing.Optional[Dictionary] = None + + def _init_widget_dictionary(self, page: Page) -> None: + if self._widget_dictionary is not None: + return + + # init page and font resources + assert self._font_size is not None + font_resource_name: Name = self._get_font_resource_name( + StandardType1Font("Helvetica"), page + ) + + # widget resource dictionary + widget_resources: Dictionary = Dictionary() + widget_resources[Name("Font")] = page["Resources"]["Font"] + + # get Catalog + catalog: Dictionary = page.get_root()["XRef"]["Trailer"]["Root"] # type: ignore [attr-defined] + + # widget dictionary + # fmt: off + self._widget_dictionary = Dictionary() + self._widget_dictionary[Name("AA")] = Dictionary() + self._widget_dictionary[Name("AA")][Name("D")] = Dictionary() + self._widget_dictionary[Name("AA")][Name("D")][Name("Type")] = Name("Action") + self._widget_dictionary[Name("AA")][Name("D")][Name("S")] = Name("ResetForm") + # fmt: on + + # create normal appearance + # fmt: off + self._widget_dictionary[Name("AP")] = Dictionary() + self._widget_dictionary[Name("AP")][Name("N")] = Stream() + self._widget_dictionary[Name("AP")][Name("N")][Name("Type")] = Name("XObject") + self._widget_dictionary[Name("AP")][Name("N")][Name("Subtype")] = Name("Form") + self._widget_dictionary[Name("AP")][Name("N")][Name("BBox")] = List().set_can_be_referenced(False) + for _ in range(0, 4): + self._widget_dictionary[Name("AP")][Name("N")][Name("BBox")].append(bDecimal(0)) + self._widget_dictionary[Name("AP")][Name("N")][Name("DecodedBytes")] = b"/Tx BMC EMC" + self._widget_dictionary[Name("AP")][Name("N")][Name("Bytes")] = zlib.compress(self._widget_dictionary[Name("AP")][Name("N")][Name("DecodedBytes")], 9) + self._widget_dictionary[Name("AP")][Name("N")][Name("Filter")] = Name("FlateDecode") + self._widget_dictionary[Name("AP")][Name("N")][Name("Length")] = bDecimal(len(self._widget_dictionary[Name("AP")][Name("N")][Name("Bytes")])) + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")] = Dictionary() + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")][Name("ProcSet")] = List().set_can_be_referenced(False) + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")][Name("ProcSet")].append(Name("PDF")) + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")][Name("ProcSet")].append(Name("Text")) + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")][Name("Font")] = Dictionary() + self._widget_dictionary[Name("AP")][Name("N")][Name("Resources")][Name("Font")] = page["Resources"]["Font"] + # fmt: on + + # create default appearance + # fmt: off + self._widget_dictionary[Name("DA")] = String("0.23921 0.23921 0.23921 rg /%s %f Tf" % (font_resource_name, self._font_size)) + self._widget_dictionary[Name("DR")] = widget_resources + # fmt: on + + # other flags + # fmt: off + self._widget_dictionary[Name("F")] = bDecimal(4) + self._widget_dictionary[Name("Ff")] = bDecimal(65536) + self._widget_dictionary[Name("FT")] = Name("Btn") + self._widget_dictionary[Name("MK")] = Dictionary() + self._widget_dictionary[Name("MK")][Name("BC")] = List().set_can_be_referenced(False) + self._widget_dictionary[Name("MK")][Name("BG")] = List().set_can_be_referenced(False) + self._widget_dictionary[Name("MK")][Name("CA")] = String("") + self._widget_dictionary[Name("P")] = catalog + self._widget_dictionary[Name("Q")] = bDecimal(1) + self._widget_dictionary[Name("Rect")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] + for _ in range(0, 4): + self._widget_dictionary[Name("Rect")].append(bDecimal(0)) + self._widget_dictionary[Name("Subtype")] = Name("Widget") + self._widget_dictionary[Name("T")] = String(self._field_name or self._get_auto_generated_field_name(page)) + self._widget_dictionary[Name("Type")] = Name("Annot") + # fmt: on + + # append field to page /Annots + if "Annots" not in page: + page[Name("Annots")] = List() + page["Annots"].append(self._widget_dictionary) + + # append field to catalog + if "AcroForm" not in catalog: + catalog[Name("AcroForm")] = Dictionary() + catalog["AcroForm"][Name("Fields")] = List() + catalog["AcroForm"][Name("DR")] = widget_resources + catalog["AcroForm"][Name("NeedAppearances")] = Boolean(True) + catalog["AcroForm"]["Fields"].append(self._widget_dictionary) + + def _do_layout(self, page: "Page", layout_box: Rectangle) -> Rectangle: + + # determine layout rectangle + assert self._font_size is not None + + # init self._widget_dictionary + self._init_widget_dictionary(page) + + # layout text + text_layout_box = LineOfText( + self._text, + background_color=self._background_color, + border_bottom=self._border_bottom, + border_color=self._border_color, + border_left=self._border_left, + border_right=self._border_right, + border_top=self._border_top, + border_width=self._border_width, + font_size=self._font_size, + font_color=self._font_color, + horizontal_alignment=self._horizontal_alignment, + margin_bottom=self._margin_bottom, + margin_left=self._margin_left, + margin_right=self._margin_right, + margin_top=self._margin_top, + padding_bottom=self._padding_bottom, + padding_left=self._padding_left, + padding_right=self._padding_right, + padding_top=self._padding_top, + ).layout(page, layout_box) + + # set location + # fmt: off + assert self._widget_dictionary is not None + self._widget_dictionary["Rect"][0] = bDecimal(text_layout_box.x) # ll_x + self._widget_dictionary["Rect"][1] = bDecimal(text_layout_box.y) # ll_y + self._widget_dictionary["Rect"][2] = bDecimal(text_layout_box.x + text_layout_box.width) # ur_x + self._widget_dictionary["Rect"][3] = bDecimal(text_layout_box.y + text_layout_box.height) # ur_y + # fmt: on + + # return Rectangle + return text_layout_box diff --git a/borb/pdf/canvas/layout/forms/text_field.py b/borb/pdf/canvas/layout/forms/text_field.py index 99ebbc386..6b21bb11c 100644 --- a/borb/pdf/canvas/layout/forms/text_field.py +++ b/borb/pdf/canvas/layout/forms/text_field.py @@ -24,19 +24,19 @@ class TextField(FormField): def __init__( self, - font_size: Decimal = Decimal(12), - font_color: Color = HexColor("000000"), - value: str = "", default_value: str = "", field_name: typing.Optional[str] = None, - padding_top: Decimal = Decimal(0), - padding_right: Decimal = Decimal(0), - padding_bottom: Decimal = Decimal(0), - padding_left: Decimal = Decimal(0), - margin_top: typing.Optional[Decimal] = None, - margin_right: typing.Optional[Decimal] = None, + font_color: Color = HexColor("000000"), + font_size: Decimal = Decimal(12), margin_bottom: typing.Optional[Decimal] = None, margin_left: typing.Optional[Decimal] = None, + margin_right: typing.Optional[Decimal] = None, + margin_top: typing.Optional[Decimal] = None, + padding_bottom: Decimal = Decimal(0), + padding_left: Decimal = Decimal(0), + padding_right: Decimal = Decimal(0), + padding_top: Decimal = Decimal(0), + value: str = "", ): super(TextField, self).__init__( padding_top=padding_top, @@ -81,11 +81,14 @@ def _init_widget_dictionary(self, page: Page, layout_box: Rectangle) -> None: widget_normal_appearance["BBox"].append(bDecimal(layout_box.width)) widget_normal_appearance["BBox"].append(bDecimal(self._font_size)) widget_normal_appearance[Name("Resources")] = widget_resources - bts = b"/Tx BMC EMC" - widget_normal_appearance[Name("DecodedBytes")] = bts - widget_normal_appearance[Name("Bytes")] = zlib.compress(bts, 9) + widget_normal_appearance[Name("DecodedBytes")] = b"/Tx BMC EMC" + widget_normal_appearance[Name("Bytes")] = zlib.compress( + widget_normal_appearance[Name("DecodedBytes")], 9 + ) widget_normal_appearance[Name("Filter")] = Name("FlateDecode") - widget_normal_appearance[Name("Length")] = bDecimal(len(bts)) + widget_normal_appearance[Name("Length")] = bDecimal( + len(widget_normal_appearance[Name("Bytes")]) + ) # widget appearance dictionary widget_appearance_dictionary: Dictionary = Dictionary() @@ -158,15 +161,15 @@ def _do_layout_without_padding( self._init_widget_dictionary(page, layout_rect) # set location + # fmt: off assert self._widget_dictionary is not None self._widget_dictionary["AP"]["N"]["BBox"][2] = bDecimal(layout_box.width) self._widget_dictionary["AP"]["N"]["BBox"][3] = bDecimal(self._font_size) self._widget_dictionary["Rect"][0] = bDecimal(layout_box.x) - self._widget_dictionary["Rect"][1] = bDecimal( - layout_box.y + layout_box.height - self._font_size - ) + self._widget_dictionary["Rect"][1] = bDecimal(layout_box.y + layout_box.height - self._font_size) self._widget_dictionary["Rect"][2] = bDecimal(layout_box.x + layout_box.width) self._widget_dictionary["Rect"][3] = bDecimal(layout_box.y + layout_box.height) + # fmt: on # return Rectangle return layout_rect diff --git a/borb/pdf/canvas/layout/page_layout/browser_layout.py b/borb/pdf/canvas/layout/page_layout/browser_layout.py index cf6cbd1d5..5d8a6640b 100644 --- a/borb/pdf/canvas/layout/page_layout/browser_layout.py +++ b/borb/pdf/canvas/layout/page_layout/browser_layout.py @@ -21,7 +21,7 @@ from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.heading import Heading from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page diff --git a/borb/pdf/canvas/layout/page_layout/multi_column_layout.py b/borb/pdf/canvas/layout/page_layout/multi_column_layout.py index 1c0a43b44..2c7c57ac9 100644 --- a/borb/pdf/canvas/layout/page_layout/multi_column_layout.py +++ b/borb/pdf/canvas/layout/page_layout/multi_column_layout.py @@ -16,7 +16,7 @@ from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page diff --git a/borb/pdf/canvas/layout/text/heading.py b/borb/pdf/canvas/layout/text/heading.py index a6fd09518..cdb78a040 100644 --- a/borb/pdf/canvas/layout/text/heading.py +++ b/borb/pdf/canvas/layout/text/heading.py @@ -11,10 +11,11 @@ from borb.pdf.canvas.color.color import Color, HexColor from borb.pdf.canvas.font.font import Font from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.link_annotation import DestinationType from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document -from borb.pdf.page.page import DestinationType, Page +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page class Heading(Paragraph): diff --git a/borb/pdf/document/__init__.py b/borb/pdf/document/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/borb/pdf/document.py b/borb/pdf/document/document.py similarity index 74% rename from borb/pdf/document.py rename to borb/pdf/document/document.py index 6125d0ccf..dde94296c 100644 --- a/borb/pdf/document.py +++ b/borb/pdf/document/document.py @@ -2,14 +2,17 @@ # -*- coding: utf-8 -*- """ - This class represents a PDF document +This class represents a PDF document """ import typing +import zlib from decimal import Decimal from borb.io.read.types import Decimal as bDecimal from borb.io.read.types import Dictionary, List, Name, Stream, String -from borb.pdf.page.page import DestinationType, Page +from borb.pdf.canvas.layout.annotation.link_annotation import DestinationType +from borb.pdf.document.name_tree import NameTree +from borb.pdf.page.page import Page from borb.pdf.trailer.document_info import DocumentInfo, XMPDocumentInfo from borb.pdf.xref.plaintext_xref import PlainTextXREF @@ -31,6 +34,10 @@ def get_xmp_document_info(self) -> XMPDocumentInfo: """ return XMPDocumentInfo(self) + # + # adding/removing pages + # + def get_page(self, page_number: int) -> Page: """ This function returns a Page (at given page_number) within this Document @@ -134,6 +141,10 @@ def pop_page(self, index: int) -> "Document": # type: ignore [name-specified] # return return self + # + # signatures + # + def has_signatures(self) -> bool: """ This function returns True if this Document has signatures, False otherwise @@ -150,6 +161,10 @@ def check_signatures(self) -> bool: # TODO return True + # + # outlines + # + def has_outlines(self) -> bool: """ A PDF document may contain a document outline that the conforming reader may display on the screen, @@ -334,6 +349,10 @@ def _children(x: Dictionary): return self + # + # embedded files + # + def append_embedded_file(self, file_name: str, file_bytes: bytes) -> "Document": """ If a PDF file contains file specifications that refer to an external file and the PDF file is archived or transmitted, @@ -344,83 +363,22 @@ def append_embedded_file(self, file_name: str, file_bytes: bytes) -> "Document": embedded files are included purely for convenience and need not be directly processed by any conforming reader.) This method embeds a file (specified by its name and bytes) into this Document """ - assert "XRef" in self - assert "Trailer" in self["XRef"] - assert "Root" in self["XRef"]["Trailer"] - root = self["XRef"]["Trailer"]["Root"] - # set up /Names dictionary - if "Names" not in root: - root[Name("Names")] = Dictionary() - names = root["Names"] + # build actual file stream + stream = Stream() + stream[Name("Type")] = Name("EmbeddedFile") + stream[Name("Bytes")] = file_bytes + stream[Name("Length")] = bDecimal(len(stream[Name("Bytes")])) - # set up /EmbeddedFiles - if "EmbeddedFiles" not in names: - names[Name("EmbeddedFiles")] = Dictionary() - names["EmbeddedFiles"][Name("Kids")] = List() + # build /EF NameTree node + leaf = Dictionary() + leaf[Name("EF")] = Dictionary() + leaf[Name("EF")][Name("F")] = stream + leaf[Name("F")] = String(file_name) + leaf[Name("Type")] = Name("Filespec") - # find parent - parent = names["EmbeddedFiles"] - while "Kids" in parent: - for k in parent["Kids"]: - lower_limit = str(k["Limits"][0]) - upper_limit = str(k["Limits"][1]) - if lower_limit == upper_limit: - continue - if lower_limit < file_name < upper_limit: - parent = k - break - break - - # add new child - if ( - len( - [ - x - for x in parent["Kids"] - if x["Limits"][0] == x["Limits"][1] == file_name - ] - ) - == 0 - ): - - kid = Dictionary() - kid[Name("F")] = String(file_name) - kid[Name("Type")] = Name("Filespec") - kid[Name("Limits")] = List() - for _ in range(0, 2): - kid["Limits"].append(String(file_name)) - - # build leaf /Names dictionary - names = List() - names.append(String(file_name)) - kid[Name("Names")] = names - - # build actual file stream - stream = Stream() - stream[Name("Type")] = Name("EmbeddedFile") - stream[Name("Bytes")] = file_bytes - stream[Name("Length")] = bDecimal(len(stream[Name("Bytes")])) - - # build leaf /Filespec dictionary - file_spec = Dictionary() - file_spec[Name("EF")] = Dictionary() - file_spec["EF"][Name("F")] = stream - file_spec[Name("F")] = String(file_name) - file_spec[Name("Type")] = Name("Filespec") - names.append(file_spec) - - # append - parent["Kids"].append(kid) - - # change existing child - else: - kid = [ - x - for x in parent["Kids"] - if x["Limits"][0] == x["Limits"][1] == file_name - ][0] - # TODO + # put + NameTree(self, name=Name("EmbeddedFiles")).put(file_name, leaf) # return return self @@ -435,42 +393,10 @@ def get_embedded_files(self) -> typing.Dict[str, bytes]: embedded files are included purely for convenience and need not be directly processed by any conforming reader.) This method returns all embedded files, as a dictionary of names unto bytes """ - assert "XRef" in self - assert "Trailer" in self["XRef"] - assert "Root" in self["XRef"]["Trailer"] - root = self["XRef"]["Trailer"]["Root"] - - # look up /Names dictionary - if "Names" not in root: - return {} - names = root["Names"] - - # look up /EmbeddedFiles dictionary - if "EmbeddedFiles" not in names: - return {} - - nodes_to_visit = [names["EmbeddedFiles"]] - file_names = [] - while len(nodes_to_visit) > 0: - n = nodes_to_visit[0] - nodes_to_visit.pop(0) - if "Kids" in n: - for k in n["Kids"]: - nodes_to_visit.append(k) - if "Limits" in n: - lower_limit = str(n["Limits"][0]) - upper_limit = str(n["Limits"][1]) - if upper_limit == lower_limit: - file_names.append(upper_limit) - - file_names_and_contents: typing.Dict[str, bytes] = {} - for n in file_names: - contents = self.get_embedded_file(n) - assert contents is not None - file_names_and_contents[n] = contents - - # return - return file_names_and_contents + return { + k: v["EF"]["F"]["DecodedBytes"] + for k, v in NameTree(self, Name("EmbeddedFiles")).items() + } def get_embedded_file(self, file_name: str) -> typing.Optional[bytes]: """ @@ -482,47 +408,36 @@ def get_embedded_file(self, file_name: str) -> typing.Optional[bytes]: embedded files are included purely for convenience and need not be directly processed by any conforming reader.) This method returns the embedded file specified by the given file_name """ - assert "XRef" in self - assert "Trailer" in self["XRef"] - assert "Root" in self["XRef"]["Trailer"] - root = self["XRef"]["Trailer"]["Root"] - - # look up /Names dictionary - if "Names" not in root: - return None - names = root["Names"] - # look up /EmbeddedFiles dictionary - if "EmbeddedFiles" not in names: - return None - - # find parent - parent = names["EmbeddedFiles"] - while "Kids" in parent: - for k in parent["Kids"]: - lower_limit = str(k["Limits"][0]) - upper_limit = str(k["Limits"][1]) - if lower_limit == upper_limit == file_name: - assert "Names" in k - assert isinstance(k["Names"], list) - assert len(k["Names"]) == 2 - assert str(k["Names"][0]) == file_name - - # go to /FileSpec leaf - file_spec_leaf = k["Names"][1] - assert isinstance(file_spec_leaf, dict) - assert "EF" in file_spec_leaf - assert isinstance(file_spec_leaf["EF"], dict) - assert "F" in file_spec_leaf["EF"] - assert isinstance(file_spec_leaf["EF"]["F"], Stream) - - # extract bytes from Stream - return file_spec_leaf["EF"]["F"]["DecodedBytes"] - - if lower_limit < file_name < upper_limit: - parent = k - break - break + for k, v in NameTree(self, Name("EmbeddedFiles")).items(): + if k == file_name: + return v["EF"]["F"]["DecodedBytes"] # default return None + + # + # embedded javascript + # + + def append_embedded_javascript(self, javascript: str) -> "Document": + + # build actual javascript stream + stream = Stream() + stream[Name("Type")] = Name("JavaScript") + stream[Name("DecodedBytes")] = bytes(javascript, "latin1") + stream[Name("Bytes")] = zlib.compress(stream[Name("DecodedBytes")], 9) + stream[Name("Length")] = bDecimal(len(stream[Name("Bytes")])) + stream[Name("Filter")] = Name("FlateDecode") + + # set up NameTree leaf + leaf = Dictionary() + leaf[Name("S")] = Name("JavaScript") + leaf[Name("JS")] = stream + + # put + nt: NameTree = NameTree(self, name=Name("JavaScript")) + nt.put("script-{0:03d}.js".format(len(nt)), leaf) + + # return + return self diff --git a/borb/pdf/document/name_tree.py b/borb/pdf/document/name_tree.py new file mode 100644 index 000000000..5a413300e --- /dev/null +++ b/borb/pdf/document/name_tree.py @@ -0,0 +1,128 @@ +import typing + +from borb.io.read.types import Dictionary, Name, List, String + + +class NameTree: + def __init__(self, document: Dictionary, name: Name): + self._document: Dictionary = document + self._name: Name = name + + def put(self, key: str, value: typing.Any): + + assert "XRef" in self._document + assert "Trailer" in self._document["XRef"] + assert "Root" in self._document["XRef"]["Trailer"] + root = self._document["XRef"]["Trailer"]["Root"] + + # set up /Names dictionary + if "Names" not in root: + root[Name("Names")] = Dictionary() + names = root["Names"] + + # set up /JavaScript + if self._name not in names: + names[self._name] = Dictionary() + names[self._name][Name("Kids")] = List() + + # find parent + parent = names[self._name] + while "Kids" in parent: + for k in parent["Kids"]: + lower_limit = str(k["Limits"][0]) + upper_limit = str(k["Limits"][1]) + if lower_limit == upper_limit: + continue + if lower_limit < key < upper_limit: + parent = k + break + break + + # insert as new child, or replace existing child? + if ( + len([x for x in parent["Kids"] if x["Limits"][0] == x["Limits"][1] == key]) + == 0 + ): + self._put_new(parent, key, value) + else: + self._put_existing(parent, key, value) + + def _put_new(self, parent: Dictionary, key: str, value: typing.Any): + + kid = Dictionary() + kid[Name("F")] = String(key) + kid[Name("Limits")] = List() + for _ in range(0, 2): + kid["Limits"].append(String(key)) + kid[Name("Names")] = List() + kid[Name("Names")].append(String(key)) + + # build leaf /Filespec dictionary + if self._name == "EmbeddedFiles": + kid[Name("Names")].append(value) + kid[Name("Type")] = Name("EF") + + # build leaf /JavaScript dictionary + if self._name == "JavaScript": + kid[Name("Names")].append(value) + + # append + parent["Kids"].append(kid) + + def _put_existing(self, parent: Dictionary, key: str, value: typing.Any): + pass + + # + # dictionary methods + # + + def get_keys(self) -> typing.List[String]: + return [k for k, v in self.items()] + + def get_values(self) -> typing.List[typing.Any]: + return [v for k, v in self.items()] + + def items(self) -> typing.Iterable[typing.Tuple[String, typing.Any]]: + + assert "XRef" in self._document + assert "Trailer" in self._document["XRef"] + assert "Root" in self._document["XRef"]["Trailer"] + root = self._document["XRef"]["Trailer"]["Root"] + + # set up /Names dictionary + if "Names" not in root: + root[Name("Names")] = Dictionary() + names = root["Names"] + + nodes_to_visit = [names[self._name]] + keys = [] + values = [] + while len(nodes_to_visit) > 0: + n = nodes_to_visit[0] + nodes_to_visit.pop(0) + if "Kids" in n: + for k in n["Kids"]: + nodes_to_visit.append(k) + if "Limits" in n: + lower_limit = str(n["Limits"][0]) + upper_limit = str(n["Limits"][1]) + if upper_limit == lower_limit: + keys.append(upper_limit) + values.append(n["Names"][1]) + + # return + return zip(keys, values) + + # + # utility functions + # + + def _get_root_or_empty(self): + assert "XRef" in self._document + assert "Trailer" in self._document["XRef"] + assert "Root" in self._document["XRef"]["Trailer"] + root = self._document["XRef"]["Trailer"]["Root"] + return root.get(Name("Names"), Dictionary()) + + def __len__(self): + return len(self._get_root_or_empty()) diff --git a/borb/pdf/page/page.py b/borb/pdf/page/page.py index 9358c788d..96dd97b49 100644 --- a/borb/pdf/page/page.py +++ b/borb/pdf/page/page.py @@ -18,76 +18,10 @@ from borb.pdf.canvas.canvas import Canvas from borb.pdf.canvas.color.color import Color, HexColor, X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.annotation import Annotation from borb.pdf.page.page_info import PageInfo -class RubberStampAnnotationIconType(enum.Enum): - """ - This Enum represents all possible rubber stamp annotation icons - """ - - APPROVED = Name("Approved") - AS_IS = Name("AsIs") - CONFIDENTIAL = Name("Confidential") - DEPARTMENTAL = Name("Departmental") - DRAFT = Name("Draft") - EXPERIMENTAL = Name("Experimental") - EXPIRED = Name("Expired") - FINAL = Name("Final") - FOR_COMMENT = Name("ForComment") - FOR_PUBLIC_RELEASE = Name("ForPublicRelease") - NOT_APPROVED = Name("NotApproved") - NOT_FOR_PUBLIC_RELEASE = Name("NotForPublicRelease") - SOLD = Name("Sold") - TOP_SECRET = Name("TopSecret") - - -class DestinationType(enum.Enum): - """ - This Enum represents all possible destination types (when adding a link annotation) - """ - - FIT = Name("Fit") - FIT_B = Name("FitB") - FIT_B_H = Name("FitBH") - FIT_B_V = Name("FitBV") - FIT_H = Name("FitH") - FIT_R = Name("FitR") - FIT_V = Name("FitV") - X_Y_Z = Name("XYZ") - - -class TextAnnotationIconType(enum.Enum): - """ - This Enum represents all possible text annotation icon types - """ - - COMMENT = Name("Comment") - HELP = Name("Help") - INSERT = Name("Insert") - KEY = Name("Key") - NEW_PARAGRAPH = Name("NewParagraph") - NOTE = Name("Note") - PARAGRAPH = Name("Paragraph") - - -class LineEndStyleType(enum.Enum): - """ - This Enum represents all possible line end styles - """ - - SQUARE = Name("Square") - CIRCLE = Name("Circle") - DIAMOND = Name("Diamond") - OPEN_ARROW = Name("OpenArrow") - CLOSED_ARROW = Name("ClosedArrow") - NONE = Name("None") - BUTT = Name("Butt") - RIGHT_OPEN_ARROW = Name("ROpenArrow") - RIGHT_CLOSED_ARROW = Name("RClosedArrow") - SLASH = Name("Slash") - - class Page(Dictionary): """ This class represents a single page in a PDF document @@ -278,38 +212,7 @@ def get_annotations(self) -> List: self[Name("Annots")] = List() return self["Annots"] - def _create_annotation( - self, - rectangle: Rectangle, - contents: Optional[str] = None, - color: Optional[Color] = None, - border_horizontal_corner_radius: Optional[Decimal] = None, - border_vertical_corner_radius: Optional[Decimal] = None, - border_width: Optional[Decimal] = None, - ): - annot = Dictionary() - - # (Optional) The type of PDF object that this dictionary describes; if - # present, shall be Annot for an annotation dictionary. - annot[Name("Type")] = Name("Annot") - - # (Required) The annotation rectangle, defining the location of the - # annotation on the page in default user space units. - annot[Name("Rect")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["Rect"].append(bDecimal(rectangle.get_x())) - annot["Rect"].append(bDecimal(rectangle.get_y())) - annot["Rect"].append(bDecimal(rectangle.get_x() + rectangle.get_width())) - annot["Rect"].append(bDecimal(rectangle.get_y() + rectangle.get_height())) - - # (Optional) Text that shall be displayed for the annotation or, if this type of - # annotation does not display text, an alternate description of the - # annotation’s contents in human-readable form. In either case, this text is - # useful when extracting the document’s contents in support of - # accessibility to users with disabilities or for other purposes (see 14.9.3, - # “Alternate Descriptions”). See 12.5.6, “Annotation Types” for more - # details on the meaning of this entry for each annotation type. - if contents is not None: - annot[Name("Contents")] = String(contents) + def append_annotation(self, annotation: Annotation): # (Optional except as noted below; PDF 1.3; not used in FDF files) An # indirect reference to the page object with which this annotation is @@ -317,1206 +220,22 @@ def _create_annotation( # This entry shall be present in screen annotations associated with # rendition actions (PDF 1.5; see 12.5.6.18, “Screen Annotations” and # 12.6.4.13, “Rendition Actions”). - annot[Name("P")] = self - - # (Optional; PDF 1.4) The annotation name, a text string uniquely - # identifying it among all the annotations on its page. - len_annots = len(self["Annots"]) if "Annots" in self else 0 - annot[Name("NM")] = String("annotation-{0:03d}".format(len_annots)) - - # (Optional; PDF 1.1) The date and time when the annotation was most - # recently modified. The format should be a date string as described in - # 7.9.4, “Dates,” but conforming readers shall accept and display a string - # in any format. - annot[Name("M")] = String(self._timestamp_to_str()) + annotation[Name("P")] = self - # (Optional; PDF 1.1) A set of flags specifying various characteristics of - # the annotation (see 12.5.3, “Annotation Flags”). Default value: 0. - annot[Name("F")] = bDecimal(4) - - # (Optional; PDF 1.2) An appearance dictionary specifying how the - # annotation shall be presented visually on the page (see 12.5.5, - # “Appearance Streams”). Individual annotation handlers may ignore this - # entry and provide their own appearances. - # annot[Name("AP")] = None - - # (Required if the appearance dictionary AP contains one or more - # subdictionaries; PDF 1.2) The annotation’s appearance state, which - # selects the applicable appearance stream from an appearance - # subdictionary (see Section 12.5.5, “Appearance Streams”). - # annot[Name("AS")] = None - - # Optional) An array specifying the characteristics of the annotation’s - # border, which shall be drawn as a rounded rectangle. - # (PDF 1.0) The array consists of three numbers defining the horizontal - # corner radius, vertical corner radius, and border width, all in default user - # space units. If the corner radii are 0, the border has square (not rounded) - # corners; if the border width is 0, no border is drawn. - # (PDF 1.1) The array may have a fourth element, an optional dash array - # defining a pattern of dashes and gaps that shall be used in drawing the - # border. The dash array shall be specified in the same format as in the - # line dash pattern parameter of the graphics state (see 8.4.3.6, “Line - # Dash Pattern”). - if ( - border_horizontal_corner_radius is not None - and border_vertical_corner_radius is not None - and border_width is not None - ): - annot[Name("Border")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["Border"].append(bDecimal(border_horizontal_corner_radius)) - annot["Border"].append(bDecimal(border_vertical_corner_radius)) - annot["Border"].append(bDecimal(border_width)) - - # (Optional; PDF 1.1) An array of numbers in the range 0.0 to 1.0, - # representing a colour used for the following purposes: - # The background of the annotation’s icon when closed - # The title bar of the annotation’s pop-up window - # The border of a link annotation - # The number of array elements determines the colour space in which the - # colour shall be defined - if color is not None: - annot[Name("C")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["C"].append(bDecimal(color.to_rgb().red)) - annot["C"].append(bDecimal(color.to_rgb().green)) - annot["C"].append(bDecimal(color.to_rgb().blue)) - - # (Required if the annotation is a structural content item; PDF 1.3) The - # integer key of the annotation’s entry in the structural parent tree (see - # 14.7.4.4, “Finding Structure Elements from Content Items”) - # annot[Name("StructParent")] = None - - # (Optional; PDF 1.5) An optional content group or optional content - # membership dictionary (see 8.11, “Optional Content”) specifying the - # optional content properties for the annotation. Before the annotation is - # drawn, its visibility shall be determined based on this entry as well as the - # annotation flags specified in the F entry (see 12.5.3, “Annotation Flags”). - # If it is determined to be invisible, the annotation shall be skipped, as if it - # were not in the document. - # annot[Name("OC")] = None - - # return - return annot - - @staticmethod - def _timestamp_to_str() -> str: - timestamp_str = "D:" - now = datetime.datetime.now() - for n in [now.year, now.month, now.day, now.hour, now.minute, now.second]: - timestamp_str += "{0:02}".format(n) - timestamp_str += "Z00" - return timestamp_str - - def _append_annotation(self, annotation: Dictionary) -> "Page": # append to /Annots if "Annots" not in self: self[Name("Annots")] = List() self["Annots"].set_parent(self) assert isinstance(self["Annots"], List) self["Annots"].append(annotation) - return self - - def append_text_annotation( - self, - rectangle: Rectangle, - contents: str, - text_annotation_icon: TextAnnotationIconType, - open: Optional[bool] = None, - color: Optional[Color] = None, - ) -> "Page": - """ - A text annotation represents a “sticky note” attached to a point in the PDF document. When closed, the - annotation shall appear as an icon; when open, it shall display a pop-up window containing the text of the note - in a font and size chosen by the conforming reader. Text annotations shall not scale and rotate with the page; - they shall behave as if the NoZoom and NoRotate annotation flags (see Table 165) were always set. Table 172 - shows the annotation dictionary entries specific to this type of annotation. - """ - # create generic annotation - annot = self._create_annotation( - rectangle=rectangle, contents=contents, color=color - ) - - # specific for text annotations - annot[Name("Subtype")] = Name("Text") - - # (Optional) A flag specifying whether the annotation shall initially be - # displayed open. Default value: false (closed). - if open is not None: - annot[Name("Open")] = Boolean(open) - # (Optional) The name of an icon that shall be used in displaying the - # annotation. Conforming readers shall provide predefined icon - # appearances for at least the following standard names: - # Comment, Key, Note, Help, NewParagraph, Paragraph, Insert - # Additional names may be supported as well. Default value: Note. - # The annotation dictionary’s AP entry, if present, shall take precedence - # over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.” - annot[Name("Name")] = text_annotation_icon.value + # FreeTextAnnotation needs to embed resources in the Page + if "Subtype" in annotation and annotation["Subtype"] == "FreeText": + annotation._embed_font_in_page(self) # return - return self._append_annotation(annot) - - def append_link_annotation( - self, - rectangle: Rectangle, - page: Decimal, - destination_type: DestinationType, - top: Optional[Decimal] = None, - right: Optional[Decimal] = None, - bottom: Optional[Decimal] = None, - left: Optional[Decimal] = None, - zoom: Optional[Decimal] = None, - highlighting_mode: Optional[str] = None, - color: Optional[Color] = None, - ) -> "Page": - """ - A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, - “Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary - entries specific to this type of annotation. - """ - - # create generic annotation - annot = self._create_annotation(rectangle=rectangle, color=color) - - # specific for text annotations - annot[Name("Subtype")] = Name("Link") - - # (Optional; PDF 1.1) An action that shall be performed when the link - # annotation is activated (see 12.6, “Actions”). - # annot[Name("A")] = None - - # (Optional; not permitted if an A entry is present) A destination that shall - # be displayed when the annotation is activated (see 12.3.2, - # “Destinations”). - destination = List().set_can_be_referenced(False) # type: ignore [attr-defined] - destination.append(bDecimal(page)) - destination.append(destination_type.value) - if destination_type == DestinationType.X_Y_Z: - assert ( - left is not None - and bottom is None - and right is None - and top is not None - and zoom is not None - ) - destination.append(bDecimal(left)) - destination.append(bDecimal(top)) - destination.append(bDecimal(zoom)) - if destination_type == DestinationType.FIT: - assert ( - left is None - and bottom is None - and right is None - and top is None - and zoom is None - ) - if destination_type == DestinationType.FIT_H: - assert ( - left is None - and bottom is None - and right is None - and top is not None - and zoom is None - ) - destination.append(bDecimal(top)) - if destination_type == DestinationType.FIT_V: - assert ( - left is not None - and bottom is None - and right is None - and top is None - and zoom is None - ) - destination.append(bDecimal(left)) - if destination_type == DestinationType.FIT_R: - assert ( - left is not None - and bottom is not None - and right is not None - and top is not None - and zoom is None - ) - destination.append(bDecimal(left)) - destination.append(bDecimal(bottom)) - destination.append(bDecimal(right)) - destination.append(bDecimal(top)) - if destination_type == DestinationType.FIT_B_H: - assert ( - left is None - and bottom is None - and right is None - and top is not None - and zoom is None - ) - destination.append(bDecimal(top)) - if destination_type == DestinationType.FIT_B_V: - assert ( - left is not None - and bottom is None - and right is None - and top is None - and zoom is None - ) - destination.append(bDecimal(left)) - annot[Name("Dest")] = destination - - # (Optional; PDF 1.2) The annotation’s highlighting mode, the visual effect - # that shall be used when the mouse button is pressed or held down - # inside its active area: - # N (None) No highlighting. - # I (Invert) Invert the contents of the annotation rectangle. - # O (Outline) Invert the annotation’s border. - # P (Push) Display the annotation as if it were being pushed below the surface of the page. - if highlighting_mode is not None: - assert highlighting_mode in ["N", "I", "O", "P"] - annot[Name("H")] = String(highlighting_mode) - - # return - return self._append_annotation(annot) - - def append_remote_go_to_annotation( - self, - rectangle: Rectangle, - uri: str, - border_horizontal_corner_radius: Decimal = Decimal(0), - border_vertical_corner_radius: Decimal = Decimal(0), - border_width: Decimal = Decimal(0), - ): - """ - A link annotation represents either a hypertext link to a destination elsewhere in the document (see 12.3.2, - “Destinations”) or an action to be performed (12.6, “Actions”). Table 173 shows the annotation dictionary - entries specific to this type of annotation. - This method adds a link annotation with an action that opens a remote URI. - """ - annot: Dictionary = self._create_annotation( - rectangle=rectangle, - border_horizontal_corner_radius=bDecimal(border_horizontal_corner_radius), - border_vertical_corner_radius=bDecimal(border_vertical_corner_radius), - border_width=bDecimal(border_width), - ) - - # (Required) The type of annotation that this dictionary describes; shall be - # Link for a link annotation. - annot[Name("Subtype")] = Name("Link") - - # (Optional; PDF 1.1) An action that shall be performed when the link - # annotation is activated (see 12.6, “Actions”). - annot[Name("A")] = Dictionary() - annot["A"][Name("Type")] = Name("Action") - annot["A"][Name("S")] = Name("URI") - annot["A"][Name("URI")] = String(uri) - - # return - return self._append_annotation(annot) - - def append_free_text_annotation( - self, - rectangle: Rectangle, - font: "Font", # type: ignore [name-defined] - font_size: Decimal, - font_color: "Color", # type: ignore [name-defined] - text: str, - background_color: "Color" = HexColor("ffffff"), - border_horizontal_corner_radius: Decimal = Decimal(0), - border_vertical_corner_radius: Decimal = Decimal(0), - border_width: Decimal = Decimal(0), - ) -> "Page": - """ - A free text annotation (PDF 1.3) displays text directly on the page. Unlike an ordinary text annotation (see - 12.5.6.4, “Text Annotations”), a free text annotation has no open or closed state; instead of being displayed in a - pop-up window, the text shall be always visible. Table 174 shows the annotation dictionary entries specific to - this type of annotation. 12.7.3.3, “Variable Text” describes the process of using these entries to generate the - appearance of the text in these annotations. - """ - # create generic annotation - annot = self._create_annotation( - rectangle=rectangle, - contents=text, - color=background_color, - border_horizontal_corner_radius=bDecimal(border_horizontal_corner_radius), - border_vertical_corner_radius=bDecimal(border_vertical_corner_radius), - border_width=bDecimal(border_width), - ) - - # specific for text annotations - annot[Name("Subtype")] = Name("FreeText") - - # (Optional; PDF 1.1) A set of flags specifying various characteristics of - # the annotation (see 12.5.3, “Annotation Flags”). Default value: 0. - annot[Name("F")] = bDecimal(20) - - # embed Font in /Page /Resources /Font - if "Resources" not in self: - self[Name("Resources")] = Dictionary() - if "Font" not in self["Resources"]: - self["Resources"][Name("Font")] = Dictionary() - font_number: int = len(self["Resources"]["Font"]) - font_name: str = "F%d" % font_number - while font_name in self["Resources"]["Font"]: - font_number += 1 - font_name = "F%d" % font_number - self["Resources"]["Font"][Name(font_name)] = font - - # (Required) The default appearance string that shall be used in formatting - # the text (see 12.7.3.3, “Variable Text”). - # The annotation dictionary’s AP entry, if present, shall take precedence - # over the DA entry; see Table 168 and 12.5.5, “Appearance Streams.” - font_color_rgb: "RGBColor" = font_color.to_rgb() # type: ignore [name-defined] - annot[Name("DA")] = String( - "/%s %f Tf %f %f %f rg" - % ( - font_name, - font_size, - font_color_rgb.red, - font_color_rgb.green, - font_color_rgb.blue, - ) - ) - - # (Optional; PDF 1.4) A code specifying the form of quadding (justification) - # that shall be used in displaying the annotation’s text: - # 0 Left-justified - # 1 Centered - # 2 Right-justified - # Default value: 0 (left-justified). - annot[Name("Q")] = bDecimal(0) - - # (Optional; PDF 1.6) A name describing the intent of the free text - # annotation (see also the IT entry in Table 170). The following values shall - # be valid: - # FreeText - # The annotation is intended to function as a plain - # free-text annotation. A plain free-text annotation - # is also known as a text box comment. - # FreeTextCallout - # The annotation is intended to function as a - # callout. The callout is associated with an area on - # the page through the callout line specified in CL. - # FreeTextTypeWriter - # The annotation is intended to function as a click- - # to-type or typewriter object and no callout line is - # drawn. - # Default value: FreeText - annot[Name("IT")] = Name("FreeTextTypeWriter") - - # return - return self._append_annotation(annot) - - def append_line_annotation( - self, - start_point: Tuple[Decimal, Decimal], - end_point: Tuple[Decimal, Decimal], - left_line_end_style: LineEndStyleType = LineEndStyleType.NONE, - right_line_end_style: LineEndStyleType = LineEndStyleType.NONE, - stroke_color: Color = HexColor("000000"), - ) -> "Page": - """ - The purpose of a line annotation (PDF 1.3) is to display a single straight line on the page. When opened, it shall - display a pop-up window containing the text of the associated note. Table 175 shows the annotation dictionary - entries specific to this type of annotation. - """ - - x = min([start_point[0], end_point[0]]) - y = min([start_point[1], end_point[1]]) - w = max([start_point[0], end_point[0]]) - x - h = max([start_point[1], end_point[1]]) - y - - # create generic annotation - annot = self._create_annotation( - rectangle=Rectangle(x, y, w, h), color=stroke_color - ) - - # (Required) The type of annotation that this dictionary describes; shall be - # Line for a line annotation. - annot[Name("Subtype")] = Name("Line") - - # (Required) An array of four numbers, [ x 1 y 1 x 2 y 2 ], specifying the - # starting and ending coordinates of the line in default user space. - # If the LL entry is present, this value shall represent the endpoints of the - # leader lines rather than the endpoints of the line itself; see Figure 60. - annot[Name("L")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["L"].append(start_point[0]) - annot["L"].append(start_point[1]) - annot["L"].append(end_point[0]) - annot["L"].append(end_point[1]) - - # (Optional; PDF 1.4) An array of two names specifying the line ending - # styles that shall be used in drawing the line. The first and second - # elements of the array shall specify the line ending styles for the endpoints - # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) - # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default - # value: [ /None /None ]. - annot[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["LE"].append(left_line_end_style.value) - annot["LE"].append(right_line_end_style) - - # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to - # 1.0 and shall specify the interior color with which to fill the annotation’s - # rectangle or ellipse. The number of array elements determines the colour - # space in which the colour shall be defined - if stroke_color is not None: - annot[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["IC"].append(bDecimal(stroke_color.to_rgb().red)) - annot["IC"].append(bDecimal(stroke_color.to_rgb().green)) - annot["IC"].append(bDecimal(stroke_color.to_rgb().blue)) - - # return - return self._append_annotation(annot) - - def append_square_annotation( - self, - rectangle: Rectangle, - stroke_color: Color, - fill_color: Optional[Color] = None, - rectangle_difference: Optional[ - Tuple[Decimal, Decimal, Decimal, Decimal] - ] = None, - ) -> "Page": - """ - Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When - opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse - shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see - Table 168). - """ - - # create generic annotation - annot = self._create_annotation(rectangle=rectangle, color=stroke_color) - - # (Required) The type of annotation that this dictionary describes; shall be - # Square or Circle for a square or circle annotation, respectively. - annot[Name("Subtype")] = Name("Square") - - # (Optional) A border style dictionary (see Table 166) specifying the line - # width and dash pattern that shall be used in drawing the rectangle or - # ellipse. - # The annotation dictionary’s AP entry, if present, shall take precedence - # over the Rect and BS entries; see Table 168 and 12.5.5, “Appearance - # Streams.” - # annot[Name("BS")] = None - - # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to - # 1.0 and shall specify the interior color with which to fill the annotation’s - # rectangle or ellipse. The number of array elements determines the colour - # space in which the colour shall be defined - if fill_color is not None: - annot[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["IC"].append(bDecimal(fill_color.to_rgb().red)) - annot["IC"].append(bDecimal(fill_color.to_rgb().green)) - annot["IC"].append(bDecimal(fill_color.to_rgb().blue)) - - # (Optional; PDF 1.5) A border effect dictionary describing an effect applied - # to the border described by the BS entry (see Table 167). - # annot[Name("BE")] = None - - # (Optional; PDF 1.5) A set of four numbers that shall describe the - # numerical differences between two rectangles: the Rect entry of the - # annotation and the actual boundaries of the underlying square or circle. - # Such a difference may occur in situations where a border effect - # (described by BE) causes the size of the Rect to increase beyond that of - # the square or circle. - # The four numbers shall correspond to the differences in default user - # space between the left, top, right, and bottom coordinates of Rect and - # those of the square or circle, respectively. Each value shall be greater - # than or equal to 0. The sum of the top and bottom differences shall be - # less than the height of Rect, and the sum of the left and right differences - # shall be less than the width of Rect. - if rectangle_difference is not None: - annot[Name("RD")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["RD"].append(bDecimal(rectangle_difference[0])) - annot["RD"].append(bDecimal(rectangle_difference[1])) - annot["RD"].append(bDecimal(rectangle_difference[2])) - annot["RD"].append(bDecimal(rectangle_difference[3])) - - # return - return self._append_annotation(annot) - - def append_circle_annotation( - self, - rectangle: Rectangle, - stroke_color: Color, - rectangle_difference: Optional[ - Tuple[Decimal, Decimal, Decimal, Decimal] - ] = None, - fill_color: Optional[Color] = None, - ) -> "Page": - """ - Square and circle annotations (PDF 1.3) shall display, respectively, a rectangle or an ellipse on the page. When - opened, they shall display a pop-up window containing the text of the associated note. The rectangle or ellipse - shall be inscribed within the annotation rectangle defined by the annotation dictionary’s Rect entry (see - Table 168). - """ - - # create generic annotation - annot = self._create_annotation(rectangle=rectangle, color=stroke_color) - - # (Required) The type of annotation that this dictionary describes; shall be - # Square or Circle for a square or circle annotation, respectively. - annot[Name("Subtype")] = Name("Circle") - - # (Optional) A border style dictionary (see Table 166) specifying the line - # width and dash pattern that shall be used in drawing the rectangle or - # ellipse. - # The annotation dictionary’s AP entry, if present, shall take precedence - # over the Rect and BS entries; see Table 168 and 12.5.5, “Appearance - # Streams.” - # annot[Name("BS")] = None - - # (Optional; PDF 1.4) An array of numbers that shall be in the range 0.0 to - # 1.0 and shall specify the interior color with which to fill the annotation’s - # rectangle or ellipse. The number of array elements determines the colour - # space in which the colour shall be defined - if fill_color is not None: - annot[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["IC"].append(bDecimal(fill_color.to_rgb().red)) - annot["IC"].append(bDecimal(fill_color.to_rgb().green)) - annot["IC"].append(bDecimal(fill_color.to_rgb().blue)) - - # (Optional; PDF 1.5) A border effect dictionary describing an effect applied - # to the border described by the BS entry (see Table 167). - # annot[Name("BE")] = None - - # (Optional; PDF 1.5) A set of four numbers that shall describe the - # numerical differences between two rectangles: the Rect entry of the - # annotation and the actual boundaries of the underlying square or circle. - # Such a difference may occur in situations where a border effect - # (described by BE) causes the size of the Rect to increase beyond that of - # the square or circle. - # The four numbers shall correspond to the differences in default user - # space between the left, top, right, and bottom coordinates of Rect and - # those of the square or circle, respectively. Each value shall be greater - # than or equal to 0. The sum of the top and bottom differences shall be - # less than the height of Rect, and the sum of the left and right differences - # shall be less than the width of Rect. - if rectangle_difference is not None: - annot[Name("RD")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["RD"].append(bDecimal(rectangle_difference[0])) - annot["RD"].append(bDecimal(rectangle_difference[1])) - annot["RD"].append(bDecimal(rectangle_difference[2])) - annot["RD"].append(bDecimal(rectangle_difference[3])) - - # return - return self._append_annotation(annot) - - def append_polygon_annotation( - self, - points: typing.List[Tuple[Decimal, Decimal]], - stroke_color: Color, - contents: Optional[str] = None, - ) -> "Page": - """ - Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of - vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first - and last vertex are not implicitly connected. - """ - - # must be at least 3 points - assert len(points) >= 3 - - # bounding box - min_x = points[0][0] - min_y = points[0][1] - max_x = min_x - max_y = min_y - for p in points: - min_x = min(min_x, p[0]) - min_y = min(min_y, p[1]) - max_x = max(max_x, p[0]) - max_y = max(max_y, p[1]) - - # create generic annotation - annot = self._create_annotation( - rectangle=Rectangle(min_x, min_y, max_x - min_x, max_y - min_y), - color=stroke_color, - contents=contents, - ) - - # (Required) The type of annotation that this dictionary describes; shall be - # Polygon or PolyLine for a polygon or polyline annotation, respectively. - annot[Name("Subtype")] = Name("Polygon") - - # (Required) An array of numbers (see Table 174) specifying the width and - # dash pattern that shall represent the alternating horizontal and vertical - # coordinates, respectively, of each vertex, in default user space. - annot[Name("Vertices")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - for p in points: - annot["Vertices"].append(bDecimal(p[0])) - annot["Vertices"].append(bDecimal(p[1])) - - # (Optional; PDF 1.4) An array of two names specifying the line ending - # styles that shall be used in drawing the line. The first and second - # elements of the array shall specify the line ending styles for the endpoints - # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) - # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default - # value: [ /None /None ]. - annot[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["LE"].append(Name("None")) - annot["LE"].append(Name("None")) - - # return - return self._append_annotation(annot) - - def append_polyline_annotation( - self, - points: typing.List[Tuple[Decimal, Decimal]], - stroke_color: Color, - left_line_end_style: LineEndStyleType = LineEndStyleType.NONE, - right_line_end_style: LineEndStyleType = LineEndStyleType.NONE, - fill_color: Optional[Color] = None, - contents: Optional[str] = None, - ) -> "Page": - """ - Polygon annotations (PDF 1.5) display closed polygons on the page. Such polygons may have any number of - vertices connected by straight lines. Polyline annotations (PDF 1.5) are similar to polygons, except that the first - and last vertex are not implicitly connected. - """ - - # must be at least 3 points - assert len(points) >= 3 - - # bounding box - min_x = points[0][0] - min_y = points[0][1] - max_x = min_x - max_y = min_y - for p in points: - min_x = min(min_x, p[0]) - min_y = min(min_y, p[1]) - max_x = max(max_x, p[0]) - max_y = max(max_y, p[1]) - - # create generic annotation - annot = self._create_annotation( - rectangle=Rectangle(min_x, min_y, max_x - min_x, max_y - min_y), - color=stroke_color, - contents=contents, - ) - - # (Required) The type of annotation that this dictionary describes; shall be - # Polygon or PolyLine for a polygon or polyline annotation, respectively. - annot[Name("Subtype")] = Name("PolyLine") - - # (Required) An array of numbers (see Table 174) specifying the width and - # dash pattern that shall represent the alternating horizontal and vertical - # coordinates, respectively, of each vertex, in default user space. - annot[Name("Vertices")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - for p in points: - annot["Vertices"].append(bDecimal(p[0])) - annot["Vertices"].append(bDecimal(p[1])) - - # (Optional; PDF 1.4) An array of two names specifying the line ending - # styles that shall be used in drawing the line. The first and second - # elements of the array shall specify the line ending styles for the endpoints - # defined, respectively, by the first and second pairs of coordinates, (x 1 , y 1 ) - # and (x 2 , y 2 ), in the L array. Table 176 shows the possible values. Default - # value: [ /None /None ]. - annot[Name("LE")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["LE"].append(left_line_end_style) - annot["LE"].append(right_line_end_style) - - if fill_color is not None: - annot[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["IC"].append(bDecimal(fill_color.to_rgb().red)) - annot["IC"].append(bDecimal(fill_color.to_rgb().green)) - annot["IC"].append(bDecimal(fill_color.to_rgb().blue)) - - # return - return self._append_annotation(annot) - - def append_highlight_annotation( - self, - rectangle: Rectangle, - color: Color = X11Color("Yellow"), - contents: Optional[str] = None, - ) -> "Page": - """ - Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) - underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing - the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of - annotations. - """ - # create generic annotation - annot = self._create_annotation( - rectangle=rectangle, color=color, contents=contents - ) - - # (Required) The type of annotation that this dictionary describes; shall - # be Highlight, Underline, Squiggly, or StrikeOut for a highlight, - # underline, squiggly-underline, or strikeout annotation, respectively. - annot[Name("Subtype")] = Name("Highlight") - - # (Required) An array of 8 × n numbers specifying the coordinates of n - # quadrilaterals in default user space. Each quadrilateral shall - # encompasses a word or group of contiguous words in the text - # underlying the annotation. The coordinates for each quadrilateral shall - # be given in the order - # x1 y1 x2 y2 x3 y3 x4 y4 - annot[Name("QuadPoints")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - # x1, y1 - annot["QuadPoints"].append(bDecimal(rectangle.get_x())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y())) - # x4, y4 - annot["QuadPoints"].append(bDecimal(rectangle.get_x())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y() + rectangle.get_height())) - # x2, y2 - annot["QuadPoints"].append(bDecimal(rectangle.get_x() + rectangle.get_width())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y())) - # x3, y3 - annot["QuadPoints"].append(bDecimal(rectangle.get_x() + rectangle.get_width())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y() + rectangle.get_height())) - - # border - annot[Name("Border")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["Border"].append(bDecimal(0)) - annot["Border"].append(bDecimal(0)) - annot["Border"].append(bDecimal(1)) - - # return - return self._append_annotation(annot) - - def append_underline_annotation( - self, - rectangle: Rectangle, - stroke_color: Color = X11Color("Yellow"), - contents: Optional[str] = None, - ) -> "Page": - """ - Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) - underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing - the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of - annotations. - """ - # create generic annotation - annot = self._create_annotation( - rectangle=rectangle, color=stroke_color, contents=contents - ) - - # (Required) The type of annotation that this dictionary describes; shall - # be Redact for a redaction annotation. - annot[Name("Subtype")] = Name("Underline") - - # (Required) An array of 8 × n numbers specifying the coordinates of n - # quadrilaterals in default user space. Each quadrilateral shall - # encompasses a word or group of contiguous words in the text - # underlying the annotation. The coordinates for each quadrilateral shall - # be given in the order - annot[Name("QuadPoints")] = List() - annot["QuadPoints"].append(bDecimal(rectangle.get_x())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y() + rectangle.get_height())) - annot["QuadPoints"].append(bDecimal(rectangle.get_x() + rectangle.get_width())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y() + rectangle.get_height())) - annot["QuadPoints"].append(bDecimal(rectangle.get_x())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y())) - annot["QuadPoints"].append(bDecimal(rectangle.get_x() + rectangle.get_width())) - annot["QuadPoints"].append(bDecimal(rectangle.get_y())) - - # (PDF 1.0) The array consists of three numbers defining the horizontal - # corner radius, vertical corner radius, and border width, all in default user - # space units. If the corner radii are 0, the border has square (not rounded) - # corners; if the border width is 0, no border is drawn. - annot[Name("Border")] = List() - annot["Border"].append(bDecimal(0)) - annot["Border"].append(bDecimal(0)) - annot["Border"].append(bDecimal(1)) - - # return - return self._append_annotation(annot) - - def append_squiggly_annotation( - self, - rectangle: Rectangle, - stroke_color: Color = X11Color("Red"), - line_width: Decimal = Decimal(1), - ) -> "Page": - """ - Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) - underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing - the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of - annotations. - """ - - # create generic annotation - annot = self._create_annotation(rectangle=rectangle) - - # (Required) The type of annotation that this dictionary describes; shall - # be Redact for a redaction annotation. - annot[Name("Subtype")] = Name("Squiggly") - - # (Optional; PDF 1.2) An appearance dictionary specifying how the - # annotation shall be presented visually on the page (see 12.5.5, - # “Appearance Streams”). Individual annotation handlers may ignore this - # entry and provide their own appearances. - annot[Name("AP")] = Dictionary() - annot["AP"][Name("N")] = Stream() - annot["AP"]["N"][Name("Type")] = Name("XObject") - annot["AP"]["N"][Name("Subtype")] = Name("Form") - - appearance_stream_content = "q %f %f %f RG %f w 0 0 m " % ( - stroke_color.to_rgb().red, - stroke_color.to_rgb().green, - stroke_color.to_rgb().blue, - line_width, - ) - for x in range(0, int(rectangle.width), 5): - appearance_stream_content += "%f %f l %f %f l " % (x, 0, x + 2.5, 7) - appearance_stream_content += "%f %f l " % ( - rectangle.width - rectangle.width % 5 + 5, - 0, - ) - appearance_stream_content += "S Q" - annot["AP"]["N"][Name("DecodedBytes")] = bytes( - appearance_stream_content, "latin1" - ) - annot["AP"]["N"][Name("Bytes")] = zlib.compress( - annot["AP"]["N"][Name("DecodedBytes")] - ) - annot["AP"]["N"][Name("Length")] = bDecimal( - len(annot["AP"]["N"][Name("Bytes")]) - ) - annot["AP"]["N"][Name("Filter")] = Name("FlateDecode") - - # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. - # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect - # entry in the widget annotation dictionary). - annot["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(rectangle.width)) - annot["AP"]["N"]["BBox"].append(bDecimal(100)) - - # return - return self._append_annotation(annot) - - def append_strike_out_annotation( - self, - rectangle: Rectangle, - stroke_color: Color = X11Color("Red"), - line_width: Decimal = Decimal(1), - ) -> "Page": - """ - Text markup annotations shall appear as highlights, underlines, strikeouts (all PDF 1.3), or jagged (“squiggly”) - underlines (PDF 1.4) in the text of a document. When opened, they shall display a pop-up window containing - the text of the associated note. Table 179 shows the annotation dictionary entries specific to these types of - annotations. - """ - # create generic annotation - annot = self._create_annotation(rectangle=rectangle) - - # (Required) The type of annotation that this dictionary describes; shall - # be Redact for a redaction annotation. - annot[Name("Subtype")] = Name("StrikeOut") - - # (Optional; PDF 1.2) An appearance dictionary specifying how the - # annotation shall be presented visually on the page (see 12.5.5, - # “Appearance Streams”). Individual annotation handlers may ignore this - # entry and provide their own appearances. - annot[Name("AP")] = Dictionary() - annot["AP"][Name("N")] = Stream() - annot["AP"]["N"][Name("Type")] = Name("XObject") - annot["AP"]["N"][Name("Subtype")] = Name("Form") - - appearance_stream_content = "q %f %f %f RG %f w 0 40 m %f 40 l S Q" % ( - stroke_color.to_rgb().red, - stroke_color.to_rgb().green, - stroke_color.to_rgb().blue, - line_width, - rectangle.width, - ) - annot["AP"]["N"][Name("DecodedBytes")] = bytes( - appearance_stream_content, "latin1" - ) - annot["AP"]["N"][Name("Bytes")] = zlib.compress( - annot["AP"]["N"][Name("DecodedBytes")] - ) - annot["AP"]["N"][Name("Length")] = bDecimal( - len(annot["AP"]["N"][Name("Bytes")]) - ) - annot["AP"]["N"][Name("Filter")] = Name("FlateDecode") - - # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. - # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect - # entry in the widget annotation dictionary). - annot["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(rectangle.width)) - annot["AP"]["N"]["BBox"].append(bDecimal(100)) - - # return - return self._append_annotation(annot) - - def append_stamp_annotation( - self, - rectangle: Rectangle, - name: RubberStampAnnotationIconType = RubberStampAnnotationIconType.DRAFT, - contents: Optional[str] = None, - color: Optional[Color] = None, - ) -> "Page": - """ - A rubber stamp annotation (PDF 1.3) displays text or graphics intended to look as if they were stamped on the - page with a rubber stamp. When opened, it shall display a pop-up window containing the text of the associated - note. Table 181 shows the annotation dictionary entries specific to this type of annotation. - """ - # create generic annotation - annot = self._create_annotation( - rectangle=rectangle, contents=contents, color=color - ) - - # (Required) The type of annotation that this dictionary describes; shall be - # Stamp for a rubber stamp annotation. - annot[Name("Subtype")] = Name("Stamp") - - # (Optional) The name of an icon that shall be used in displaying the annotation. Conforming readers shall provide predefined icon - # appearances for at least the following standard names: - # Approved, Experimental, NotApproved, AsIs, - # Expired, NotForPublicRelease, Confidential, Final, Sold, - # Departmental, ForComment, TopSecret, Draft, ForPublicRelease - # Additional names may be supported as well. Default value: Draft. - # The annotation dictionary’s AP entry, if present, shall take precedence - # over the Name entry; see Table 168 and 12.5.5, “Appearance Streams.” - annot[Name("Name")] = name.value - - # (Optional; PDF 1.4) The constant opacity value that shall be used in - # painting the annotation (see Sections 11.2, “Overview of Transparency,” - # and 11.3.7, “Shape and Opacity Computations”). This value shall apply to - # all visible elements of the annotation in its closed state (including its - # background and border) but not to the pop-up window that appears when - # the annotation is opened. - annot[Name("CA")] = bDecimal(1) - - # return - return self._append_annotation(annot) - - def append_caret_annotation(self) -> "Page": - """ - A caret annotation (PDF 1.5) is a visual symbol that indicates the presence of text edits. Table 180 lists the - entries specific to caret annotations. - """ - # TODO - return self - - def append_ink_annotation(self) -> "Page": - """ - An ink annotation (PDF 1.3) represents a freehand “scribble” composed of one or more disjoint paths. When - opened, it shall display a pop-up window containing the text of the associated note. Table 182 shows the - annotation dictionary entries specific to this type of annotation. - """ - # TODO - return self - - def append_popup_annotation(self) -> "Page": - """ - A pop-up annotation (PDF 1.3) displays text in a pop-up window for entry and editing. It shall not appear alone - but is associated with a markup annotation, its parent annotation, and shall be used for editing the parent’s text. - It shall have no appearance stream or associated actions of its own and shall be identified by the Popup entry - in the parent’s annotation dictionary (see Table 174). Table 183 shows the annotation dictionary entries specific - to this type of annotation. - """ - # TODO - return self - - def append_file_attachment_annotation(self) -> "Page": - """ - A file attachment annotation (PDF 1.3) contains a reference to a file, which typically shall be embedded in the - PDF file (see 7.11.4, “Embedded File Streams”). - """ - # TODO - return self - - def append_sound_annotation(self) -> "Page": - """ - A sound annotation (PDF 1.2) shall analogous to a text annotation except that instead of a text note, it contains - sound recorded from the computer’s microphone or imported from a file. When the annotation is activated, the - sound shall be played. The annotation shall behave like a text annotation in most ways, with a different icon (by - default, a speaker) to indicate that it represents a sound. Table 185 shows the annotation dictionary entries - specific to this type of annotation. Sound objects are discussed in 13.3, “Sounds.” - """ - # TODO - return self - - def append_movie_annotation(self) -> "Page": - """ - A movie annotation (PDF 1.2) contains animated graphics and sound to be presented on the computer screen - and through the speakers. When the annotation is activated, the movie shall be played. Table 186 shows the - annotation dictionary entries specific to this type of annotation. Movies are discussed in 13.4, “Movies.” - """ - # TODO - return self - - def append_widget_annotation(self) -> "Page": - """ - Interactive forms (see 12.7, “Interactive Forms”) use widget annotations (PDF 1.2) to represent the appearance - of fields and to manage user interactions. As a convenience, when a field has only a single associated widget - annotation, the contents of the field dictionary (12.7.3, “Field Dictionaries”) and the annotation dictionary may - be merged into a single dictionary containing entries that pertain to both a field and an annotation. - """ - # TODO - return self - - def append_screen_annotation(self) -> "Page": - """ - A screen annotation (PDF 1.5) specifies a region of a page upon which media clips may be played. It also - serves as an object from which actions can be triggered. 12.6.4.13, “Rendition Actions” discusses the - relationship between screen annotations and rendition actions. Table 187 shows the annotation dictionary - entries specific to this type of annotation. - """ - # TODO - return self - - def append_printer_mark_annotation(self) -> "Page": - """ - A printer’s mark annotation (PDF 1.4) represents a graphic symbol, such as a registration target, colour bar, or - cut mark, that may be added to a page to assist production personnel in identifying components of a multiple- - plate job and maintaining consistent output during production. See 14.11.3, “Printer’s Marks,” for further - discussion. - """ - # TODO return self - def append_trap_net_annotation(self) -> "Page": - """ - A trap network annotation (PDF 1.3) may be used to define the trapping characteristics for a page of a PDF - document. - """ - # TODO - return self - - def append_watermark_annotation( - self, - rectangle: Rectangle, - contents: str, - ) -> "Page": - """ - A watermark annotation (PDF 1.6) shall be used to represent graphics that shall be printed at a fixed size and - position on a page, regardless of the dimensions of the printed page. The FixedPrint entry of a watermark - annotation dictionary (see Table 190) shall be a dictionary that contains values for specifying the size and - position of the annotation (see Table 191). - """ - # TODO - return self - - def append_3d_annotation(self) -> "Page": - """ - 3D annotations (PDF 1.6) are the means by which 3D artwork shall be represented in a PDF document. - Table 298 shows the entries specific to a 3D annotation dictionary. Table 164 describes the entries common to - all annotation dictionaries. - - In addition to these entries, a 3D annotation shall provide an appearance stream in its AP entry (see Table 164) - that has a normal appearance (the N entry in Table 168). This appearance may be used by applications that do - not support 3D annotations and by all applications for the initial display of the annotation. - """ - # TODO - return self - - def append_redact_annotation( - self, - rectangle: Rectangle, - overlay_text: Optional[str] = None, - repeat_overlay_text: Optional[bool] = None, - line_width: Decimal = Decimal(1), - stroke_color: Optional[Color] = HexColor("ff0000"), - fill_color: Optional[Color] = None, - ) -> "Page": - """ - A redaction annotation (PDF 1.7) identifies content that is intended to be removed from the document. The - intent of redaction annotations is to enable the following process: - - a) Content identification. A user applies redact annotations that specify the pieces or regions of content that - should be removed. Up until the next step is performed, the user can see, move and redefine these - annotations. - - b) Content removal. The user instructs the viewer application to apply the redact annotations, after which the - content in the area specified by the redact annotations is removed. In the removed content’s place, some - marking appears to indicate the area has been redacted. Also, the redact annotations are removed from - the PDF document. - - Redaction annotations provide a mechanism for the first step in the redaction process (content identification). - This allows content to be marked for redaction in a non-destructive way, thus enabling a review process for - evaluating potential redactions prior to removing the specified content. - """ - - # create generic annotation - annot = self._create_annotation(rectangle=rectangle) - - # (Required) The type of annotation that this dictionary describes; shall - # be Redact for a redaction annotation. - annot[Name("Subtype")] = Name("Redact") - - # (Optional) An array of three numbers in the range 0.0 to 1.0 - # specifying the components, in the DeviceRGB colour space, of the - # interior colour with which to fill the redacted region after the affected - # content has been removed. If this entry is absent, the interior of the - # redaction region is left transparent. This entry is ignored if the RO - # entry is present. - if fill_color is not None: - annot[Name("IC")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["IC"].append(bDecimal(fill_color.to_rgb().red)) - annot["IC"].append(bDecimal(fill_color.to_rgb().green)) - annot["IC"].append(bDecimal(fill_color.to_rgb().blue)) - - # (Optional) A text string specifying the overlay text that should be - # drawn over the redacted region after the affected content has been - # removed. This entry is ignored if the RO entry is present. - if overlay_text is not None: - annot[Name("OverlayText")] = String(overlay_text) - - # (Optional) If true, then the text specified by OverlayText should be - # repeated to fill the redacted region after the affected content has been - # removed. This entry is ignored if the RO entry is present. Default - # value: false. - if repeat_overlay_text is not None: - assert overlay_text is not None - annot[Name("Repeat")] = Boolean(repeat_overlay_text) - - # (Optional; PDF 1.2) An appearance dictionary specifying how the - # annotation shall be presented visually on the page (see 12.5.5, - # “Appearance Streams”). Individual annotation handlers may ignore this - # entry and provide their own appearances. - annot[Name("AP")] = Dictionary() - annot["AP"][Name("N")] = Stream() - annot["AP"]["N"][Name("Type")] = Name("XObject") - annot["AP"]["N"][Name("Subtype")] = Name("Form") - appearance_stream_content = "q" - if stroke_color is not None: - appearance_stream_content += " %f %f %f RG" % ( - stroke_color.to_rgb().red, - stroke_color.to_rgb().green, - stroke_color.to_rgb().blue, - ) - if fill_color is not None: - appearance_stream_content += " %f %f %f rg" % ( - fill_color.to_rgb().red, - fill_color.to_rgb().green, - fill_color.to_rgb().blue, - ) - if stroke_color is not None and fill_color is not None: - appearance_stream_content += " %f w 0 0 100 100 re b" % line_width - elif stroke_color is not None: - appearance_stream_content += " %f w 0 0 100 100 re s" % line_width - elif fill_color is not None: - appearance_stream_content += " %f w 0 0 100 100 re f" % line_width - appearance_stream_content += " Q" - annot["AP"]["N"][Name("DecodedBytes")] = bytes( - appearance_stream_content, "latin1" - ) - annot["AP"]["N"][Name("Bytes")] = zlib.compress( - annot["AP"]["N"][Name("DecodedBytes")] - ) - annot["AP"]["N"][Name("Length")] = bDecimal( - len(annot["AP"]["N"][Name("Bytes")]) - ) - annot["AP"]["N"][Name("Filter")] = Name("FlateDecode") - - # The lower-left corner of the bounding box (BBox) is set to coordinates (0, 0) in the form coordinate system. - # The box’s top and right coordinates are taken from the dimensions of the annotation rectangle (the Rect - # entry in the widget annotation dictionary). - annot["AP"]["N"][Name("BBox")] = List().set_can_be_referenced(False) # type: ignore [attr-defined] - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(0)) - annot["AP"]["N"]["BBox"].append(bDecimal(100)) - annot["AP"]["N"]["BBox"].append(bDecimal(100)) - - # return - return self._append_annotation(annot) - def apply_redact_annotations( self, rectangles_to_redact: typing.List[Rectangle] = [] ): diff --git a/borb/pdf/pdf.py b/borb/pdf/pdf.py index b5cddfd5a..c30213b18 100644 --- a/borb/pdf/pdf.py +++ b/borb/pdf/pdf.py @@ -22,7 +22,7 @@ from borb.io.write.conformance_level import ConformanceLevel from borb.io.write.transformer import WriteTransformerState from borb.pdf.canvas.event.event_listener import EventListener -from borb.pdf.document import Document +from borb.pdf.document.document import Document class PDF: diff --git a/borb/toolkit/diff/pdf_diff.py b/borb/toolkit/diff/pdf_diff.py index 861170690..6b39a9eb7 100644 --- a/borb/toolkit/diff/pdf_diff.py +++ b/borb/toolkit/diff/pdf_diff.py @@ -9,7 +9,7 @@ from borb.io.filter.stream_decode_util import decode_stream from borb.io.read.types import Decimal, Dictionary, List, Name, Stream -from borb.pdf.document import Document +from borb.pdf.document.document import Document class PDFDiff: diff --git a/borb/toolkit/export/html_to_pdf/html_to_pdf.py b/borb/toolkit/export/html_to_pdf/html_to_pdf.py index 9ed1aa34e..09ad031a2 100644 --- a/borb/toolkit/export/html_to_pdf/html_to_pdf.py +++ b/borb/toolkit/export/html_to_pdf/html_to_pdf.py @@ -11,7 +11,7 @@ from borb.pdf.canvas.layout.page_layout.browser_layout import BrowserLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.page.page_size import PageSize from borb.toolkit.export.html_to_pdf.tag_transformer.any_tag_transformer import ( diff --git a/borb/toolkit/export/html_to_pdf/read/head/meta_tag_transformer.py b/borb/toolkit/export/html_to_pdf/read/head/meta_tag_transformer.py index 68ee55926..dc813f1c9 100644 --- a/borb/toolkit/export/html_to_pdf/read/head/meta_tag_transformer.py +++ b/borb/toolkit/export/html_to_pdf/read/head/meta_tag_transformer.py @@ -10,7 +10,7 @@ from borb.io.read.types import Dictionary, Name, String from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.xref.plaintext_xref import PlainTextXREF from borb.toolkit.export.html_to_pdf.read.transformer import Transformer diff --git a/borb/toolkit/export/html_to_pdf/read/head/title_tag_transformer.py b/borb/toolkit/export/html_to_pdf/read/head/title_tag_transformer.py index 793392041..d67c721f9 100644 --- a/borb/toolkit/export/html_to_pdf/read/head/title_tag_transformer.py +++ b/borb/toolkit/export/html_to_pdf/read/head/title_tag_transformer.py @@ -10,7 +10,7 @@ from borb.io.read.types import Dictionary, Name, String from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.xref.plaintext_xref import PlainTextXREF from borb.toolkit.export.html_to_pdf.read.transformer import Transformer diff --git a/borb/toolkit/export/html_to_pdf/tag_transformer/head/meta_tag_transformer.py b/borb/toolkit/export/html_to_pdf/tag_transformer/head/meta_tag_transformer.py index 2954c8be0..d74d2628d 100644 --- a/borb/toolkit/export/html_to_pdf/tag_transformer/head/meta_tag_transformer.py +++ b/borb/toolkit/export/html_to_pdf/tag_transformer/head/meta_tag_transformer.py @@ -10,7 +10,7 @@ from borb.io.read.types import Dictionary, Name, String from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.xref.plaintext_xref import PlainTextXREF from borb.toolkit.export.html_to_pdf.tag_transformer.base_tag_transformer import ( BaseTagTransformer, diff --git a/borb/toolkit/export/html_to_pdf/tag_transformer/head/title_tag_transformer.py b/borb/toolkit/export/html_to_pdf/tag_transformer/head/title_tag_transformer.py index 4bcd8ec3d..0e0bbeb02 100644 --- a/borb/toolkit/export/html_to_pdf/tag_transformer/head/title_tag_transformer.py +++ b/borb/toolkit/export/html_to_pdf/tag_transformer/head/title_tag_transformer.py @@ -10,7 +10,7 @@ from borb.io.read.types import Dictionary, Name, String from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.xref.plaintext_xref import PlainTextXREF from borb.toolkit.export.html_to_pdf.tag_transformer.base_tag_transformer import ( BaseTagTransformer, diff --git a/borb/toolkit/export/markdown_to_pdf/markdown_to_pdf.py b/borb/toolkit/export/markdown_to_pdf/markdown_to_pdf.py index e9763f98d..b34c8c68f 100644 --- a/borb/toolkit/export/markdown_to_pdf/markdown_to_pdf.py +++ b/borb/toolkit/export/markdown_to_pdf/markdown_to_pdf.py @@ -4,7 +4,7 @@ """ This class converts Markdown to PDF """ -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.toolkit.export.markdown_to_pdf.read.any_markdown_transformer import ( AnyMarkdownTransformer, ) diff --git a/borb/toolkit/export/markdown_to_pdf/read/heading/alternate_syntax_heading_transformer.py b/borb/toolkit/export/markdown_to_pdf/read/heading/alternate_syntax_heading_transformer.py index f91fc6422..5e10fa07c 100644 --- a/borb/toolkit/export/markdown_to_pdf/read/heading/alternate_syntax_heading_transformer.py +++ b/borb/toolkit/export/markdown_to_pdf/read/heading/alternate_syntax_heading_transformer.py @@ -10,7 +10,7 @@ from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.heading import Heading -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.toolkit.export.markdown_to_pdf.read.transformer import ( Transformer, diff --git a/borb/toolkit/export/markdown_to_pdf/read/heading/heading_transformer.py b/borb/toolkit/export/markdown_to_pdf/read/heading/heading_transformer.py index 6703b0852..8d3a4444b 100644 --- a/borb/toolkit/export/markdown_to_pdf/read/heading/heading_transformer.py +++ b/borb/toolkit/export/markdown_to_pdf/read/heading/heading_transformer.py @@ -10,7 +10,7 @@ from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.heading import Heading -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.toolkit.export.markdown_to_pdf.read.transformer import ( Transformer, diff --git a/borb/toolkit/export/markdown_to_pdf/read/heading/horizontal_rule_transformer.py b/borb/toolkit/export/markdown_to_pdf/read/heading/horizontal_rule_transformer.py index c30f11e11..da219f102 100644 --- a/borb/toolkit/export/markdown_to_pdf/read/heading/horizontal_rule_transformer.py +++ b/borb/toolkit/export/markdown_to_pdf/read/heading/horizontal_rule_transformer.py @@ -9,7 +9,7 @@ from borb.pdf.canvas.layout.horizontal_rule import HorizontalRule from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.toolkit.export.markdown_to_pdf.read.transformer import ( Transformer, diff --git a/borb/toolkit/export/markdown_to_pdf/read/transformer.py b/borb/toolkit/export/markdown_to_pdf/read/transformer.py index 00a47dca5..68e8cbd20 100644 --- a/borb/toolkit/export/markdown_to_pdf/read/transformer.py +++ b/borb/toolkit/export/markdown_to_pdf/read/transformer.py @@ -11,7 +11,7 @@ from borb.pdf.canvas.layout.layout_element import LayoutElement from borb.pdf.canvas.layout.page_layout.browser_layout import BrowserLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page diff --git a/borb/toolkit/ocr/ocr_as_optional_content_group.py b/borb/toolkit/ocr/ocr_as_optional_content_group.py index 75be0459e..d525e4813 100644 --- a/borb/toolkit/ocr/ocr_as_optional_content_group.py +++ b/borb/toolkit/ocr/ocr_as_optional_content_group.py @@ -18,7 +18,7 @@ from borb.pdf.canvas.event.event_listener import Event from borb.pdf.canvas.geometry.rectangle import Rectangle from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.toolkit.ocr.ocr_image_render_event_listener import ( OCREvent, diff --git a/borb/toolkit/ocr/ocr_image_render_event_listener.py b/borb/toolkit/ocr/ocr_image_render_event_listener.py index de25fae53..314be5f33 100644 --- a/borb/toolkit/ocr/ocr_image_render_event_listener.py +++ b/borb/toolkit/ocr/ocr_image_render_event_listener.py @@ -248,8 +248,14 @@ def _get_font_color( ) # write text - text_image_draw = ImageDraw.Draw(text_image) - text_image_draw.text((0, 0), text, fill=(0, 0, 0)) + # this can go wrong if the default font for drawing text + # does not support one or more of the characters being drawn + # in which case this code returns black + try: + text_image_draw = ImageDraw.Draw(text_image) + text_image_draw.text((0, 0), text, fill=(0, 0, 0)) + except: + return HexColor("000000") # count number of text pixels percentage_of_text_pixels: Decimal = Decimal(0) @@ -273,12 +279,12 @@ def _get_font_color( ) ) - # count colors in cropped image - surface: Decimal = ( - cropped_image.width - * (image_bounding_box.height / image_bounding_box.width) - * cropped_image.height + # count number of pixels in cropped image + number_of_pixels_in_cropped_image: Decimal = ( + cropped_image.width * cropped_image.height ) + + # build color histogram color_histogram: typing.Dict[str, Decimal] = {} for i in range(0, cropped_image.width): for j in range(0, cropped_image.height): @@ -299,7 +305,11 @@ def _get_font_color( hex_color, Decimal(0) ) + Decimal(1) - color_histogram = {k: (v / surface) for k, v in color_histogram.items()} + # normalize + color_histogram = { + k: (v / number_of_pixels_in_cropped_image) + for k, v in color_histogram.items() + } # trim color_histogram = {k: v for k, v in color_histogram.items() if v > 0.05} diff --git a/release_notes.md b/release_notes.md index eb0a5c124..9a6c46c83 100644 --- a/release_notes.md +++ b/release_notes.md @@ -1,7 +1,22 @@ -# :mega: borb release 2.0.18 +# :mega: borb release 2.0.19 -This release is a cleanup release. +This release is a small feature release. -- The library (previously called `ptext`) still had some imports being renamed as `pDecimal` or `pString` or `pList`. - These occurences have been completely removed from the code. -- `borb` can now create PDF documents that are almost PDF/A-1b valid. Some effort for fonts remains. \ No newline at end of file +- Forms have been extended with `PushButton`, which enables you to place a `PushButton` in a PDF and tie an action to it. + +- Tests for `PushButton` have been added to the repository. + +- Examples for `PushButton` have been added to the examples repository. + +- A test was added for issue #69 on GitHub, which deals with adding 500 `Heading` objects to a PDF. +Turns out recursive parsing has its limits :face_with_spiral_eyes: + +- A small fix was introduced for issue #71 on GitHub + +- `Annotation` now is its own proper class, each seperate `Annotation` has its own subclass. This makes the `Page` class a lot lighter (where the code previously resided). + +- `Document` level JavaScript is now supported, examples and tests have been added to the corresponding repositories. + +- Both embedded files and JavaScript use the concept of a `NameTree` which is now its own separate class. + +In order to make sure your code runs smoothly, check your imports when upgrading to the latest version. \ No newline at end of file diff --git a/setup.py b/setup.py index 44473ccf6..678f1aa36 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setuptools.setup( name="borb", - version="2.0.18", + version="2.0.19", author="Joris Schellekens", author_email="joris.schellekens.1989@gmail.com", description="borb is a library for reading, creating and manipulating PDF files in python.", diff --git a/tests/corpus/test_copy_document_compare_size.py b/tests/corpus/test_copy_document_compare_size.py index 4fe5981ba..3e5903ece 100644 --- a/tests/corpus/test_copy_document_compare_size.py +++ b/tests/corpus/test_copy_document_compare_size.py @@ -16,7 +16,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/corpus/test_copy_document_resize_images_compare_size.py b/tests/corpus/test_copy_document_resize_images_compare_size.py index 2169acd51..728fd8a21 100644 --- a/tests/corpus/test_copy_document_resize_images_compare_size.py +++ b/tests/corpus/test_copy_document_resize_images_compare_size.py @@ -16,7 +16,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.image.image_format_optimization import ImageFormatOptimization diff --git a/tests/corpus/test_extract_text_expect_ground_truth.py b/tests/corpus/test_extract_text_expect_ground_truth.py index bf10848bb..4cbcfadb9 100644 --- a/tests/corpus/test_extract_text_expect_ground_truth.py +++ b/tests/corpus/test_extract_text_expect_ground_truth.py @@ -1,6 +1,5 @@ import os import time -import traceback import typing import unittest from datetime import datetime @@ -19,7 +18,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.simple_text_extraction import SimpleTextExtraction diff --git a/tests/corpus/test_open_document.py b/tests/corpus/test_open_document.py index dbf05e077..58eaadbd6 100644 --- a/tests/corpus/test_open_document.py +++ b/tests/corpus/test_open_document.py @@ -18,7 +18,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/corpus/test_open_encrypted_document.py b/tests/corpus/test_open_encrypted_document.py index 73a8fe1fc..1918290ac 100644 --- a/tests/corpus/test_open_encrypted_document.py +++ b/tests/corpus/test_open_encrypted_document.py @@ -16,7 +16,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/misc/types/test_type_methods.py b/tests/misc/types/test_type_methods.py index 921a233fc..485c9cb7a 100644 --- a/tests/misc/types/test_type_methods.py +++ b/tests/misc/types/test_type_methods.py @@ -1,6 +1,6 @@ import unittest -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page diff --git a/tests/output/test_add_all_rubber_stamp_annotations/output.pdf b/tests/output/test_add_all_rubber_stamp_annotations/output.pdf index fb266f7d9..8288195ba 100644 Binary files a/tests/output/test_add_all_rubber_stamp_annotations/output.pdf and b/tests/output/test_add_all_rubber_stamp_annotations/output.pdf differ diff --git a/tests/output/test_add_circle_annotation/output.pdf b/tests/output/test_add_circle_annotation/output.pdf index c0e98782f..535ecb542 100644 Binary files a/tests/output/test_add_circle_annotation/output.pdf and b/tests/output/test_add_circle_annotation/output.pdf differ diff --git a/tests/output/test_add_free_text_annotation/output_001.pdf b/tests/output/test_add_free_text_annotation/output_001.pdf index 08ded72d5..340e71022 100644 Binary files a/tests/output/test_add_free_text_annotation/output_001.pdf and b/tests/output/test_add_free_text_annotation/output_001.pdf differ diff --git a/tests/output/test_add_free_text_annotation/output_002.pdf b/tests/output/test_add_free_text_annotation/output_002.pdf index b85dd85a3..eb39d6a1b 100644 Binary files a/tests/output/test_add_free_text_annotation/output_002.pdf and b/tests/output/test_add_free_text_annotation/output_002.pdf differ diff --git a/tests/output/test_add_highlight_annotation/output_001.pdf b/tests/output/test_add_highlight_annotation/output_001.pdf index 66b1f4d2a..679530ab2 100644 Binary files a/tests/output/test_add_highlight_annotation/output_001.pdf and b/tests/output/test_add_highlight_annotation/output_001.pdf differ diff --git a/tests/output/test_add_highlight_annotation/output_002.pdf b/tests/output/test_add_highlight_annotation/output_002.pdf index 24760a515..a9fa4d4eb 100644 Binary files a/tests/output/test_add_highlight_annotation/output_002.pdf and b/tests/output/test_add_highlight_annotation/output_002.pdf differ diff --git a/tests/output/test_add_large_amount_of_headings/output_001.pdf b/tests/output/test_add_large_amount_of_headings/output_001.pdf new file mode 100644 index 000000000..883f401b4 Binary files /dev/null and b/tests/output/test_add_large_amount_of_headings/output_001.pdf differ diff --git a/tests/output/test_add_large_amount_of_headings/output_002.pdf b/tests/output/test_add_large_amount_of_headings/output_002.pdf new file mode 100644 index 000000000..763f1d29a Binary files /dev/null and b/tests/output/test_add_large_amount_of_headings/output_002.pdf differ diff --git a/tests/output/test_add_line_annotation/output_001.pdf b/tests/output/test_add_line_annotation/output_001.pdf index c7299c689..89264d203 100644 Binary files a/tests/output/test_add_line_annotation/output_001.pdf and b/tests/output/test_add_line_annotation/output_001.pdf differ diff --git a/tests/output/test_add_line_annotation/output_002.pdf b/tests/output/test_add_line_annotation/output_002.pdf index 5dc82c6c8..8b50198d7 100644 Binary files a/tests/output/test_add_line_annotation/output_002.pdf and b/tests/output/test_add_line_annotation/output_002.pdf differ diff --git a/tests/output/test_add_outline/output_001.pdf b/tests/output/test_add_outline/output_001.pdf index e8e5cd657..162a76142 100644 Binary files a/tests/output/test_add_outline/output_001.pdf and b/tests/output/test_add_outline/output_001.pdf differ diff --git a/tests/output/test_add_outline/output_002.pdf b/tests/output/test_add_outline/output_002.pdf index 4737a83c9..98412a1de 100644 Binary files a/tests/output/test_add_outline/output_002.pdf and b/tests/output/test_add_outline/output_002.pdf differ diff --git a/tests/output/test_add_polygon_annotation_using_line_art_factory/output.pdf b/tests/output/test_add_polygon_annotation_using_line_art_factory/output.pdf index e5075f6dd..ed176734c 100644 Binary files a/tests/output/test_add_polygon_annotation_using_line_art_factory/output.pdf and b/tests/output/test_add_polygon_annotation_using_line_art_factory/output.pdf differ diff --git a/tests/output/test_add_polyline_annotation_using_line_art_factory/output.pdf b/tests/output/test_add_polyline_annotation_using_line_art_factory/output.pdf index 50b6a2beb..a0a7b937a 100644 Binary files a/tests/output/test_add_polyline_annotation_using_line_art_factory/output.pdf and b/tests/output/test_add_polyline_annotation_using_line_art_factory/output.pdf differ diff --git a/tests/output/test_add_redact_annotation/output_001.pdf b/tests/output/test_add_redact_annotation/output_001.pdf index cc4c55bb7..50f64f2d3 100644 Binary files a/tests/output/test_add_redact_annotation/output_001.pdf and b/tests/output/test_add_redact_annotation/output_001.pdf differ diff --git a/tests/output/test_add_redact_annotation/output_002.pdf b/tests/output/test_add_redact_annotation/output_002.pdf index 28f2a194f..ddb00f5ee 100644 Binary files a/tests/output/test_add_redact_annotation/output_002.pdf and b/tests/output/test_add_redact_annotation/output_002.pdf differ diff --git a/tests/output/test_add_redact_annotation/output_003.pdf b/tests/output/test_add_redact_annotation/output_003.pdf index f168ad4c6..51a24182f 100644 Binary files a/tests/output/test_add_redact_annotation/output_003.pdf and b/tests/output/test_add_redact_annotation/output_003.pdf differ diff --git a/tests/output/test_add_redact_annotation/output_004.pdf b/tests/output/test_add_redact_annotation/output_004.pdf index 4be84a39f..b1e7cc1fc 100644 Binary files a/tests/output/test_add_redact_annotation/output_004.pdf and b/tests/output/test_add_redact_annotation/output_004.pdf differ diff --git a/tests/output/test_add_redact_annotation/output_005.pdf b/tests/output/test_add_redact_annotation/output_005.pdf index 1b77b862d..a705d2afe 100644 Binary files a/tests/output/test_add_redact_annotation/output_005.pdf and b/tests/output/test_add_redact_annotation/output_005.pdf differ diff --git a/tests/output/test_add_remote_go_to_annotation/output_001.pdf b/tests/output/test_add_remote_go_to_annotation/output_001.pdf index c27976e6c..cf40bd40d 100644 Binary files a/tests/output/test_add_remote_go_to_annotation/output_001.pdf and b/tests/output/test_add_remote_go_to_annotation/output_001.pdf differ diff --git a/tests/output/test_add_remote_go_to_annotation/output_002.pdf b/tests/output/test_add_remote_go_to_annotation/output_002.pdf index ec24dbcee..19001b418 100644 Binary files a/tests/output/test_add_remote_go_to_annotation/output_002.pdf and b/tests/output/test_add_remote_go_to_annotation/output_002.pdf differ diff --git a/tests/output/test_add_square_annotation/output.pdf b/tests/output/test_add_square_annotation/output.pdf index 79a3b2b45..bf6a10bd3 100644 Binary files a/tests/output/test_add_square_annotation/output.pdf and b/tests/output/test_add_square_annotation/output.pdf differ diff --git a/tests/output/test_add_square_annotation_in_free_space/output_001.pdf b/tests/output/test_add_square_annotation_in_free_space/output_001.pdf index ff33ea07f..6bdadf5b0 100644 Binary files a/tests/output/test_add_square_annotation_in_free_space/output_001.pdf and b/tests/output/test_add_square_annotation_in_free_space/output_001.pdf differ diff --git a/tests/output/test_add_square_annotation_in_free_space/output_002.pdf b/tests/output/test_add_square_annotation_in_free_space/output_002.pdf index 9c2c0ac18..1656e5890 100644 Binary files a/tests/output/test_add_square_annotation_in_free_space/output_002.pdf and b/tests/output/test_add_square_annotation_in_free_space/output_002.pdf differ diff --git a/tests/output/test_add_squiggle_annotation/output_001.pdf b/tests/output/test_add_squiggle_annotation/output_001.pdf index b96dca538..f18c3341e 100644 Binary files a/tests/output/test_add_squiggle_annotation/output_001.pdf and b/tests/output/test_add_squiggle_annotation/output_001.pdf differ diff --git a/tests/output/test_add_squiggle_annotation/output_002.pdf b/tests/output/test_add_squiggle_annotation/output_002.pdf index bcb1bf274..0343b4592 100644 Binary files a/tests/output/test_add_squiggle_annotation/output_002.pdf and b/tests/output/test_add_squiggle_annotation/output_002.pdf differ diff --git a/tests/output/test_add_strikeout_annotation/output_001.pdf b/tests/output/test_add_strikeout_annotation/output_001.pdf index d849ab346..a830a6bcb 100644 Binary files a/tests/output/test_add_strikeout_annotation/output_001.pdf and b/tests/output/test_add_strikeout_annotation/output_001.pdf differ diff --git a/tests/output/test_add_strikeout_annotation/output_002.pdf b/tests/output/test_add_strikeout_annotation/output_002.pdf index 175e08c60..3bd9af572 100644 Binary files a/tests/output/test_add_strikeout_annotation/output_002.pdf and b/tests/output/test_add_strikeout_annotation/output_002.pdf differ diff --git a/tests/output/test_add_super_mario_annotation/output.pdf b/tests/output/test_add_super_mario_annotation/output.pdf index 5ec21ba33..24b84ee18 100644 Binary files a/tests/output/test_add_super_mario_annotation/output.pdf and b/tests/output/test_add_super_mario_annotation/output.pdf differ diff --git a/tests/output/test_add_text_annotation/output_001.pdf b/tests/output/test_add_text_annotation/output_001.pdf index 3675c0db4..3ec2f9a0e 100644 Binary files a/tests/output/test_add_text_annotation/output_001.pdf and b/tests/output/test_add_text_annotation/output_001.pdf differ diff --git a/tests/output/test_add_text_annotation/output_002.pdf b/tests/output/test_add_text_annotation/output_002.pdf index 8d565738a..58f4d0470 100644 Binary files a/tests/output/test_add_text_annotation/output_002.pdf and b/tests/output/test_add_text_annotation/output_002.pdf differ diff --git a/tests/output/test_add_underline_annotation/output_001.pdf b/tests/output/test_add_underline_annotation/output_001.pdf index f54dcc35c..26f02f778 100644 Binary files a/tests/output/test_add_underline_annotation/output_001.pdf and b/tests/output/test_add_underline_annotation/output_001.pdf differ diff --git a/tests/output/test_add_underline_annotation/output_002.pdf b/tests/output/test_add_underline_annotation/output_002.pdf index c67160d4c..7c77d9f0a 100644 Binary files a/tests/output/test_add_underline_annotation/output_002.pdf and b/tests/output/test_add_underline_annotation/output_002.pdf differ diff --git a/tests/output/test_analogous_color_scheme/output.pdf b/tests/output/test_analogous_color_scheme/output.pdf index d13880b55..f538ff61e 100644 Binary files a/tests/output/test_analogous_color_scheme/output.pdf and b/tests/output/test_analogous_color_scheme/output.pdf differ diff --git a/tests/output/test_append_embedded_file/output_001.pdf b/tests/output/test_append_embedded_file/output_001.pdf index 58c71db19..c23fe1ac9 100644 Binary files a/tests/output/test_append_embedded_file/output_001.pdf and b/tests/output/test_append_embedded_file/output_001.pdf differ diff --git a/tests/output/test_append_embedded_file/output_002.pdf b/tests/output/test_append_embedded_file/output_002.pdf index c3a0febe8..cffd83a9c 100644 Binary files a/tests/output/test_append_embedded_file/output_002.pdf and b/tests/output/test_append_embedded_file/output_002.pdf differ diff --git a/tests/output/test_append_embedded_javascript/output_001.pdf b/tests/output/test_append_embedded_javascript/output_001.pdf new file mode 100644 index 000000000..7ae11f55b Binary files /dev/null and b/tests/output/test_append_embedded_javascript/output_001.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_001.pdf b/tests/output/test_apply_redaction_annotations/output_001.pdf index d2cd1cf45..4da702c40 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_001.pdf and b/tests/output/test_apply_redaction_annotations/output_001.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_002.pdf b/tests/output/test_apply_redaction_annotations/output_002.pdf index 020eb1c1b..17dfb2306 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_002.pdf and b/tests/output/test_apply_redaction_annotations/output_002.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_003.pdf b/tests/output/test_apply_redaction_annotations/output_003.pdf index 76b45b03c..ec12a4d82 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_003.pdf and b/tests/output/test_apply_redaction_annotations/output_003.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_004.pdf b/tests/output/test_apply_redaction_annotations/output_004.pdf index c080fb229..d45053af8 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_004.pdf and b/tests/output/test_apply_redaction_annotations/output_004.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_005.pdf b/tests/output/test_apply_redaction_annotations/output_005.pdf index 920488f96..bfa02664f 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_005.pdf and b/tests/output/test_apply_redaction_annotations/output_005.pdf differ diff --git a/tests/output/test_apply_redaction_annotations/output_006.pdf b/tests/output/test_apply_redaction_annotations/output_006.pdf index 37d3f1fd5..7db23b666 100644 Binary files a/tests/output/test_apply_redaction_annotations/output_006.pdf and b/tests/output/test_apply_redaction_annotations/output_006.pdf differ diff --git a/tests/output/test_browser_layout_inline_next_line/output.pdf b/tests/output/test_browser_layout_inline_next_line/output.pdf index e71c7e0ef..e08a6a1c1 100644 Binary files a/tests/output/test_browser_layout_inline_next_line/output.pdf and b/tests/output/test_browser_layout_inline_next_line/output.pdf differ diff --git a/tests/output/test_change_info_dictionary_author/output_001.pdf b/tests/output/test_change_info_dictionary_author/output_001.pdf index e5c75ae9e..88b449309 100644 Binary files a/tests/output/test_change_info_dictionary_author/output_001.pdf and b/tests/output/test_change_info_dictionary_author/output_001.pdf differ diff --git a/tests/output/test_change_info_dictionary_author/output_002.pdf b/tests/output/test_change_info_dictionary_author/output_002.pdf index da2a2c997..ced2e9e7a 100644 Binary files a/tests/output/test_change_info_dictionary_author/output_002.pdf and b/tests/output/test_change_info_dictionary_author/output_002.pdf differ diff --git a/tests/output/test_concat_documents/output_000.pdf b/tests/output/test_concat_documents/output_000.pdf index 7be081516..051a20fdb 100644 Binary files a/tests/output/test_concat_documents/output_000.pdf and b/tests/output/test_concat_documents/output_000.pdf differ diff --git a/tests/output/test_concat_documents/output_001.pdf b/tests/output/test_concat_documents/output_001.pdf index 68c4a18fd..1bb7596bb 100644 Binary files a/tests/output/test_concat_documents/output_001.pdf and b/tests/output/test_concat_documents/output_001.pdf differ diff --git a/tests/output/test_concat_documents/output_002.pdf b/tests/output/test_concat_documents/output_002.pdf index f39b304a9..b1493f974 100644 Binary files a/tests/output/test_concat_documents/output_002.pdf and b/tests/output/test_concat_documents/output_002.pdf differ diff --git a/tests/output/test_copy_document_compare_size/0187_page_0_copy.pdf b/tests/output/test_copy_document_compare_size/0187_page_0_copy.pdf deleted file mode 100644 index 021de36ab..000000000 Binary files a/tests/output/test_copy_document_compare_size/0187_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_compare_size/0430_page_0_copy.pdf b/tests/output/test_copy_document_compare_size/0430_page_0_copy.pdf deleted file mode 100644 index 2092e2a1d..000000000 Binary files a/tests/output/test_copy_document_compare_size/0430_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_compare_size/0462_page_0_copy.pdf b/tests/output/test_copy_document_compare_size/0462_page_0_copy.pdf deleted file mode 100644 index 75f443d5f..000000000 Binary files a/tests/output/test_copy_document_compare_size/0462_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_compare_size/0495_page_0_copy.pdf b/tests/output/test_copy_document_compare_size/0495_page_0_copy.pdf deleted file mode 100644 index 88182e8d2..000000000 Binary files a/tests/output/test_copy_document_compare_size/0495_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_compare_size/0594_page_0_copy.pdf b/tests/output/test_copy_document_compare_size/0594_page_0_copy.pdf deleted file mode 100644 index 672cd4971..000000000 Binary files a/tests/output/test_copy_document_compare_size/0594_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_compare_size/output.pdf b/tests/output/test_copy_document_compare_size/output.pdf index 1bed09221..5b3aa4eba 100644 Binary files a/tests/output/test_copy_document_compare_size/output.pdf and b/tests/output/test_copy_document_compare_size/output.pdf differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/0187_page_0_copy.pdf b/tests/output/test_copy_document_resize_images_compare_size/0187_page_0_copy.pdf deleted file mode 100644 index 715bd87bc..000000000 Binary files a/tests/output/test_copy_document_resize_images_compare_size/0187_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/0430_page_0_copy.pdf b/tests/output/test_copy_document_resize_images_compare_size/0430_page_0_copy.pdf deleted file mode 100644 index f0516bb17..000000000 Binary files a/tests/output/test_copy_document_resize_images_compare_size/0430_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/0462_page_0_copy.pdf b/tests/output/test_copy_document_resize_images_compare_size/0462_page_0_copy.pdf deleted file mode 100644 index 4a31bf5e9..000000000 Binary files a/tests/output/test_copy_document_resize_images_compare_size/0462_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/0495_page_0_copy.pdf b/tests/output/test_copy_document_resize_images_compare_size/0495_page_0_copy.pdf deleted file mode 100644 index cb4cf3b22..000000000 Binary files a/tests/output/test_copy_document_resize_images_compare_size/0495_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/0594_page_0_copy.pdf b/tests/output/test_copy_document_resize_images_compare_size/0594_page_0_copy.pdf deleted file mode 100644 index c1d2fdedd..000000000 Binary files a/tests/output/test_copy_document_resize_images_compare_size/0594_page_0_copy.pdf and /dev/null differ diff --git a/tests/output/test_copy_document_resize_images_compare_size/output.pdf b/tests/output/test_copy_document_resize_images_compare_size/output.pdf index 593279301..2ff4cad9d 100644 Binary files a/tests/output/test_copy_document_resize_images_compare_size/output.pdf and b/tests/output/test_copy_document_resize_images_compare_size/output.pdf differ diff --git a/tests/output/test_count_annotations/output_001.pdf b/tests/output/test_count_annotations/output_001.pdf index d80a33a25..34c6508e4 100644 Binary files a/tests/output/test_count_annotations/output_001.pdf and b/tests/output/test_count_annotations/output_001.pdf differ diff --git a/tests/output/test_count_annotations/output_002.pdf b/tests/output/test_count_annotations/output_002.pdf index 3f8c1f926..03fa84c82 100644 Binary files a/tests/output/test_count_annotations/output_002.pdf and b/tests/output/test_count_annotations/output_002.pdf differ diff --git a/tests/output/test_create_document_with_output_intent/output_001.pdf b/tests/output/test_create_document_with_output_intent/output_001.pdf index 33b4433e1..5a012ae5d 100644 Binary files a/tests/output/test_create_document_with_output_intent/output_001.pdf and b/tests/output/test_create_document_with_output_intent/output_001.pdf differ diff --git a/tests/output/test_detect_table/input_000.pdf b/tests/output/test_detect_table/input_000.pdf index fbe3b2a54..0459fd52e 100644 Binary files a/tests/output/test_detect_table/input_000.pdf and b/tests/output/test_detect_table/input_000.pdf differ diff --git a/tests/output/test_detect_table/input_001.pdf b/tests/output/test_detect_table/input_001.pdf index 13f8609be..65a53f28e 100644 Binary files a/tests/output/test_detect_table/input_001.pdf and b/tests/output/test_detect_table/input_001.pdf differ diff --git a/tests/output/test_detect_table/input_002.pdf b/tests/output/test_detect_table/input_002.pdf index ab7191ead..36e97ab22 100644 Binary files a/tests/output/test_detect_table/input_002.pdf and b/tests/output/test_detect_table/input_002.pdf differ diff --git a/tests/output/test_detect_table/input_003.pdf b/tests/output/test_detect_table/input_003.pdf index 155e54aca..29c766ba9 100644 Binary files a/tests/output/test_detect_table/input_003.pdf and b/tests/output/test_detect_table/input_003.pdf differ diff --git a/tests/output/test_detect_table/input_004.pdf b/tests/output/test_detect_table/input_004.pdf index ec94f8add..c58823754 100644 Binary files a/tests/output/test_detect_table/input_004.pdf and b/tests/output/test_detect_table/input_004.pdf differ diff --git a/tests/output/test_detect_table/input_005.pdf b/tests/output/test_detect_table/input_005.pdf index 3c4fc9622..255a7ef2b 100644 Binary files a/tests/output/test_detect_table/input_005.pdf and b/tests/output/test_detect_table/input_005.pdf differ diff --git a/tests/output/test_detect_table/input_006.pdf b/tests/output/test_detect_table/input_006.pdf index 2267941c1..ac9601e40 100644 Binary files a/tests/output/test_detect_table/input_006.pdf and b/tests/output/test_detect_table/input_006.pdf differ diff --git a/tests/output/test_detect_table/output_000.pdf b/tests/output/test_detect_table/output_000.pdf index 35d192e37..8c1b3fc53 100644 Binary files a/tests/output/test_detect_table/output_000.pdf and b/tests/output/test_detect_table/output_000.pdf differ diff --git a/tests/output/test_detect_table/output_001.pdf b/tests/output/test_detect_table/output_001.pdf index 263253ba3..06370ddf5 100644 Binary files a/tests/output/test_detect_table/output_001.pdf and b/tests/output/test_detect_table/output_001.pdf differ diff --git a/tests/output/test_detect_table/output_002.pdf b/tests/output/test_detect_table/output_002.pdf index 5406a59f2..9ee901965 100644 Binary files a/tests/output/test_detect_table/output_002.pdf and b/tests/output/test_detect_table/output_002.pdf differ diff --git a/tests/output/test_detect_table/output_003.pdf b/tests/output/test_detect_table/output_003.pdf index 9963af0a2..c4ffe14a6 100644 Binary files a/tests/output/test_detect_table/output_003.pdf and b/tests/output/test_detect_table/output_003.pdf differ diff --git a/tests/output/test_detect_table/output_004.pdf b/tests/output/test_detect_table/output_004.pdf index b6fcf4764..2d73ac5fa 100644 Binary files a/tests/output/test_detect_table/output_004.pdf and b/tests/output/test_detect_table/output_004.pdf differ diff --git a/tests/output/test_detect_table/output_005.pdf b/tests/output/test_detect_table/output_005.pdf index 9ed50a3ea..9c3edd7be 100644 Binary files a/tests/output/test_detect_table/output_005.pdf and b/tests/output/test_detect_table/output_005.pdf differ diff --git a/tests/output/test_detect_table/output_006.pdf b/tests/output/test_detect_table/output_006.pdf index 0eb4d74e1..8b0fb501b 100644 Binary files a/tests/output/test_detect_table/output_006.pdf and b/tests/output/test_detect_table/output_006.pdf differ diff --git a/tests/output/test_digit_placement_ubuntu_font/output_001.pdf b/tests/output/test_digit_placement_ubuntu_font/output_001.pdf index b691f3c60..c130bfa69 100644 Binary files a/tests/output/test_digit_placement_ubuntu_font/output_001.pdf and b/tests/output/test_digit_placement_ubuntu_font/output_001.pdf differ diff --git a/tests/output/test_digit_placement_ubuntu_font/output_001.png b/tests/output/test_digit_placement_ubuntu_font/output_001.png index d718c8f44..c96f6fe59 100644 Binary files a/tests/output/test_digit_placement_ubuntu_font/output_001.png and b/tests/output/test_digit_placement_ubuntu_font/output_001.png differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_000.pdf b/tests/output/test_export_html_to_pdf/example_html_input_000.pdf index 0ab1105a8..7fc7b0606 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_000.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_000.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_001.pdf b/tests/output/test_export_html_to_pdf/example_html_input_001.pdf index c31703fcf..2f1948ed9 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_001.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_001.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_002.pdf b/tests/output/test_export_html_to_pdf/example_html_input_002.pdf index 41435fbc9..d14388170 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_002.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_002.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_003.pdf b/tests/output/test_export_html_to_pdf/example_html_input_003.pdf index f56eccea4..7a9f52bcb 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_003.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_003.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_004.pdf b/tests/output/test_export_html_to_pdf/example_html_input_004.pdf index dc304a1d0..fad91c9ab 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_004.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_004.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_005.pdf b/tests/output/test_export_html_to_pdf/example_html_input_005.pdf index d557e0bb2..aff5670a5 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_005.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_005.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_006.pdf b/tests/output/test_export_html_to_pdf/example_html_input_006.pdf index d90a4e83e..1113b3360 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_006.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_006.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_007.pdf b/tests/output/test_export_html_to_pdf/example_html_input_007.pdf index cabe64d24..81c292b71 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_007.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_007.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_008.pdf b/tests/output/test_export_html_to_pdf/example_html_input_008.pdf index fe58837c7..ef15a61c6 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_008.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_008.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_009.pdf b/tests/output/test_export_html_to_pdf/example_html_input_009.pdf index 7f146fe67..fe2e41ee4 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_009.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_009.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_010.pdf b/tests/output/test_export_html_to_pdf/example_html_input_010.pdf index d67881aff..088f0ccb8 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_010.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_010.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_011.pdf b/tests/output/test_export_html_to_pdf/example_html_input_011.pdf index a80c59b55..14aa25132 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_011.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_011.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_012.pdf b/tests/output/test_export_html_to_pdf/example_html_input_012.pdf index 56fe89cba..e3b06cd8e 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_012.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_012.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_013.pdf b/tests/output/test_export_html_to_pdf/example_html_input_013.pdf index 817815cc5..bafd02f83 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_013.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_013.pdf differ diff --git a/tests/output/test_export_html_to_pdf/example_html_input_014.pdf b/tests/output/test_export_html_to_pdf/example_html_input_014.pdf index 8b63a68ad..5c75d22b2 100644 Binary files a/tests/output/test_export_html_to_pdf/example_html_input_014.pdf and b/tests/output/test_export_html_to_pdf/example_html_input_014.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-001.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-001.md.pdf index 273c9ea90..4f697ac17 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-001.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-001.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-002.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-002.md.pdf index caa55bb38..8046456b2 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-002.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-002.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-003.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-003.md.pdf index 1dcb4eab0..9ad0893fd 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-003.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-003.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-004.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-004.md.pdf index 4ed58e17f..32e71ec57 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-004.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-004.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-005.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-005.md.pdf index e9308d9d8..c6af45b32 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-005.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-005.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-006.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-006.md.pdf index 9963c7ed8..658d4007c 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-006.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-006.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-007.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-007.md.pdf index a7f64818f..4888b0877 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-007.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-007.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-008.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-008.md.pdf index a3abedffa..3ddfbfdf4 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-008.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-008.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-009.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-009.md.pdf index a87b0ad92..9fb9fddd0 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-009.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-009.md.pdf differ diff --git a/tests/output/test_export_markdown_to_pdf/example-markdown-input-010.md.pdf b/tests/output/test_export_markdown_to_pdf/example-markdown-input-010.md.pdf index 4a2ce4029..bc629434d 100644 Binary files a/tests/output/test_export_markdown_to_pdf/example-markdown-input-010.md.pdf and b/tests/output/test_export_markdown_to_pdf/example-markdown-input-010.md.pdf differ diff --git a/tests/output/test_export_to_mp3/output.mp3 b/tests/output/test_export_to_mp3/output.mp3 index 07f2ca25b..32b44aa88 100644 Binary files a/tests/output/test_export_to_mp3/output.mp3 and b/tests/output/test_export_to_mp3/output.mp3 differ diff --git a/tests/output/test_extract_colors/output_001.pdf b/tests/output/test_extract_colors/output_001.pdf index 34696e9e1..4a6a0c95c 100644 Binary files a/tests/output/test_extract_colors/output_001.pdf and b/tests/output/test_extract_colors/output_001.pdf differ diff --git a/tests/output/test_extract_colors/output_002.pdf b/tests/output/test_extract_colors/output_002.pdf index b78bc27e0..ce11217f7 100644 Binary files a/tests/output/test_extract_colors/output_002.pdf and b/tests/output/test_extract_colors/output_002.pdf differ diff --git a/tests/output/test_extract_colors/output_002.png b/tests/output/test_extract_colors/output_002.png index 7875dae9d..be9ce68d3 100644 Binary files a/tests/output/test_extract_colors/output_002.png and b/tests/output/test_extract_colors/output_002.png differ diff --git a/tests/output/test_extract_courier_text/output_001.pdf b/tests/output/test_extract_courier_text/output_001.pdf index 029623278..1175e2849 100644 Binary files a/tests/output/test_extract_courier_text/output_001.pdf and b/tests/output/test_extract_courier_text/output_001.pdf differ diff --git a/tests/output/test_extract_font_names/output_001.pdf b/tests/output/test_extract_font_names/output_001.pdf index ae5ccf67b..16a2058d8 100644 Binary files a/tests/output/test_extract_font_names/output_001.pdf and b/tests/output/test_extract_font_names/output_001.pdf differ diff --git a/tests/output/test_extract_font_names/output_002.pdf b/tests/output/test_extract_font_names/output_002.pdf index 6d407eaca..d3a606dd6 100644 Binary files a/tests/output/test_extract_font_names/output_002.pdf and b/tests/output/test_extract_font_names/output_002.pdf differ diff --git a/tests/output/test_extract_keywords/output_001.pdf b/tests/output/test_extract_keywords/output_001.pdf index 95a1be7b7..bb3a7bd36 100644 Binary files a/tests/output/test_extract_keywords/output_001.pdf and b/tests/output/test_extract_keywords/output_001.pdf differ diff --git a/tests/output/test_extract_keywords/output_002.pdf b/tests/output/test_extract_keywords/output_002.pdf index 196a9d676..f5b277f6d 100644 Binary files a/tests/output/test_extract_keywords/output_002.pdf and b/tests/output/test_extract_keywords/output_002.pdf differ diff --git a/tests/output/test_extract_keywords/output_003.pdf b/tests/output/test_extract_keywords/output_003.pdf index 492e76d50..9a5ff3d0b 100644 Binary files a/tests/output/test_extract_keywords/output_003.pdf and b/tests/output/test_extract_keywords/output_003.pdf differ diff --git a/tests/output/test_extract_red_text/output_001.pdf b/tests/output/test_extract_red_text/output_001.pdf index 807087e81..93aaa08ec 100644 Binary files a/tests/output/test_extract_red_text/output_001.pdf and b/tests/output/test_extract_red_text/output_001.pdf differ diff --git a/tests/output/test_extract_regex/output_001.pdf b/tests/output/test_extract_regex/output_001.pdf index 5e30239d5..e1e27d7c6 100644 Binary files a/tests/output/test_extract_regex/output_001.pdf and b/tests/output/test_extract_regex/output_001.pdf differ diff --git a/tests/output/test_extract_regex/output_002.pdf b/tests/output/test_extract_regex/output_002.pdf index 545cba58d..7062d216e 100644 Binary files a/tests/output/test_extract_regex/output_002.pdf and b/tests/output/test_extract_regex/output_002.pdf differ diff --git a/tests/output/test_extract_text/output_001.pdf b/tests/output/test_extract_text/output_001.pdf index a6733b253..282b0f31a 100644 Binary files a/tests/output/test_extract_text/output_001.pdf and b/tests/output/test_extract_text/output_001.pdf differ diff --git a/tests/output/test_extract_text/output_002.pdf b/tests/output/test_extract_text/output_002.pdf index b5cd4b54c..8c6deb6cc 100644 Binary files a/tests/output/test_extract_text/output_002.pdf and b/tests/output/test_extract_text/output_002.pdf differ diff --git a/tests/output/test_extract_text_expect_ground_truth/output.pdf b/tests/output/test_extract_text_expect_ground_truth/output.pdf index 5ff6c3f19..84e113971 100644 Binary files a/tests/output/test_extract_text_expect_ground_truth/output.pdf and b/tests/output/test_extract_text_expect_ground_truth/output.pdf differ diff --git a/tests/output/test_extract_text_from_self_made_invoice/output.pdf b/tests/output/test_extract_text_from_self_made_invoice/output.pdf index 63fead8eb..1d80c40ce 100644 Binary files a/tests/output/test_extract_text_from_self_made_invoice/output.pdf and b/tests/output/test_extract_text_from_self_made_invoice/output.pdf differ diff --git a/tests/output/test_margin_and_padding/output_001.pdf b/tests/output/test_margin_and_padding/output_001.pdf index 56ec22fb4..7b92de7e7 100644 Binary files a/tests/output/test_margin_and_padding/output_001.pdf and b/tests/output/test_margin_and_padding/output_001.pdf differ diff --git a/tests/output/test_margin_and_padding/output_002.pdf b/tests/output/test_margin_and_padding/output_002.pdf index 2a818efc3..a50e342f7 100644 Binary files a/tests/output/test_margin_and_padding/output_002.pdf and b/tests/output/test_margin_and_padding/output_002.pdf differ diff --git a/tests/output/test_modify_image/output_001.pdf b/tests/output/test_modify_image/output_001.pdf index 806246300..4f7a051d2 100644 Binary files a/tests/output/test_modify_image/output_001.pdf and b/tests/output/test_modify_image/output_001.pdf differ diff --git a/tests/output/test_modify_image/output_002.pdf b/tests/output/test_modify_image/output_002.pdf index 5b4cb9740..05548534b 100644 Binary files a/tests/output/test_modify_image/output_002.pdf and b/tests/output/test_modify_image/output_002.pdf differ diff --git a/tests/output/test_open_document/output.pdf b/tests/output/test_open_document/output.pdf index bcbaa4732..445051ecd 100644 Binary files a/tests/output/test_open_document/output.pdf and b/tests/output/test_open_document/output.pdf differ diff --git a/tests/output/test_open_encrypted_document/output.pdf b/tests/output/test_open_encrypted_document/output.pdf index 8f6e030ac..d54dd32c5 100644 Binary files a/tests/output/test_open_encrypted_document/output.pdf and b/tests/output/test_open_encrypted_document/output.pdf differ diff --git a/tests/output/test_optimize_images/output_001.pdf b/tests/output/test_optimize_images/output_001.pdf index c442e12d7..706c091bd 100644 Binary files a/tests/output/test_optimize_images/output_001.pdf and b/tests/output/test_optimize_images/output_001.pdf differ diff --git a/tests/output/test_page_has_empty_resource_dictionary/output_001.pdf b/tests/output/test_page_has_empty_resource_dictionary/output_001.pdf index 025ffab64..e5f39f68e 100644 Binary files a/tests/output/test_page_has_empty_resource_dictionary/output_001.pdf and b/tests/output/test_page_has_empty_resource_dictionary/output_001.pdf differ diff --git a/tests/output/test_redact_common_regular_expressions/output_001.pdf b/tests/output/test_redact_common_regular_expressions/output_001.pdf index c6712d020..1549477d9 100644 Binary files a/tests/output/test_redact_common_regular_expressions/output_001.pdf and b/tests/output/test_redact_common_regular_expressions/output_001.pdf differ diff --git a/tests/output/test_redact_common_regular_expressions/output_002.pdf b/tests/output/test_redact_common_regular_expressions/output_002.pdf index 470895fb0..392ee3cb9 100644 Binary files a/tests/output/test_redact_common_regular_expressions/output_002.pdf and b/tests/output/test_redact_common_regular_expressions/output_002.pdf differ diff --git a/tests/output/test_redact_common_regular_expressions/output_003.pdf b/tests/output/test_redact_common_regular_expressions/output_003.pdf index cde36cf3e..aeb061540 100644 Binary files a/tests/output/test_redact_common_regular_expressions/output_003.pdf and b/tests/output/test_redact_common_regular_expressions/output_003.pdf differ diff --git a/tests/output/test_remove_annotation/output_001.pdf b/tests/output/test_remove_annotation/output_001.pdf index 0566f1598..f67f25646 100644 Binary files a/tests/output/test_remove_annotation/output_001.pdf and b/tests/output/test_remove_annotation/output_001.pdf differ diff --git a/tests/output/test_remove_annotation/output_002.pdf b/tests/output/test_remove_annotation/output_002.pdf index 1c7bb5f3a..d1a6bad3a 100644 Binary files a/tests/output/test_remove_annotation/output_002.pdf and b/tests/output/test_remove_annotation/output_002.pdf differ diff --git a/tests/output/test_remove_annotation/output_003.pdf b/tests/output/test_remove_annotation/output_003.pdf index a0703f544..2b6345036 100644 Binary files a/tests/output/test_remove_annotation/output_003.pdf and b/tests/output/test_remove_annotation/output_003.pdf differ diff --git a/tests/output/test_remove_page/output_001.pdf b/tests/output/test_remove_page/output_001.pdf index ca1cd031a..b9fe49031 100644 Binary files a/tests/output/test_remove_page/output_001.pdf and b/tests/output/test_remove_page/output_001.pdf differ diff --git a/tests/output/test_remove_page/output_002.pdf b/tests/output/test_remove_page/output_002.pdf index 0e97e0ce5..04d285db1 100644 Binary files a/tests/output/test_remove_page/output_002.pdf and b/tests/output/test_remove_page/output_002.pdf differ diff --git a/tests/output/test_remove_page/output_003.pdf b/tests/output/test_remove_page/output_003.pdf index a3eafbe1b..4d9ad9399 100644 Binary files a/tests/output/test_remove_page/output_003.pdf and b/tests/output/test_remove_page/output_003.pdf differ diff --git a/tests/output/test_remove_page/output_004.pdf b/tests/output/test_remove_page/output_004.pdf index 9aad02c13..659859940 100644 Binary files a/tests/output/test_remove_page/output_004.pdf and b/tests/output/test_remove_page/output_004.pdf differ diff --git a/tests/output/test_rotate_page/output_001.pdf b/tests/output/test_rotate_page/output_001.pdf index 8cd061f4c..9705423a1 100644 Binary files a/tests/output/test_rotate_page/output_001.pdf and b/tests/output/test_rotate_page/output_001.pdf differ diff --git a/tests/output/test_rotate_page/output_002.pdf b/tests/output/test_rotate_page/output_002.pdf index f07ac868a..c9d0fca4f 100644 Binary files a/tests/output/test_rotate_page/output_002.pdf and b/tests/output/test_rotate_page/output_002.pdf differ diff --git a/tests/output/test_rotate_page/output_003.pdf b/tests/output/test_rotate_page/output_003.pdf index 56adbacfd..775604d11 100644 Binary files a/tests/output/test_rotate_page/output_003.pdf and b/tests/output/test_rotate_page/output_003.pdf differ diff --git a/tests/output/test_split_complementary_color_scheme/output.pdf b/tests/output/test_split_complementary_color_scheme/output.pdf index 0252667cb..629e6a860 100644 Binary files a/tests/output/test_split_complementary_color_scheme/output.pdf and b/tests/output/test_split_complementary_color_scheme/output.pdf differ diff --git a/tests/output/test_tetradic_rectangle_color_scheme/output.pdf b/tests/output/test_tetradic_rectangle_color_scheme/output.pdf index f54573c85..98e7bbfa0 100644 Binary files a/tests/output/test_tetradic_rectangle_color_scheme/output.pdf and b/tests/output/test_tetradic_rectangle_color_scheme/output.pdf differ diff --git a/tests/output/test_tetradic_square_color_scheme/output.pdf b/tests/output/test_tetradic_square_color_scheme/output.pdf index 0f1f3b6ab..84b25423f 100644 Binary files a/tests/output/test_tetradic_square_color_scheme/output.pdf and b/tests/output/test_tetradic_square_color_scheme/output.pdf differ diff --git a/tests/output/test_triadic_color_scheme/output.pdf b/tests/output/test_triadic_color_scheme/output.pdf index 50a75e268..8261293c0 100644 Binary files a/tests/output/test_triadic_color_scheme/output.pdf and b/tests/output/test_triadic_color_scheme/output.pdf differ diff --git a/tests/output/test_write_2_scatter_plots/output.pdf b/tests/output/test_write_2_scatter_plots/output.pdf index 18ff9c86d..de5c30673 100644 Binary files a/tests/output/test_write_2_scatter_plots/output.pdf and b/tests/output/test_write_2_scatter_plots/output.pdf differ diff --git a/tests/output/test_write_3d_density_chart/output.pdf b/tests/output/test_write_3d_density_chart/output.pdf index e94bf686d..5251c5443 100644 Binary files a/tests/output/test_write_3d_density_chart/output.pdf and b/tests/output/test_write_3d_density_chart/output.pdf differ diff --git a/tests/output/test_write_3d_surface_plot/output.pdf b/tests/output/test_write_3d_surface_plot/output.pdf index a37317ec0..67ebc28f7 100644 Binary files a/tests/output/test_write_3d_surface_plot/output.pdf and b/tests/output/test_write_3d_surface_plot/output.pdf differ diff --git a/tests/output/test_write_all_types_of_barcode/output.pdf b/tests/output/test_write_all_types_of_barcode/output.pdf index 29de4f32c..d7e162ef4 100644 Binary files a/tests/output/test_write_all_types_of_barcode/output.pdf and b/tests/output/test_write_all_types_of_barcode/output.pdf differ diff --git a/tests/output/test_write_battleship/output.pdf b/tests/output/test_write_battleship/output.pdf index 6255d2436..154ff6a73 100644 Binary files a/tests/output/test_write_battleship/output.pdf and b/tests/output/test_write_battleship/output.pdf differ diff --git a/tests/output/test_write_blobs/output.pdf b/tests/output/test_write_blobs/output.pdf index 34622e2a0..f0bc0582c 100644 Binary files a/tests/output/test_write_blobs/output.pdf and b/tests/output/test_write_blobs/output.pdf differ diff --git a/tests/output/test_write_check_box/output_001.pdf b/tests/output/test_write_check_box/output_001.pdf index b53894e76..23e6393b8 100644 Binary files a/tests/output/test_write_check_box/output_001.pdf and b/tests/output/test_write_check_box/output_001.pdf differ diff --git a/tests/output/test_write_check_box/output_002.pdf b/tests/output/test_write_check_box/output_002.pdf index fbc69c6f4..73978d27e 100644 Binary files a/tests/output/test_write_check_box/output_002.pdf and b/tests/output/test_write_check_box/output_002.pdf differ diff --git a/tests/output/test_write_chunk_of_text/output.pdf b/tests/output/test_write_chunk_of_text/output.pdf index 13aa18038..8f190465e 100644 Binary files a/tests/output/test_write_chunk_of_text/output.pdf and b/tests/output/test_write_chunk_of_text/output.pdf differ diff --git a/tests/output/test_write_chunk_of_text_escaped_chars/output.pdf b/tests/output/test_write_chunk_of_text_escaped_chars/output.pdf index 1d2f3ec1c..cc109c5c3 100644 Binary files a/tests/output/test_write_chunk_of_text_escaped_chars/output.pdf and b/tests/output/test_write_chunk_of_text_escaped_chars/output.pdf differ diff --git a/tests/output/test_write_chunk_of_text_in_rainbow_colors/output.pdf b/tests/output/test_write_chunk_of_text_in_rainbow_colors/output.pdf index 1f39b0c2d..9ff76f659 100644 Binary files a/tests/output/test_write_chunk_of_text_in_rainbow_colors/output.pdf and b/tests/output/test_write_chunk_of_text_in_rainbow_colors/output.pdf differ diff --git a/tests/output/test_write_chunks_of_text/output_001.pdf b/tests/output/test_write_chunks_of_text/output_001.pdf index 7b6cb2b17..a2a4de953 100644 Binary files a/tests/output/test_write_chunks_of_text/output_001.pdf and b/tests/output/test_write_chunks_of_text/output_001.pdf differ diff --git a/tests/output/test_write_chunks_of_text/output_002.pdf b/tests/output/test_write_chunks_of_text/output_002.pdf index 7a6005dde..84cd36c07 100644 Binary files a/tests/output/test_write_chunks_of_text/output_002.pdf and b/tests/output/test_write_chunks_of_text/output_002.pdf differ diff --git a/tests/output/test_write_chunks_of_text/output_003.pdf b/tests/output/test_write_chunks_of_text/output_003.pdf index e378194f6..e29726788 100644 Binary files a/tests/output/test_write_chunks_of_text/output_003.pdf and b/tests/output/test_write_chunks_of_text/output_003.pdf differ diff --git a/tests/output/test_write_chunks_of_text/output_004.pdf b/tests/output/test_write_chunks_of_text/output_004.pdf index f20a10647..bbf90cd37 100644 Binary files a/tests/output/test_write_chunks_of_text/output_004.pdf and b/tests/output/test_write_chunks_of_text/output_004.pdf differ diff --git a/tests/output/test_write_chunks_of_text/output_005.pdf b/tests/output/test_write_chunks_of_text/output_005.pdf index 68712a7b2..4713b0aaf 100644 Binary files a/tests/output/test_write_chunks_of_text/output_005.pdf and b/tests/output/test_write_chunks_of_text/output_005.pdf differ diff --git a/tests/output/test_write_chunks_of_text_preserves_bounding_boxes/output.pdf b/tests/output/test_write_chunks_of_text_preserves_bounding_boxes/output.pdf index bbaa18534..5d77b9f8e 100644 Binary files a/tests/output/test_write_chunks_of_text_preserves_bounding_boxes/output.pdf and b/tests/output/test_write_chunks_of_text_preserves_bounding_boxes/output.pdf differ diff --git a/tests/output/test_write_code_128_barcode/output.pdf b/tests/output/test_write_code_128_barcode/output.pdf index 99fc0c46f..7a9e37ef0 100644 Binary files a/tests/output/test_write_code_128_barcode/output.pdf and b/tests/output/test_write_code_128_barcode/output.pdf differ diff --git a/tests/output/test_write_code_128_barcode_in_color/output.pdf b/tests/output/test_write_code_128_barcode_in_color/output.pdf index f708412f8..d18dd7387 100644 Binary files a/tests/output/test_write_code_128_barcode_in_color/output.pdf and b/tests/output/test_write_code_128_barcode_in_color/output.pdf differ diff --git a/tests/output/test_write_codeblock/output.pdf b/tests/output/test_write_codeblock/output.pdf index 558d0ce82..73f026a1e 100644 Binary files a/tests/output/test_write_codeblock/output.pdf and b/tests/output/test_write_codeblock/output.pdf differ diff --git a/tests/output/test_write_dragon_curve/output.pdf b/tests/output/test_write_dragon_curve/output.pdf index cf4c110a3..e62d579e8 100644 Binary files a/tests/output/test_write_dragon_curve/output.pdf and b/tests/output/test_write_dragon_curve/output.pdf differ diff --git a/tests/output/test_write_drop_down_list/output_001.pdf b/tests/output/test_write_drop_down_list/output_001.pdf index 516daf0cd..3d013befc 100644 Binary files a/tests/output/test_write_drop_down_list/output_001.pdf and b/tests/output/test_write_drop_down_list/output_001.pdf differ diff --git a/tests/output/test_write_drop_down_list/output_002.pdf b/tests/output/test_write_drop_down_list/output_002.pdf index df96236ae..56e3bb25f 100644 Binary files a/tests/output/test_write_drop_down_list/output_002.pdf and b/tests/output/test_write_drop_down_list/output_002.pdf differ diff --git a/tests/output/test_write_emoji/output.pdf b/tests/output/test_write_emoji/output.pdf index eec2ffcc4..3170c6a9e 100644 Binary files a/tests/output/test_write_emoji/output.pdf and b/tests/output/test_write_emoji/output.pdf differ diff --git a/tests/output/test_write_empty_document/output.pdf b/tests/output/test_write_empty_document/output.pdf index 4298dcd07..d1723d22f 100644 Binary files a/tests/output/test_write_empty_document/output.pdf and b/tests/output/test_write_empty_document/output.pdf differ diff --git a/tests/output/test_write_fixed_column_width_table/output_001.pdf b/tests/output/test_write_fixed_column_width_table/output_001.pdf index b90a9ed83..62ff8c3a1 100644 Binary files a/tests/output/test_write_fixed_column_width_table/output_001.pdf and b/tests/output/test_write_fixed_column_width_table/output_001.pdf differ diff --git a/tests/output/test_write_fixed_column_width_table/output_002.pdf b/tests/output/test_write_fixed_column_width_table/output_002.pdf index 18217c575..e6ff24331 100644 Binary files a/tests/output/test_write_fixed_column_width_table/output_002.pdf and b/tests/output/test_write_fixed_column_width_table/output_002.pdf differ diff --git a/tests/output/test_write_fixed_column_width_table/output_003.pdf b/tests/output/test_write_fixed_column_width_table/output_003.pdf index 3ed23582c..1f1ebc5e4 100644 Binary files a/tests/output/test_write_fixed_column_width_table/output_003.pdf and b/tests/output/test_write_fixed_column_width_table/output_003.pdf differ diff --git a/tests/output/test_write_fixed_column_width_table/output_004.pdf b/tests/output/test_write_fixed_column_width_table/output_004.pdf index f47b6dcfd..e92b08ac5 100644 Binary files a/tests/output/test_write_fixed_column_width_table/output_004.pdf and b/tests/output/test_write_fixed_column_width_table/output_004.pdf differ diff --git a/tests/output/test_write_fixed_column_width_table/output_005.pdf b/tests/output/test_write_fixed_column_width_table/output_005.pdf index 32e507151..dad92af0f 100644 Binary files a/tests/output/test_write_fixed_column_width_table/output_005.pdf and b/tests/output/test_write_fixed_column_width_table/output_005.pdf differ diff --git a/tests/output/test_write_flexi_table/output_001.pdf b/tests/output/test_write_flexi_table/output_001.pdf index 5de0a370a..19d7dfd13 100644 Binary files a/tests/output/test_write_flexi_table/output_001.pdf and b/tests/output/test_write_flexi_table/output_001.pdf differ diff --git a/tests/output/test_write_flexi_table/output_002.pdf b/tests/output/test_write_flexi_table/output_002.pdf index 535c2484e..e3c5c19be 100644 Binary files a/tests/output/test_write_flexi_table/output_002.pdf and b/tests/output/test_write_flexi_table/output_002.pdf differ diff --git a/tests/output/test_write_flexi_table/output_003.pdf b/tests/output/test_write_flexi_table/output_003.pdf index 00476139d..f102361ab 100644 Binary files a/tests/output/test_write_flexi_table/output_003.pdf and b/tests/output/test_write_flexi_table/output_003.pdf differ diff --git a/tests/output/test_write_flexi_table/output_004.pdf b/tests/output/test_write_flexi_table/output_004.pdf index e13346ab2..bde67186b 100644 Binary files a/tests/output/test_write_flexi_table/output_004.pdf and b/tests/output/test_write_flexi_table/output_004.pdf differ diff --git a/tests/output/test_write_flexi_table/output_005.pdf b/tests/output/test_write_flexi_table/output_005.pdf index cea3e62cc..632c50dbb 100644 Binary files a/tests/output/test_write_flexi_table/output_005.pdf and b/tests/output/test_write_flexi_table/output_005.pdf differ diff --git a/tests/output/test_write_flexi_table_with_preferred_width/output.pdf b/tests/output/test_write_flexi_table_with_preferred_width/output.pdf index b05f6259e..b8f176d31 100644 Binary files a/tests/output/test_write_flexi_table_with_preferred_width/output.pdf and b/tests/output/test_write_flexi_table_with_preferred_width/output.pdf differ diff --git a/tests/output/test_write_flowchart_line_art/output.pdf b/tests/output/test_write_flowchart_line_art/output.pdf index 81b9bd3b0..6a40a34d7 100644 Binary files a/tests/output/test_write_flowchart_line_art/output.pdf and b/tests/output/test_write_flowchart_line_art/output.pdf differ diff --git a/tests/output/test_write_flyer/output.pdf b/tests/output/test_write_flyer/output.pdf index e109b23fe..1ef7558d9 100644 Binary files a/tests/output/test_write_flyer/output.pdf and b/tests/output/test_write_flyer/output.pdf differ diff --git a/tests/output/test_write_gradient_rectangular_maze/output_001.pdf b/tests/output/test_write_gradient_rectangular_maze/output_001.pdf index 892a6324f..2b2e07d2f 100644 Binary files a/tests/output/test_write_gradient_rectangular_maze/output_001.pdf and b/tests/output/test_write_gradient_rectangular_maze/output_001.pdf differ diff --git a/tests/output/test_write_gradient_rectangular_maze/output_002.pdf b/tests/output/test_write_gradient_rectangular_maze/output_002.pdf index 10b8bfbec..34357f682 100644 Binary files a/tests/output/test_write_gradient_rectangular_maze/output_002.pdf and b/tests/output/test_write_gradient_rectangular_maze/output_002.pdf differ diff --git a/tests/output/test_write_gradient_rectangular_maze/output_003.pdf b/tests/output/test_write_gradient_rectangular_maze/output_003.pdf index 0479f3b96..69acae679 100644 Binary files a/tests/output/test_write_gradient_rectangular_maze/output_003.pdf and b/tests/output/test_write_gradient_rectangular_maze/output_003.pdf differ diff --git a/tests/output/test_write_grayscale_image/output.pdf b/tests/output/test_write_grayscale_image/output.pdf index 5d43149c8..444722dc6 100644 Binary files a/tests/output/test_write_grayscale_image/output.pdf and b/tests/output/test_write_grayscale_image/output.pdf differ diff --git a/tests/output/test_write_hello_world_with_monaco_font/output_001.pdf b/tests/output/test_write_hello_world_with_monaco_font/output_001.pdf index 46d7ac0ba..30a870e8e 100644 Binary files a/tests/output/test_write_hello_world_with_monaco_font/output_001.pdf and b/tests/output/test_write_hello_world_with_monaco_font/output_001.pdf differ diff --git a/tests/output/test_write_hello_world_with_simhei_font/output_001.pdf b/tests/output/test_write_hello_world_with_simhei_font/output_001.pdf index fd1cea481..db1369297 100644 Binary files a/tests/output/test_write_hello_world_with_simhei_font/output_001.pdf and b/tests/output/test_write_hello_world_with_simhei_font/output_001.pdf differ diff --git a/tests/output/test_write_hyphenated_paragraph/output_001.pdf b/tests/output/test_write_hyphenated_paragraph/output_001.pdf index 7ba92f3a8..3395be4e8 100644 Binary files a/tests/output/test_write_hyphenated_paragraph/output_001.pdf and b/tests/output/test_write_hyphenated_paragraph/output_001.pdf differ diff --git a/tests/output/test_write_hyphenated_paragraph/output_002.pdf b/tests/output/test_write_hyphenated_paragraph/output_002.pdf index 3a4d7ca72..d05d4dca7 100644 Binary files a/tests/output/test_write_hyphenated_paragraph/output_002.pdf and b/tests/output/test_write_hyphenated_paragraph/output_002.pdf differ diff --git a/tests/output/test_write_image_aligned_center/output.pdf b/tests/output/test_write_image_aligned_center/output.pdf index 5dd7ed6d3..53ae15a37 100644 Binary files a/tests/output/test_write_image_aligned_center/output.pdf and b/tests/output/test_write_image_aligned_center/output.pdf differ diff --git a/tests/output/test_write_image_by_url/output.pdf b/tests/output/test_write_image_by_url/output.pdf index ee031d843..4300d8fd6 100644 Binary files a/tests/output/test_write_image_by_url/output.pdf and b/tests/output/test_write_image_by_url/output.pdf differ diff --git a/tests/output/test_write_incomplete_table/output.pdf b/tests/output/test_write_incomplete_table/output.pdf index f3a863867..6cad4ec91 100644 Binary files a/tests/output/test_write_incomplete_table/output.pdf and b/tests/output/test_write_incomplete_table/output.pdf differ diff --git a/tests/output/test_write_line_of_text_justified_center/output.pdf b/tests/output/test_write_line_of_text_justified_center/output.pdf index e8a5ba759..1ce6532d1 100644 Binary files a/tests/output/test_write_line_of_text_justified_center/output.pdf and b/tests/output/test_write_line_of_text_justified_center/output.pdf differ diff --git a/tests/output/test_write_line_of_text_justified_full/output.pdf b/tests/output/test_write_line_of_text_justified_full/output.pdf index 0d4f7352b..a9b930809 100644 Binary files a/tests/output/test_write_line_of_text_justified_full/output.pdf and b/tests/output/test_write_line_of_text_justified_full/output.pdf differ diff --git a/tests/output/test_write_line_of_text_justified_right/output.pdf b/tests/output/test_write_line_of_text_justified_right/output_001.pdf similarity index 52% rename from tests/output/test_write_line_of_text_justified_right/output.pdf rename to tests/output/test_write_line_of_text_justified_right/output_001.pdf index 64b1effb3..2dae37890 100644 Binary files a/tests/output/test_write_line_of_text_justified_right/output.pdf and b/tests/output/test_write_line_of_text_justified_right/output_001.pdf differ diff --git a/tests/output/test_write_line_of_text_justified_right/output_002.pdf b/tests/output/test_write_line_of_text_justified_right/output_002.pdf new file mode 100644 index 000000000..b346abd0e Binary files /dev/null and b/tests/output/test_write_line_of_text_justified_right/output_002.pdf differ diff --git a/tests/output/test_write_lissajours_line_art/output.pdf b/tests/output/test_write_lissajours_line_art/output.pdf index 73d31489d..42815d046 100644 Binary files a/tests/output/test_write_lissajours_line_art/output.pdf and b/tests/output/test_write_lissajours_line_art/output.pdf differ diff --git a/tests/output/test_write_long_unordered_list/output.pdf b/tests/output/test_write_long_unordered_list/output.pdf index 719b7a746..8bc99eca8 100644 Binary files a/tests/output/test_write_long_unordered_list/output.pdf and b/tests/output/test_write_long_unordered_list/output.pdf differ diff --git a/tests/output/test_write_multiple_pages/output.pdf b/tests/output/test_write_multiple_pages/output.pdf index b63ae06d5..02afb1d18 100644 Binary files a/tests/output/test_write_multiple_pages/output.pdf and b/tests/output/test_write_multiple_pages/output.pdf differ diff --git a/tests/output/test_write_nested_ordered_list/output.pdf b/tests/output/test_write_nested_ordered_list/output.pdf index 03a63021f..f8ca95593 100644 Binary files a/tests/output/test_write_nested_ordered_list/output.pdf and b/tests/output/test_write_nested_ordered_list/output.pdf differ diff --git a/tests/output/test_write_nested_unordered_list/output.pdf b/tests/output/test_write_nested_unordered_list/output.pdf index 97a31bc45..07f29ec1d 100644 Binary files a/tests/output/test_write_nested_unordered_list/output.pdf and b/tests/output/test_write_nested_unordered_list/output.pdf differ diff --git a/tests/output/test_write_nested_unordered_list/output.png b/tests/output/test_write_nested_unordered_list/output.png index ef3f89a69..d7702228a 100644 Binary files a/tests/output/test_write_nested_unordered_list/output.png and b/tests/output/test_write_nested_unordered_list/output.png differ diff --git a/tests/output/test_write_ordered_list/output_001.pdf b/tests/output/test_write_ordered_list/output_001.pdf index 31dd36391..a6742e699 100644 Binary files a/tests/output/test_write_ordered_list/output_001.pdf and b/tests/output/test_write_ordered_list/output_001.pdf differ diff --git a/tests/output/test_write_ordered_list/output_002.pdf b/tests/output/test_write_ordered_list/output_002.pdf index f41e23be3..018b972ec 100644 Binary files a/tests/output/test_write_ordered_list/output_002.pdf and b/tests/output/test_write_ordered_list/output_002.pdf differ diff --git a/tests/output/test_write_paragraph/output.pdf b/tests/output/test_write_paragraph/output.pdf index e781c2f5e..a801977f6 100644 Binary files a/tests/output/test_write_paragraph/output.pdf and b/tests/output/test_write_paragraph/output.pdf differ diff --git a/tests/output/test_write_paragraph_alignment/output.pdf b/tests/output/test_write_paragraph_alignment/output.pdf index 0684074c0..9ba3084c3 100644 Binary files a/tests/output/test_write_paragraph_alignment/output.pdf and b/tests/output/test_write_paragraph_alignment/output.pdf differ diff --git a/tests/output/test_write_paragraph_border_left/output.pdf b/tests/output/test_write_paragraph_border_left/output.pdf index abf398a33..45740f632 100644 Binary files a/tests/output/test_write_paragraph_border_left/output.pdf and b/tests/output/test_write_paragraph_border_left/output.pdf differ diff --git a/tests/output/test_write_paragraph_force_split/output.pdf b/tests/output/test_write_paragraph_force_split/output.pdf index 363df38bf..3fa533f60 100644 Binary files a/tests/output/test_write_paragraph_force_split/output.pdf and b/tests/output/test_write_paragraph_force_split/output.pdf differ diff --git a/tests/output/test_write_paragraph_justified_center/output_001.pdf b/tests/output/test_write_paragraph_justified_center/output_001.pdf index ad9a3c706..5246108ad 100644 Binary files a/tests/output/test_write_paragraph_justified_center/output_001.pdf and b/tests/output/test_write_paragraph_justified_center/output_001.pdf differ diff --git a/tests/output/test_write_paragraph_justified_center/output_002.pdf b/tests/output/test_write_paragraph_justified_center/output_002.pdf index 1da66518e..bd14b175a 100644 Binary files a/tests/output/test_write_paragraph_justified_center/output_002.pdf and b/tests/output/test_write_paragraph_justified_center/output_002.pdf differ diff --git a/tests/output/test_write_paragraph_justified_center_with_padding/output.pdf b/tests/output/test_write_paragraph_justified_center_with_padding/output.pdf index 0c5d12310..de1779024 100644 Binary files a/tests/output/test_write_paragraph_justified_center_with_padding/output.pdf and b/tests/output/test_write_paragraph_justified_center_with_padding/output.pdf differ diff --git a/tests/output/test_write_paragraph_justified_center_with_padding_and_border/output.pdf b/tests/output/test_write_paragraph_justified_center_with_padding_and_border/output.pdf index 01e70ba8e..5fe2df80f 100644 Binary files a/tests/output/test_write_paragraph_justified_center_with_padding_and_border/output.pdf and b/tests/output/test_write_paragraph_justified_center_with_padding_and_border/output.pdf differ diff --git a/tests/output/test_write_paragraph_justified_center_with_padding_and_border_and_background/output.pdf b/tests/output/test_write_paragraph_justified_center_with_padding_and_border_and_background/output.pdf index aa0d2d70c..eb991c206 100644 Binary files a/tests/output/test_write_paragraph_justified_center_with_padding_and_border_and_background/output.pdf and b/tests/output/test_write_paragraph_justified_center_with_padding_and_border_and_background/output.pdf differ diff --git a/tests/output/test_write_paragraph_justified_full/output.pdf b/tests/output/test_write_paragraph_justified_full/output.pdf index 806ea78e1..1e7d15f55 100644 Binary files a/tests/output/test_write_paragraph_justified_full/output.pdf and b/tests/output/test_write_paragraph_justified_full/output.pdf differ diff --git a/tests/output/test_write_paragraph_justified_right/output.pdf b/tests/output/test_write_paragraph_justified_right/output.pdf index be60124b7..b0a984526 100644 Binary files a/tests/output/test_write_paragraph_justified_right/output.pdf and b/tests/output/test_write_paragraph_justified_right/output.pdf differ diff --git a/tests/output/test_write_paragraph_preserve_space/output.pdf b/tests/output/test_write_paragraph_preserve_space/output.pdf index 32083d7a7..17fc4a526 100644 Binary files a/tests/output/test_write_paragraph_preserve_space/output.pdf and b/tests/output/test_write_paragraph_preserve_space/output.pdf differ diff --git a/tests/output/test_write_paragraph_save_twice/output_001.pdf b/tests/output/test_write_paragraph_save_twice/output_001.pdf index c6eb5f97d..b74b9e222 100644 Binary files a/tests/output/test_write_paragraph_save_twice/output_001.pdf and b/tests/output/test_write_paragraph_save_twice/output_001.pdf differ diff --git a/tests/output/test_write_paragraph_save_twice/output_002.pdf b/tests/output/test_write_paragraph_save_twice/output_002.pdf index 0bdc17a26..a568b609d 100644 Binary files a/tests/output/test_write_paragraph_save_twice/output_002.pdf and b/tests/output/test_write_paragraph_save_twice/output_002.pdf differ diff --git a/tests/output/test_write_paragraph_with_accented_letters/output.pdf b/tests/output/test_write_paragraph_with_accented_letters/output.pdf index 328930bf4..cbf055565 100644 Binary files a/tests/output/test_write_paragraph_with_accented_letters/output.pdf and b/tests/output/test_write_paragraph_with_accented_letters/output.pdf differ diff --git a/tests/output/test_write_paragraphs_using_multi_column_layout/output.pdf b/tests/output/test_write_paragraphs_using_multi_column_layout/output.pdf index 059848a3f..f842aff47 100644 Binary files a/tests/output/test_write_paragraphs_using_multi_column_layout/output.pdf and b/tests/output/test_write_paragraphs_using_multi_column_layout/output.pdf differ diff --git a/tests/output/test_write_paragraphs_using_single_column_layout/output.pdf b/tests/output/test_write_paragraphs_using_single_column_layout/output.pdf index c361b8264..13d0d054d 100644 Binary files a/tests/output/test_write_paragraphs_using_single_column_layout/output.pdf and b/tests/output/test_write_paragraphs_using_single_column_layout/output.pdf differ diff --git a/tests/output/test_write_paragraphs_with_headings/output.pdf b/tests/output/test_write_paragraphs_with_headings/output.pdf index 33057a14d..4f60f182e 100644 Binary files a/tests/output/test_write_paragraphs_with_headings/output.pdf and b/tests/output/test_write_paragraphs_with_headings/output.pdf differ diff --git a/tests/output/test_write_pdf_a_1b/output_001.pdf b/tests/output/test_write_pdf_a_1b/output_001.pdf index f08bcb86f..9bd8fdcdd 100644 Binary files a/tests/output/test_write_pdf_a_1b/output_001.pdf and b/tests/output/test_write_pdf_a_1b/output_001.pdf differ diff --git a/tests/output/test_write_pdf_a_1b/output_002.pdf b/tests/output/test_write_pdf_a_1b/output_002.pdf index 4ad166e1f..15bc2c6bf 100644 Binary files a/tests/output/test_write_pdf_a_1b/output_002.pdf and b/tests/output/test_write_pdf_a_1b/output_002.pdf differ diff --git a/tests/output/test_write_pil_image/output.pdf b/tests/output/test_write_pil_image/output.pdf index 0e42e82fe..8da7e9777 100644 Binary files a/tests/output/test_write_pil_image/output.pdf and b/tests/output/test_write_pil_image/output.pdf differ diff --git a/tests/output/test_write_png_image_by_url/output.pdf b/tests/output/test_write_png_image_by_url/output.pdf index 287cfb220..ec0ae3f31 100644 Binary files a/tests/output/test_write_png_image_by_url/output.pdf and b/tests/output/test_write_png_image_by_url/output.pdf differ diff --git a/tests/output/test_write_push_button/output_001.pdf b/tests/output/test_write_push_button/output_001.pdf new file mode 100644 index 000000000..d7cfaea56 Binary files /dev/null and b/tests/output/test_write_push_button/output_001.pdf differ diff --git a/tests/output/test_write_push_button/output_002.pdf b/tests/output/test_write_push_button/output_002.pdf new file mode 100644 index 000000000..506a05c30 Binary files /dev/null and b/tests/output/test_write_push_button/output_002.pdf differ diff --git a/tests/output/test_write_radar_plot/output.pdf b/tests/output/test_write_radar_plot/output.pdf index 07b022b59..3ab52f5ad 100644 Binary files a/tests/output/test_write_radar_plot/output.pdf and b/tests/output/test_write_radar_plot/output.pdf differ diff --git a/tests/output/test_write_rectangular_hitomezashi/output.pdf b/tests/output/test_write_rectangular_hitomezashi/output.pdf index eee3fc201..a1eb7759c 100644 Binary files a/tests/output/test_write_rectangular_hitomezashi/output.pdf and b/tests/output/test_write_rectangular_hitomezashi/output.pdf differ diff --git a/tests/output/test_write_rectangular_maze/output.pdf b/tests/output/test_write_rectangular_maze/output.pdf index 726bfddc0..4117d5950 100644 Binary files a/tests/output/test_write_rectangular_maze/output.pdf and b/tests/output/test_write_rectangular_maze/output.pdf differ diff --git a/tests/output/test_write_single_line_justified_full/output_001.pdf b/tests/output/test_write_single_line_justified_full/output_001.pdf index 9cecf5cbe..47e188960 100644 Binary files a/tests/output/test_write_single_line_justified_full/output_001.pdf and b/tests/output/test_write_single_line_justified_full/output_001.pdf differ diff --git a/tests/output/test_write_single_line_justified_full/output_002.pdf b/tests/output/test_write_single_line_justified_full/output_002.pdf index 32d0d2e52..1bb5b8603 100644 Binary files a/tests/output/test_write_single_line_justified_full/output_002.pdf and b/tests/output/test_write_single_line_justified_full/output_002.pdf differ diff --git a/tests/output/test_write_table_with_col_span/output.pdf b/tests/output/test_write_table_with_col_span/output.pdf index 9e14c7e49..9757b6b12 100644 Binary files a/tests/output/test_write_table_with_col_span/output.pdf and b/tests/output/test_write_table_with_col_span/output.pdf differ diff --git a/tests/output/test_write_table_with_image/output.pdf b/tests/output/test_write_table_with_image/output.pdf index ed02934e2..538329780 100644 Binary files a/tests/output/test_write_table_with_image/output.pdf and b/tests/output/test_write_table_with_image/output.pdf differ diff --git a/tests/output/test_write_table_with_non_black_paragraphs/output.pdf b/tests/output/test_write_table_with_non_black_paragraphs/output.pdf index 9d0c64679..64c34b41f 100644 Binary files a/tests/output/test_write_table_with_non_black_paragraphs/output.pdf and b/tests/output/test_write_table_with_non_black_paragraphs/output.pdf differ diff --git a/tests/output/test_write_table_with_rainbow_background/output.pdf b/tests/output/test_write_table_with_rainbow_background/output.pdf index f22cf6325..e41a1873f 100644 Binary files a/tests/output/test_write_table_with_rainbow_background/output.pdf and b/tests/output/test_write_table_with_rainbow_background/output.pdf differ diff --git a/tests/output/test_write_table_with_row_span/output.pdf b/tests/output/test_write_table_with_row_span/output.pdf index 551700c3a..163d7aeff 100644 Binary files a/tests/output/test_write_table_with_row_span/output.pdf and b/tests/output/test_write_table_with_row_span/output.pdf differ diff --git a/tests/output/test_write_table_with_special_characters/output.pdf b/tests/output/test_write_table_with_special_characters/output.pdf index 8b3616b3b..627523d39 100644 Binary files a/tests/output/test_write_table_with_special_characters/output.pdf and b/tests/output/test_write_table_with_special_characters/output.pdf differ diff --git a/tests/output/test_write_tents_and_trees/output.pdf b/tests/output/test_write_tents_and_trees/output.pdf index a81804a81..3b42cb70a 100644 Binary files a/tests/output/test_write_tents_and_trees/output.pdf and b/tests/output/test_write_tents_and_trees/output.pdf differ diff --git a/tests/output/test_write_text_area/output_001.pdf b/tests/output/test_write_text_area/output_001.pdf index 5547e366e..300431d15 100644 Binary files a/tests/output/test_write_text_area/output_001.pdf and b/tests/output/test_write_text_area/output_001.pdf differ diff --git a/tests/output/test_write_text_area/output_002.pdf b/tests/output/test_write_text_area/output_002.pdf index 014fa0a07..e45182505 100644 Binary files a/tests/output/test_write_text_area/output_002.pdf and b/tests/output/test_write_text_area/output_002.pdf differ diff --git a/tests/output/test_write_text_field/output_001.pdf b/tests/output/test_write_text_field/output_001.pdf index b9769702c..e85666b18 100644 Binary files a/tests/output/test_write_text_field/output_001.pdf and b/tests/output/test_write_text_field/output_001.pdf differ diff --git a/tests/output/test_write_text_field/output_002.pdf b/tests/output/test_write_text_field/output_002.pdf index 50366dfb8..9ccd39aca 100644 Binary files a/tests/output/test_write_text_field/output_002.pdf and b/tests/output/test_write_text_field/output_002.pdf differ diff --git a/tests/output/test_write_unordered_list/output.pdf b/tests/output/test_write_unordered_list/output.pdf index 9315b869a..fec59676a 100644 Binary files a/tests/output/test_write_unordered_list/output.pdf and b/tests/output/test_write_unordered_list/output.pdf differ diff --git a/tests/output/test_write_using_low_level_instructions/output.pdf b/tests/output/test_write_using_low_level_instructions/output.pdf index 56f784826..46a7e5b02 100644 Binary files a/tests/output/test_write_using_low_level_instructions/output.pdf and b/tests/output/test_write_using_low_level_instructions/output.pdf differ diff --git a/tests/output/test_write_with_truetype_font/output_001.pdf b/tests/output/test_write_with_truetype_font/output_001.pdf index 66431bcb2..0b02a7679 100644 Binary files a/tests/output/test_write_with_truetype_font/output_001.pdf and b/tests/output/test_write_with_truetype_font/output_001.pdf differ diff --git a/tests/output/test_write_with_truetype_font/output_002.pdf b/tests/output/test_write_with_truetype_font/output_002.pdf index c16c69026..49827455c 100644 Binary files a/tests/output/test_write_with_truetype_font/output_002.pdf and b/tests/output/test_write_with_truetype_font/output_002.pdf differ diff --git a/tests/output/test_write_with_truetype_font/output_002.png b/tests/output/test_write_with_truetype_font/output_002.png index 076cde805..d801c17b1 100644 Binary files a/tests/output/test_write_with_truetype_font/output_002.png and b/tests/output/test_write_with_truetype_font/output_002.png differ diff --git a/tests/output/test_write_with_truetype_font/output_003.pdf b/tests/output/test_write_with_truetype_font/output_003.pdf index b06344cbd..1bd2dffbe 100644 Binary files a/tests/output/test_write_with_truetype_font/output_003.pdf and b/tests/output/test_write_with_truetype_font/output_003.pdf differ diff --git a/tests/output/test_write_with_truetype_font/output_004.pdf b/tests/output/test_write_with_truetype_font/output_004.pdf index f7be59f74..c60356d50 100644 Binary files a/tests/output/test_write_with_truetype_font/output_004.pdf and b/tests/output/test_write_with_truetype_font/output_004.pdf differ diff --git a/tests/output/test_write_xl_image/output.pdf b/tests/output/test_write_xl_image/output.pdf index 2c20716e3..a22781537 100644 Binary files a/tests/output/test_write_xl_image/output.pdf and b/tests/output/test_write_xl_image/output.pdf differ diff --git a/tests/pdf/canvas/color/test_analogous_color_scheme.py b/tests/pdf/canvas/color/test_analogous_color_scheme.py index ab6589451..aaa44ad97 100644 --- a/tests/pdf/canvas/color/test_analogous_color_scheme.py +++ b/tests/pdf/canvas/color/test_analogous_color_scheme.py @@ -7,13 +7,13 @@ from borb.pdf.canvas.color.color import HexColor, HSVColor, Color from borb.pdf.canvas.color.pantone import Pantone from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/color/test_extract_colors.py b/tests/pdf/canvas/color/test_extract_colors.py index 65a1dd59c..aa476a221 100644 --- a/tests/pdf/canvas/color/test_extract_colors.py +++ b/tests/pdf/canvas/color/test_extract_colors.py @@ -7,16 +7,16 @@ from borb.pdf.canvas.color.color import HexColor, RGBColor, X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle from borb.pdf.canvas.layout.image.image import Image -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.color.color_spectrum_extraction import ColorSpectrumExtraction diff --git a/tests/pdf/canvas/color/test_split_complementary_color_scheme.py b/tests/pdf/canvas/color/test_split_complementary_color_scheme.py index fb8e2cda5..d9d118d4c 100644 --- a/tests/pdf/canvas/color/test_split_complementary_color_scheme.py +++ b/tests/pdf/canvas/color/test_split_complementary_color_scheme.py @@ -7,13 +7,13 @@ from borb.pdf.canvas.color.color import HexColor, HSVColor, Color from borb.pdf.canvas.color.pantone import Pantone from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/color/test_tetradic_rectangle_color_scheme.py b/tests/pdf/canvas/color/test_tetradic_rectangle_color_scheme.py index bf19759ad..26cd63570 100644 --- a/tests/pdf/canvas/color/test_tetradic_rectangle_color_scheme.py +++ b/tests/pdf/canvas/color/test_tetradic_rectangle_color_scheme.py @@ -7,13 +7,13 @@ from borb.pdf.canvas.color.color import HexColor, HSVColor, Color from borb.pdf.canvas.color.pantone import Pantone from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/color/test_tetradic_square_color_scheme.py b/tests/pdf/canvas/color/test_tetradic_square_color_scheme.py index 4fc9c4f48..0bc3737b3 100644 --- a/tests/pdf/canvas/color/test_tetradic_square_color_scheme.py +++ b/tests/pdf/canvas/color/test_tetradic_square_color_scheme.py @@ -7,13 +7,13 @@ from borb.pdf.canvas.color.color import HexColor, HSVColor, Color from borb.pdf.canvas.color.pantone import Pantone from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/color/test_triadic_color_scheme.py b/tests/pdf/canvas/color/test_triadic_color_scheme.py index 92c427c3a..10290bbbd 100644 --- a/tests/pdf/canvas/color/test_triadic_color_scheme.py +++ b/tests/pdf/canvas/color/test_triadic_color_scheme.py @@ -7,13 +7,13 @@ from borb.pdf.canvas.color.color import HexColor, HSVColor, Color from borb.pdf.canvas.color.pantone import Pantone from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/font/test_digit_placement_ubuntu_font.py b/tests/pdf/canvas/font/test_digit_placement_ubuntu_font.py index e02339881..a7e497320 100644 --- a/tests/pdf/canvas/font/test_digit_placement_ubuntu_font.py +++ b/tests/pdf/canvas/font/test_digit_placement_ubuntu_font.py @@ -8,7 +8,7 @@ from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/font/test_extract_font_names.py b/tests/pdf/canvas/font/test_extract_font_names.py index 41f9ee3c2..0f2b7f088 100644 --- a/tests/pdf/canvas/font/test_extract_font_names.py +++ b/tests/pdf/canvas/font/test_extract_font_names.py @@ -11,7 +11,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.font_extraction import FontExtraction diff --git a/tests/pdf/canvas/font/test_write_hello_world_with_monaco_font.py b/tests/pdf/canvas/font/test_write_hello_world_with_monaco_font.py index d395dc927..79435abb5 100644 --- a/tests/pdf/canvas/font/test_write_hello_world_with_monaco_font.py +++ b/tests/pdf/canvas/font/test_write_hello_world_with_monaco_font.py @@ -6,7 +6,7 @@ from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/font/test_write_hello_world_with_simhei_font.py b/tests/pdf/canvas/font/test_write_hello_world_with_simhei_font.py index 32bca97a5..39a04929e 100644 --- a/tests/pdf/canvas/font/test_write_hello_world_with_simhei_font.py +++ b/tests/pdf/canvas/font/test_write_hello_world_with_simhei_font.py @@ -6,7 +6,7 @@ from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/font/test_write_with_truetype_font.py b/tests/pdf/canvas/font/test_write_with_truetype_font.py index f56325429..ded97d5ad 100644 --- a/tests/pdf/canvas/font/test_write_with_truetype_font.py +++ b/tests/pdf/canvas/font/test_write_with_truetype_font.py @@ -5,14 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth @@ -74,9 +74,8 @@ def test_write_document_004(self): layout.add(p) # add box - page.append_polygon_annotation( - LineArtFactory.rectangle(p.get_bounding_box()), - stroke_color=HexColor("ff0000"), + page.append_annotation( + SquareAnnotation(p.get_bounding_box(), stroke_color=HexColor("ff0000")) ) # determine output location diff --git a/tests/pdf/canvas/layout/barcode/test_write_all_types_of_barcode.py b/tests/pdf/canvas/layout/barcode/test_write_all_types_of_barcode.py index a13c02f6a..6f4bdc4ba 100644 --- a/tests/pdf/canvas/layout/barcode/test_write_all_types_of_barcode.py +++ b/tests/pdf/canvas/layout/barcode/test_write_all_types_of_barcode.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode.py b/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode.py index cc39f3a51..e18fdeaa8 100644 --- a/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode.py +++ b/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode_in_color.py b/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode_in_color.py index b6591e1d2..37ee40ce4 100644 --- a/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode_in_color.py +++ b/tests/pdf/canvas/layout/barcode/test_write_code_128_barcode_in_color.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/chart/test_write_2_scatter_plots.py b/tests/pdf/canvas/layout/chart/test_write_2_scatter_plots.py index a980a52e0..231102a5a 100644 --- a/tests/pdf/canvas/layout/chart/test_write_2_scatter_plots.py +++ b/tests/pdf/canvas/layout/chart/test_write_2_scatter_plots.py @@ -12,7 +12,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/chart/test_write_3d_density_chart.py b/tests/pdf/canvas/layout/chart/test_write_3d_density_chart.py index 95c041a39..5029a910a 100644 --- a/tests/pdf/canvas/layout/chart/test_write_3d_density_chart.py +++ b/tests/pdf/canvas/layout/chart/test_write_3d_density_chart.py @@ -14,7 +14,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/chart/test_write_3d_surface_plot.py b/tests/pdf/canvas/layout/chart/test_write_3d_surface_plot.py index 09722b477..fd4d120b4 100644 --- a/tests/pdf/canvas/layout/chart/test_write_3d_surface_plot.py +++ b/tests/pdf/canvas/layout/chart/test_write_3d_surface_plot.py @@ -13,7 +13,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/chart/test_write_radar_plot.py b/tests/pdf/canvas/layout/chart/test_write_radar_plot.py index 421f35107..c4a02db63 100644 --- a/tests/pdf/canvas/layout/chart/test_write_radar_plot.py +++ b/tests/pdf/canvas/layout/chart/test_write_radar_plot.py @@ -14,7 +14,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text.py b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text.py index 5ba55ab34..a5ce57907 100644 --- a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text.py +++ b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text.py @@ -10,7 +10,7 @@ ) from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_escaped_chars.py b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_escaped_chars.py index 369a74d80..879b2e226 100644 --- a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_escaped_chars.py +++ b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_escaped_chars.py @@ -10,7 +10,7 @@ ) from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_in_rainbow_colors.py b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_in_rainbow_colors.py index f72bebe23..0b23c5c6a 100644 --- a/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_in_rainbow_colors.py +++ b/tests/pdf/canvas/layout/chunk_of_text/test_write_chunk_of_text_in_rainbow_colors.py @@ -11,7 +11,7 @@ ) from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/chunk_of_text/test_write_paragraph_with_accented_letters.py b/tests/pdf/canvas/layout/chunk_of_text/test_write_paragraph_with_accented_letters.py index 57b43c7c9..1c6058213 100644 --- a/tests/pdf/canvas/layout/chunk_of_text/test_write_paragraph_with_accented_letters.py +++ b/tests/pdf/canvas/layout/chunk_of_text/test_write_paragraph_with_accented_letters.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.simple_text_extraction import SimpleTextExtraction diff --git a/tests/pdf/canvas/layout/chunk_of_text/test_write_using_low_level_instructions.py b/tests/pdf/canvas/layout/chunk_of_text/test_write_using_low_level_instructions.py index e812d3243..2e5aac2e2 100644 --- a/tests/pdf/canvas/layout/chunk_of_text/test_write_using_low_level_instructions.py +++ b/tests/pdf/canvas/layout/chunk_of_text/test_write_using_low_level_instructions.py @@ -11,7 +11,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text.py b/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text.py index bb1eae97b..a69834c35 100644 --- a/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text.py +++ b/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text.py @@ -6,6 +6,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor, Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( @@ -14,7 +15,7 @@ from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.chunks_of_text import HeterogeneousParagraph from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth @@ -90,10 +91,7 @@ def test_write_document_001(self): HeterogeneousParagraph(chunks_of_text).layout(page, bb) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output_001.pdf" @@ -160,10 +158,7 @@ def test_write_document_002(self): ).layout(page, bb) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output_002.pdf" @@ -230,10 +225,7 @@ def test_write_document_003(self): ).layout(page, bb) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output_003.pdf" @@ -304,10 +296,7 @@ def test_write_document_004(self): ).layout(page, bb) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output_004.pdf" @@ -379,10 +368,7 @@ def test_write_document_005(self): ).layout(page, bb) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output_005.pdf" diff --git a/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text_preserves_bounding_boxes.py b/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text_preserves_bounding_boxes.py index cd52da470..919f56b2e 100644 --- a/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text_preserves_bounding_boxes.py +++ b/tests/pdf/canvas/layout/chunks_of_text/test_write_chunks_of_text_preserves_bounding_boxes.py @@ -7,6 +7,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor, Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, @@ -14,7 +15,7 @@ from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.chunks_of_text import HeterogeneousParagraph from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth @@ -85,10 +86,12 @@ def test_write_document(self): for i, c in enumerate(chunks_of_text): r: Rectangle = copy.deepcopy(chunks_of_text[i].get_bounding_box()) r.y -= (i + 1) * Decimal(10) - page.append_square_annotation( - stroke_color=colors[i], - fill_color=colors[i], - rectangle=r, + page.append_annotation( + SquareAnnotation( + stroke_color=colors[i], + fill_color=colors[i], + bounding_box=r, + ) ) # determine output location diff --git a/tests/pdf/canvas/layout/codeblock/test_write_codeblock.py b/tests/pdf/canvas/layout/codeblock/test_write_codeblock.py index 671ae8373..04f84d2f2 100644 --- a/tests/pdf/canvas/layout/codeblock/test_write_codeblock.py +++ b/tests/pdf/canvas/layout/codeblock/test_write_codeblock.py @@ -9,7 +9,7 @@ ) from borb.pdf.canvas.layout.text.codeblock import CodeBlock from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/emoji/test_write_emoji.py b/tests/pdf/canvas/layout/emoji/test_write_emoji.py index f6178be04..fd6b28ea2 100644 --- a/tests/pdf/canvas/layout/emoji/test_write_emoji.py +++ b/tests/pdf/canvas/layout/emoji/test_write_emoji.py @@ -10,7 +10,7 @@ ) from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/forms/test_write_check_box.py b/tests/pdf/canvas/layout/forms/test_write_check_box.py index 95f467ca2..e53116c80 100644 --- a/tests/pdf/canvas/layout/forms/test_write_check_box.py +++ b/tests/pdf/canvas/layout/forms/test_write_check_box.py @@ -13,7 +13,7 @@ FixedColumnWidthTable, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/forms/test_write_drop_down_list.py b/tests/pdf/canvas/layout/forms/test_write_drop_down_list.py index e2c66e1e3..caac56ffd 100644 --- a/tests/pdf/canvas/layout/forms/test_write_drop_down_list.py +++ b/tests/pdf/canvas/layout/forms/test_write_drop_down_list.py @@ -13,7 +13,7 @@ FixedColumnWidthTable, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/forms/test_write_push_button.py b/tests/pdf/canvas/layout/forms/test_write_push_button.py new file mode 100644 index 000000000..0815bac43 --- /dev/null +++ b/tests/pdf/canvas/layout/forms/test_write_push_button.py @@ -0,0 +1,134 @@ +import typing +import unittest +from datetime import datetime +from decimal import Decimal +from pathlib import Path + +from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.forms.push_button import PushButton +from borb.pdf.canvas.layout.forms.text_area import TextArea +from borb.pdf.canvas.layout.forms.text_field import TextField +from borb.pdf.canvas.layout.layout_element import Alignment +from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.table.fixed_column_width_table import ( + FixedColumnWidthTable as Table, + FixedColumnWidthTable, +) +from borb.pdf.canvas.layout.text.paragraph import Paragraph +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page +from borb.pdf.pdf import PDF + + +class TestWritePushButton(unittest.TestCase): + """ + This test attempts to extract the text of each PDF in the corpus + """ + + def __init__(self, methodName="runTest"): + super().__init__(methodName) + # find output dir + p: Path = Path(__file__).parent + while "output" not in [x.stem for x in p.iterdir() if x.is_dir()]: + p = p.parent + p = p / "output" + self.output_dir = Path(p, Path(__file__).stem.replace(".py", "")) + if not self.output_dir.exists(): + self.output_dir.mkdir() + + def test_write_push_button_at_absolute_position(self): + + # create empty document + pdf: Document = Document() + + # create empty page + page: Page = Page() + + # add page to document + pdf.append_page(page) + + # add test information + layout = SingleColumnLayout(page) + layout.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add(Paragraph("This test creates a PDF with a PushButton in it.")) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + # write TextField + tf: PushButton = PushButton("Click Me!") + tf.layout( + page, Rectangle(Decimal(59), Decimal(600), Decimal(476), Decimal(12.5 * 5)) + ) + + # write + file = self.output_dir / "output_001.pdf" + with open(file, "wb") as pdf_file_handle: + PDF.dumps(pdf_file_handle, pdf) + + def test_write_push_button_using_layout_manager(self): + + # create empty document + pdf: Document = Document() + + # create empty page + page: Page = Page() + + # add page to document + pdf.append_page(page) + + # layout manager + l: PageLayout = SingleColumnLayout(page) + + # write test info + l.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add(Paragraph("This test creates a PDF with a few TextField objects and a TextArea in it.")) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + # write TextField + l.add( + FixedColumnWidthTable( + number_of_rows=4, number_of_columns=2, margin_top=Decimal(20) + ) + .add(Paragraph("Name:")) + .add(TextField(value="Doe", font_color=HexColor("56cbf9"), font_size=Decimal(20))) + .add(Paragraph("Firstname:")) + .add(TextField(value="John", font_color=HexColor("56cbf9"), font_size=Decimal(20))) + .add(Paragraph("Place of residence:")) + .add(TextArea(field_name="place_of_residence")) + .add(Paragraph(" ")) + .add(PushButton("Submit!", horizontal_alignment=Alignment.RIGHT)) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + # write + file = self.output_dir / "output_002.pdf" + with open(file, "wb") as pdf_file_handle: + PDF.dumps(pdf_file_handle, pdf) + + def test_check_acroform_present(self): + + doc: typing.Optional[Document] = None + with open(self.output_dir / "output_002.pdf", "rb") as pdf_file_handle: + doc = PDF.loads(pdf_file_handle) + + assert doc is not None + assert doc.get_page(0).has_acroforms() + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/pdf/canvas/layout/forms/test_write_text_area.py b/tests/pdf/canvas/layout/forms/test_write_text_area.py index a1bae556a..230844524 100644 --- a/tests/pdf/canvas/layout/forms/test_write_text_area.py +++ b/tests/pdf/canvas/layout/forms/test_write_text_area.py @@ -15,7 +15,7 @@ FixedColumnWidthTable, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/forms/test_write_text_field.py b/tests/pdf/canvas/layout/forms/test_write_text_field.py index db6d78d99..f71a467b3 100644 --- a/tests/pdf/canvas/layout/forms/test_write_text_field.py +++ b/tests/pdf/canvas/layout/forms/test_write_text_field.py @@ -14,7 +14,7 @@ FixedColumnWidthTable, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/heading/test_write_paragraphs_with_headings.py b/tests/pdf/canvas/layout/heading/test_write_paragraphs_with_headings.py index f036de49f..6b6c27b2a 100644 --- a/tests/pdf/canvas/layout/heading/test_write_paragraphs_with_headings.py +++ b/tests/pdf/canvas/layout/heading/test_write_paragraphs_with_headings.py @@ -15,7 +15,7 @@ ) from borb.pdf.canvas.layout.text.heading import Heading from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/hyphenation/test_write_hyphenated_paragraph.py b/tests/pdf/canvas/layout/hyphenation/test_write_hyphenated_paragraph.py index e6ce38f8a..ff2b224c3 100644 --- a/tests/pdf/canvas/layout/hyphenation/test_write_hyphenated_paragraph.py +++ b/tests/pdf/canvas/layout/hyphenation/test_write_hyphenated_paragraph.py @@ -14,7 +14,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_modify_image.py b/tests/pdf/canvas/layout/image/test_modify_image.py index 313494bf9..1b322a293 100644 --- a/tests/pdf/canvas/layout/image/test_modify_image.py +++ b/tests/pdf/canvas/layout/image/test_modify_image.py @@ -12,7 +12,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_write_grayscale_image.py b/tests/pdf/canvas/layout/image/test_write_grayscale_image.py index 2da97c842..3b3a4e33c 100644 --- a/tests/pdf/canvas/layout/image/test_write_grayscale_image.py +++ b/tests/pdf/canvas/layout/image/test_write_grayscale_image.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_write_image_aligned_center.py b/tests/pdf/canvas/layout/image/test_write_image_aligned_center.py index 3e61a4d8b..898f0ac7c 100644 --- a/tests/pdf/canvas/layout/image/test_write_image_aligned_center.py +++ b/tests/pdf/canvas/layout/image/test_write_image_aligned_center.py @@ -13,7 +13,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_write_image_by_url.py b/tests/pdf/canvas/layout/image/test_write_image_by_url.py index 154c57c0d..8786beccc 100644 --- a/tests/pdf/canvas/layout/image/test_write_image_by_url.py +++ b/tests/pdf/canvas/layout/image/test_write_image_by_url.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/image/test_write_pil_image.py b/tests/pdf/canvas/layout/image/test_write_pil_image.py index 0fc958780..a9aac52ea 100644 --- a/tests/pdf/canvas/layout/image/test_write_pil_image.py +++ b/tests/pdf/canvas/layout/image/test_write_pil_image.py @@ -13,7 +13,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_write_png_image_by_url.py b/tests/pdf/canvas/layout/image/test_write_png_image_by_url.py index e8cfc4569..746fcaab0 100644 --- a/tests/pdf/canvas/layout/image/test_write_png_image_by_url.py +++ b/tests/pdf/canvas/layout/image/test_write_png_image_by_url.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/image/test_write_xl_image.py b/tests/pdf/canvas/layout/image/test_write_xl_image.py index 1afc8b7fc..e2617c4a6 100644 --- a/tests/pdf/canvas/layout/image/test_write_xl_image.py +++ b/tests/pdf/canvas/layout/image/test_write_xl_image.py @@ -11,7 +11,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/line_art/test_write_blobs.py b/tests/pdf/canvas/layout/line_art/test_write_blobs.py index 4947c4e96..d17125ff1 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_blobs.py +++ b/tests/pdf/canvas/layout/line_art/test_write_blobs.py @@ -4,16 +4,16 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.blob_factory import BlobFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/line_art/test_write_dragon_curve.py b/tests/pdf/canvas/layout/line_art/test_write_dragon_curve.py index c2caac922..adc115480 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_dragon_curve.py +++ b/tests/pdf/canvas/layout/line_art/test_write_dragon_curve.py @@ -5,15 +5,15 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_art/test_write_flowchart_line_art.py b/tests/pdf/canvas/layout/line_art/test_write_flowchart_line_art.py index e70d672d1..11db4679a 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_flowchart_line_art.py +++ b/tests/pdf/canvas/layout/line_art/test_write_flowchart_line_art.py @@ -5,15 +5,15 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor, X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_art/test_write_flyer.py b/tests/pdf/canvas/layout/line_art/test_write_flyer.py index cdbc759ff..c6524d203 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_flyer.py +++ b/tests/pdf/canvas/layout/line_art/test_write_flyer.py @@ -5,13 +5,16 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.remote_go_to_annotation import ( + RemoteGoToAnnotation, +) from borb.pdf.canvas.layout.image.barcode import Barcode, BarcodeType from borb.pdf.canvas.layout.image.image import Image -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import LayoutElement, Alignment from borb.pdf.canvas.layout.list.unordered_list import UnorderedList from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.table.flexible_column_width_table import ( FlexibleColumnWidthTable, @@ -19,7 +22,7 @@ from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.page.page_size import PageSize from borb.pdf.pdf import PDF @@ -175,8 +178,10 @@ def test_create_flyer(self): ) .no_borders() ) - page.append_remote_go_to_annotation( - qr_code.get_bounding_box(), uri="https://www.borbpdf.com" + page.append_annotation( + RemoteGoToAnnotation( + qr_code.get_bounding_box(), uri="https://www.borbpdf.com" + ) ) # title diff --git a/tests/pdf/canvas/layout/line_art/test_write_gradient_rectangular_maze.py b/tests/pdf/canvas/layout/line_art/test_write_gradient_rectangular_maze.py index 5cf109b50..3e05c6a7f 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_gradient_rectangular_maze.py +++ b/tests/pdf/canvas/layout/line_art/test_write_gradient_rectangular_maze.py @@ -5,9 +5,9 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor -from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.shape.gradient_colored_disjoint_shape import ( GradientColoredDisjointShape, ) @@ -16,7 +16,7 @@ ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.rectangular_maze_factory import RectangularMazeFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_art/test_write_lissajours_line_art.py b/tests/pdf/canvas/layout/line_art/test_write_lissajours_line_art.py index 52f362847..c47dca581 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_lissajours_line_art.py +++ b/tests/pdf/canvas/layout/line_art/test_write_lissajours_line_art.py @@ -5,15 +5,15 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle -from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_art/test_write_rectangular_hitomezashi.py b/tests/pdf/canvas/layout/line_art/test_write_rectangular_hitomezashi.py index a404a3db0..cee7b75d1 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_rectangular_hitomezashi.py +++ b/tests/pdf/canvas/layout/line_art/test_write_rectangular_hitomezashi.py @@ -1,20 +1,18 @@ -import random import unittest from datetime import datetime from pathlib import Path from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor -from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.rectangular_hitomezashi import RectangularHitomezashi -from borb.pdf.canvas.line_art.rectangular_maze_factory import RectangularMazeFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_art/test_write_rectangular_maze.py b/tests/pdf/canvas/layout/line_art/test_write_rectangular_maze.py index 928e92271..741d132b7 100644 --- a/tests/pdf/canvas/layout/line_art/test_write_rectangular_maze.py +++ b/tests/pdf/canvas/layout/line_art/test_write_rectangular_maze.py @@ -5,15 +5,15 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor -from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.shape.disjoint_shape import DisjointShape from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.rectangular_maze_factory import RectangularMazeFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_center.py b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_center.py index 93169ac53..f165ca1b8 100644 --- a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_center.py +++ b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_center.py @@ -5,6 +5,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( @@ -12,7 +13,7 @@ ) from borb.pdf.canvas.layout.text.line_of_text import LineOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -82,11 +83,13 @@ def test_write_document(self): rs.append(r) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=Rectangle( - Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) - ), + page.append_annotation( + SquareAnnotation( + stroke_color=HexColor("f1cd2e"), + bounding_box=Rectangle( + Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) + ), + ) ) # determine output location diff --git a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_full.py b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_full.py index e4f9d9cb8..a26e5a1fc 100644 --- a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_full.py +++ b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_full.py @@ -5,6 +5,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( @@ -12,7 +13,7 @@ ) from borb.pdf.canvas.layout.text.line_of_text import LineOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -82,11 +83,13 @@ def test_write_document(self): rs.append(r) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=Rectangle( - Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) - ), + page.append_annotation( + SquareAnnotation( + stroke_color=HexColor("f1cd2e"), + bounding_box=Rectangle( + Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) + ), + ) ) # determine output location diff --git a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_right.py b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_right.py index 311edbb95..09e5f4127 100644 --- a/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_right.py +++ b/tests/pdf/canvas/layout/line_of_text/test_write_line_of_text_justified_right.py @@ -3,8 +3,9 @@ from pathlib import Path from borb.io.read.types import Decimal -from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.color.color import HexColor, X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( @@ -12,7 +13,7 @@ ) from borb.pdf.canvas.layout.text.line_of_text import LineOfText from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -78,15 +79,72 @@ def test_write_document(self): rs.append(r) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=Rectangle( - Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) - ), + page.append_annotation( + SquareAnnotation( + Rectangle( + Decimal(59), Decimal(550 - 24 * 4), Decimal(476), Decimal(24 * 5) + ), + stroke_color=HexColor("f1cd2e"), + ) ) # determine output location - out_file = self.output_dir / "output.pdf" + out_file = self.output_dir / "output_001.pdf" + + # attempt to store PDF + with open(out_file, "wb") as in_file_handle: + PDF.dumps(in_file_handle, pdf) + + def test_write_single_line_of_text_with_annotation(self): + + # create document + pdf = Document() + + # add page + page = Page() + pdf.append_page(page) + + # add test information + layout = SingleColumnLayout(page) + layout.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add( + Paragraph( + "This test creates a PDF with a single LineOfText object in it, horizontal alignment set to RIGHT." + ) + ) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + # Rectangle + rect: Rectangle = Rectangle(Decimal(59), Decimal(550 - 24), Decimal(476), Decimal(24)) + + # Shape + page.append_annotation(SquareAnnotation(rect, stroke_color=HexColor("000000"))) + + # LineOfText + LineOfText( + "Lorem Ipsum Dolor Sit Amet", + font_size=Decimal(10), + background_color=X11Color("Gray"), + border_color=X11Color("Black"), + border_top=True, + border_right=True, + border_bottom=True, + border_left=True, + horizontal_alignment=Alignment.RIGHT, + ).layout( + page, + rect, + ) + + # determine output location + out_file = self.output_dir / "output_002.pdf" # attempt to store PDF with open(out_file, "wb") as in_file_handle: diff --git a/tests/pdf/canvas/layout/list/test_write_long_unordered_list.py b/tests/pdf/canvas/layout/list/test_write_long_unordered_list.py index 5c3e40629..a26dedbe1 100644 --- a/tests/pdf/canvas/layout/list/test_write_long_unordered_list.py +++ b/tests/pdf/canvas/layout/list/test_write_long_unordered_list.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/list/test_write_nested_ordered_list.py b/tests/pdf/canvas/layout/list/test_write_nested_ordered_list.py index 9d7c97e13..0ab85c779 100644 --- a/tests/pdf/canvas/layout/list/test_write_nested_ordered_list.py +++ b/tests/pdf/canvas/layout/list/test_write_nested_ordered_list.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/list/test_write_nested_unordered_list.py b/tests/pdf/canvas/layout/list/test_write_nested_unordered_list.py index 99965b66b..e521cc619 100644 --- a/tests/pdf/canvas/layout/list/test_write_nested_unordered_list.py +++ b/tests/pdf/canvas/layout/list/test_write_nested_unordered_list.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/list/test_write_ordered_list.py b/tests/pdf/canvas/layout/list/test_write_ordered_list.py index 4b021b943..7cbd03eaf 100644 --- a/tests/pdf/canvas/layout/list/test_write_ordered_list.py +++ b/tests/pdf/canvas/layout/list/test_write_ordered_list.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/list/test_write_unordered_list.py b/tests/pdf/canvas/layout/list/test_write_unordered_list.py index 34d8d7cd0..492f71b2c 100644 --- a/tests/pdf/canvas/layout/list/test_write_unordered_list.py +++ b/tests/pdf/canvas/layout/list/test_write_unordered_list.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/page_layout/test_browser_layout_inline_next_line.py b/tests/pdf/canvas/layout/page_layout/test_browser_layout_inline_next_line.py index 8251f63c7..44dd13d85 100644 --- a/tests/pdf/canvas/layout/page_layout/test_browser_layout_inline_next_line.py +++ b/tests/pdf/canvas/layout/page_layout/test_browser_layout_inline_next_line.py @@ -3,7 +3,7 @@ from borb.pdf.canvas.layout.page_layout.browser_layout import BrowserLayout from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/page_layout/test_margin_and_padding.py b/tests/pdf/canvas/layout/page_layout/test_margin_and_padding.py index bdba91ae3..5e8facd25 100644 --- a/tests/pdf/canvas/layout/page_layout/test_margin_and_padding.py +++ b/tests/pdf/canvas/layout/page_layout/test_margin_and_padding.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/page_layout/test_write_multiple_pages.py b/tests/pdf/canvas/layout/page_layout/test_write_multiple_pages.py index 09e1ded46..8d159693d 100644 --- a/tests/pdf/canvas/layout/page_layout/test_write_multiple_pages.py +++ b/tests/pdf/canvas/layout/page_layout/test_write_multiple_pages.py @@ -8,7 +8,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_multi_column_layout.py b/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_multi_column_layout.py index 034e868cb..f8fb6f8eb 100644 --- a/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_multi_column_layout.py +++ b/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_multi_column_layout.py @@ -12,7 +12,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_single_column_layout.py b/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_single_column_layout.py index cc32bfc76..c7bd1739c 100644 --- a/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_single_column_layout.py +++ b/tests/pdf/canvas/layout/page_layout/test_write_paragraphs_using_single_column_layout.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/paragraph/test_hello_world.py b/tests/pdf/canvas/layout/paragraph/test_hello_world.py index 41bf38cc3..1e998209b 100644 --- a/tests/pdf/canvas/layout/paragraph/test_hello_world.py +++ b/tests/pdf/canvas/layout/paragraph/test_hello_world.py @@ -2,7 +2,7 @@ from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph.py index ce12abd11..f57caf78d 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph.py @@ -5,6 +5,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout @@ -12,7 +13,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -81,10 +82,7 @@ def test_write_document(self): ) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, - ) + page.append_annotation(SquareAnnotation(bb, stroke_color=HexColor("f1cd2e"))) # determine output location out_file = self.output_dir / "output.pdf" diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_alignment.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_alignment.py index 2c77ef68a..ea758925e 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_alignment.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_alignment.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -104,9 +105,8 @@ def test_write_document(self): ) # add rectangle annotation - page.append_square_annotation( - stroke_color=HexColor("f1cd2e"), - rectangle=bb, + page.append_annotation( + SquareAnnotation(bb, stroke_color=HexColor("f1cd2e")) ) # determine output location diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_border_left.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_border_left.py index cfb68d74a..ca1b79571 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_border_left.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_border_left.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_force_split.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_force_split.py index 16ac57cfb..6a9868f23 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_force_split.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_force_split.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center.py index 5555a44e1..1546882e5 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -69,7 +70,7 @@ def test_write_document_001(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) @@ -132,7 +133,7 @@ def test_write_document_002(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding.py index d3a56eccb..1983088ef 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -89,7 +90,7 @@ def test_write_document(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border.py index dd62e74fb..5a38f892d 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -97,7 +98,7 @@ def test_write_document(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border_and_background.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border_and_background.py index 740f17bd9..62765fc1d 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border_and_background.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_center_with_padding_and_border_and_background.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -94,7 +95,7 @@ def test_write_document(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_full.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_full.py index d8cf2fc14..6c6ab2b9b 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_full.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_full.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -85,7 +86,7 @@ def test_write_document(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_right.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_right.py index 55cad0789..cea588dc7 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_right.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_justified_right.py @@ -5,13 +5,14 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -85,7 +86,7 @@ def test_write_document(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_preserve_space.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_preserve_space.py index ce4b32902..0053c4b08 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_preserve_space.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_preserve_space.py @@ -8,7 +8,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_save_twice.py b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_save_twice.py index 7824943aa..275ceac54 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_paragraph_save_twice.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_paragraph_save_twice.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/paragraph/test_write_single_line_justified_full.py b/tests/pdf/canvas/layout/paragraph/test_write_single_line_justified_full.py index ac8a21847..0695e3e77 100644 --- a/tests/pdf/canvas/layout/paragraph/test_write_single_line_justified_full.py +++ b/tests/pdf/canvas/layout/paragraph/test_write_single_line_justified_full.py @@ -5,6 +5,7 @@ from borb.io.read.types import Decimal from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import ( SingleColumnLayout, @@ -15,7 +16,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.page.page_size import PageSize from borb.pdf.pdf import PDF @@ -75,7 +76,7 @@ def test_write_document_001(self): # fmt: on # this is a quick and dirty way to draw a rectangle on the page - page.append_square_annotation(r, stroke_color=HexColor("f1cd2e")) + page.append_annotation(SquareAnnotation(r, stroke_color=HexColor("f1cd2e"))) # add the paragraph to the page p.layout(page, r) diff --git a/tests/pdf/canvas/layout/table/test_write_battleship.py b/tests/pdf/canvas/layout/table/test_write_battleship.py index 37503e399..7bf5db1ab 100644 --- a/tests/pdf/canvas/layout/table/test_write_battleship.py +++ b/tests/pdf/canvas/layout/table/test_write_battleship.py @@ -15,7 +15,7 @@ from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.heading import Heading from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_fixed_column_width_table.py b/tests/pdf/canvas/layout/table/test_write_fixed_column_width_table.py index 6ca91beaa..9a663fe1a 100644 --- a/tests/pdf/canvas/layout/table/test_write_fixed_column_width_table.py +++ b/tests/pdf/canvas/layout/table/test_write_fixed_column_width_table.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_flexi_table.py b/tests/pdf/canvas/layout/table/test_write_flexi_table.py index ea875812c..c830de248 100644 --- a/tests/pdf/canvas/layout/table/test_write_flexi_table.py +++ b/tests/pdf/canvas/layout/table/test_write_flexi_table.py @@ -13,7 +13,7 @@ FlexibleColumnWidthTable, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_flexi_table_with_preferred_width.py b/tests/pdf/canvas/layout/table/test_write_flexi_table_with_preferred_width.py index 37cc5d913..ba2e3cf3c 100644 --- a/tests/pdf/canvas/layout/table/test_write_flexi_table_with_preferred_width.py +++ b/tests/pdf/canvas/layout/table/test_write_flexi_table_with_preferred_width.py @@ -13,7 +13,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_incomplete_table.py b/tests/pdf/canvas/layout/table/test_write_incomplete_table.py index f7eb2383d..b35807f36 100644 --- a/tests/pdf/canvas/layout/table/test_write_incomplete_table.py +++ b/tests/pdf/canvas/layout/table/test_write_incomplete_table.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_col_span.py b/tests/pdf/canvas/layout/table/test_write_table_with_col_span.py index 418cd3db6..c78c8dfdc 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_col_span.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_col_span.py @@ -10,7 +10,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_image.py b/tests/pdf/canvas/layout/table/test_write_table_with_image.py index a0a4042d4..253e15499 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_image.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_image.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_non_black_paragraphs.py b/tests/pdf/canvas/layout/table/test_write_table_with_non_black_paragraphs.py index 97a24b243..58d311f74 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_non_black_paragraphs.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_non_black_paragraphs.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Alignment, Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_rainbow_background.py b/tests/pdf/canvas/layout/table/test_write_table_with_rainbow_background.py index df3abda3b..7190d7555 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_rainbow_background.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_rainbow_background.py @@ -11,7 +11,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_row_span.py b/tests/pdf/canvas/layout/table/test_write_table_with_row_span.py index 53e5e7894..d1c5b51f2 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_row_span.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_row_span.py @@ -10,7 +10,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/layout/table/test_write_table_with_special_characters.py b/tests/pdf/canvas/layout/table/test_write_table_with_special_characters.py index 073b5ece0..c09afc523 100644 --- a/tests/pdf/canvas/layout/table/test_write_table_with_special_characters.py +++ b/tests/pdf/canvas/layout/table/test_write_table_with_special_characters.py @@ -12,7 +12,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/canvas/layout/table/test_write_tents_and_trees.py b/tests/pdf/canvas/layout/table/test_write_tents_and_trees.py index 264cbedc3..64985ba79 100644 --- a/tests/pdf/canvas/layout/table/test_write_tents_and_trees.py +++ b/tests/pdf/canvas/layout/table/test_write_tents_and_trees.py @@ -18,7 +18,7 @@ ) from borb.pdf.canvas.layout.table.table import TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/canvas/test_write_empty_document.py b/tests/pdf/canvas/test_write_empty_document.py index 6ff57e5e8..e289458b7 100644 --- a/tests/pdf/canvas/test_write_empty_document.py +++ b/tests/pdf/canvas/test_write_empty_document.py @@ -1,7 +1,7 @@ import unittest from pathlib import Path -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/conformance/test_write_pdf_a_1b.py b/tests/pdf/conformance/test_write_pdf_a_1b.py index 4a0b71cdc..72405bdc1 100644 --- a/tests/pdf/conformance/test_write_pdf_a_1b.py +++ b/tests/pdf/conformance/test_write_pdf_a_1b.py @@ -6,7 +6,7 @@ from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/document/concat/test_concat_documents.py b/tests/pdf/document/concat/test_concat_documents.py index c2cf4be5f..073b10d24 100644 --- a/tests/pdf/document/concat/test_concat_documents.py +++ b/tests/pdf/document/concat/test_concat_documents.py @@ -8,7 +8,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/document/embedded_files/test_append_embedded_file.py b/tests/pdf/document/embedded_files/test_append_embedded_file.py index aa37aaedf..6c2b200b8 100644 --- a/tests/pdf/document/embedded_files/test_append_embedded_file.py +++ b/tests/pdf/document/embedded_files/test_append_embedded_file.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/document/outlines/test_add_outline.py b/tests/pdf/document/outlines/test_add_outline.py index 71af80134..ed8ab45b1 100644 --- a/tests/pdf/document/outlines/test_add_outline.py +++ b/tests/pdf/document/outlines/test_add_outline.py @@ -3,14 +3,15 @@ from decimal import Decimal from pathlib import Path +from borb.pdf.canvas.layout.annotation.link_annotation import DestinationType from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document -from borb.pdf.page.page import DestinationType, Page +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page from borb.pdf.pdf import PDF unittest.TestLoader.sortTestMethodsUsing = None diff --git a/tests/pdf/document/outputintent/test_create_document_with_output_intent.py b/tests/pdf/document/outputintent/test_create_document_with_output_intent.py index f6da49456..4dfe1c708 100644 --- a/tests/pdf/document/outputintent/test_create_document_with_output_intent.py +++ b/tests/pdf/document/outputintent/test_create_document_with_output_intent.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/pdf/document/test_add_large_amount_of_headings.py b/tests/pdf/document/test_add_large_amount_of_headings.py new file mode 100644 index 000000000..053319d40 --- /dev/null +++ b/tests/pdf/document/test_add_large_amount_of_headings.py @@ -0,0 +1,142 @@ +import sys +import unittest +from datetime import datetime +from decimal import Decimal +from pathlib import Path + +from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.table.fixed_column_width_table import ( + FixedColumnWidthTable as Table, +) +from borb.pdf.canvas.layout.text.heading import Heading +from borb.pdf.canvas.layout.text.paragraph import Paragraph +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page +from borb.pdf.pdf import PDF + +unittest.TestLoader.sortTestMethodsUsing = None + + +class TestAddLargeAmountOfHeadings(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + # find output dir + p: Path = Path(__file__).parent + while "output" not in [x.stem for x in p.iterdir() if x.is_dir()]: + p = p.parent + p = p / "output" + self.output_dir = Path(p, Path(__file__).stem.replace(".py", "")) + if not self.output_dir.exists(): + self.output_dir.mkdir() + + def test_write_document_001(self): + + # create document + pdf = Document() + + # add page + page = Page() + pdf.append_page(page) + + # add test information + layout = SingleColumnLayout(page) + layout.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add( + Paragraph( + "This test creates a PDF with 32 pages, each page containing 10 headings." + ) + ) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + sys.setrecursionlimit(1000) + N: int = 32 + for i in range(0, N): + # Create empty Page + page = Page() + + # Add Page to Document + pdf.append_page(page) + + # Create PageLayout + layout = SingleColumnLayout(page) + + # add heading + for j in range(0, 10): + layout.add( + Heading( + f"Page {i}, Heading {j}", + font_color=HexColor("13505B"), + font_size=Decimal(12), + ) + ) + + # determine output location + out_file = self.output_dir / "output_001.pdf" + + # attempt to store PDF + with self.assertRaises(RecursionError) as context: + with open(out_file, "wb") as in_file_handle: + PDF.dumps(in_file_handle, pdf) + + def test_write_document_002(self): + + # create document + pdf = Document() + + # add page + page = Page() + pdf.append_page(page) + + # add test information + layout = SingleColumnLayout(page) + layout.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add( + Paragraph( + "This test creates a PDF with 32 pages, each page containing 10 headings." + ) + ) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + sys.setrecursionlimit(2048) + N: int = 32 + for i in range(0, N): + # Create empty Page + page = Page() + + # Add Page to Document + pdf.append_page(page) + + # Create PageLayout + layout = SingleColumnLayout(page) + + # add heading + for j in range(0, 10): + layout.add( + Heading( + f"Page {i}, Heading {j}", + font_color=HexColor("13505B"), + font_size=Decimal(12), + ) + ) + + # determine output location + out_file = self.output_dir / "output_002.pdf" + + # attempt to store PDF + with open(out_file, "wb") as in_file_handle: + PDF.dumps(in_file_handle, pdf) diff --git a/tests/pdf/document/test_append_embedded_javascript.py b/tests/pdf/document/test_append_embedded_javascript.py new file mode 100644 index 000000000..8007cb3f5 --- /dev/null +++ b/tests/pdf/document/test_append_embedded_javascript.py @@ -0,0 +1,63 @@ +import unittest +from datetime import datetime +from decimal import Decimal +from pathlib import Path + +from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout +from borb.pdf.canvas.layout.table.fixed_column_width_table import ( + FixedColumnWidthTable as Table, +) +from borb.pdf.canvas.layout.text.paragraph import Paragraph +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page +from borb.pdf.pdf import PDF + +unittest.TestLoader.sortTestMethodsUsing = None + + +class TestAppendEmbeddedJavascript(unittest.TestCase): + def __init__(self, methodName="runTest"): + super().__init__(methodName) + # find output dir + p: Path = Path(__file__).parent + while "output" not in [x.stem for x in p.iterdir() if x.is_dir()]: + p = p.parent + p = p / "output" + self.output_dir = Path(p, Path(__file__).stem.replace(".py", "")) + if not self.output_dir.exists(): + self.output_dir.mkdir() + + def test_append_embedded_javascript(self): + + # create document + pdf = Document() + + # add page + page = Page() + pdf.append_page(page) + + # add test information + layout = SingleColumnLayout(page) + layout.add( + Table(number_of_columns=2, number_of_rows=3) + .add(Paragraph("Date", font="Helvetica-Bold")) + .add(Paragraph(datetime.now().strftime("%d/%m/%Y, %H:%M:%S"))) + .add(Paragraph("Test", font="Helvetica-Bold")) + .add(Paragraph(Path(__file__).stem)) + .add(Paragraph("Description", font="Helvetica-Bold")) + .add( + Paragraph( + "This test creates a PDF with 1 page and embedded Javascript." + ) + ) + .set_padding_on_all_cells(Decimal(2), Decimal(2), Decimal(2), Decimal(2)) + ) + + pdf.append_embedded_javascript("app.alert('Hello World!', 3)") + + # determine output location + out_file = self.output_dir / "output_001.pdf" + + # attempt to store PDF + with open(out_file, "wb") as in_file_handle: + PDF.dumps(in_file_handle, pdf) diff --git a/tests/pdf/document/test_remove_page.py b/tests/pdf/document/test_remove_page.py index 1599121e5..262507d48 100644 --- a/tests/pdf/document/test_remove_page.py +++ b/tests/pdf/document/test_remove_page.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/page/annotations/test_add_all_rubber_stamp_annotations.py b/tests/pdf/page/annotations/test_add_all_rubber_stamp_annotations.py index e1bc74a99..b7294b717 100644 --- a/tests/pdf/page/annotations/test_add_all_rubber_stamp_annotations.py +++ b/tests/pdf/page/annotations/test_add_all_rubber_stamp_annotations.py @@ -3,18 +3,21 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.rubber_stamp_annotation import ( + RubberStampAnnotation, + RubberStampAnnotationIconType, +) from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document -from borb.pdf.page.page import Page, RubberStampAnnotationIconType +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth class TestAddAllRubberStampAnnotations(unittest.TestCase): @@ -57,13 +60,18 @@ def test_all_add_rubber_stamp_annotations(self): # add annotation for index, name in enumerate(RubberStampAnnotationIconType): - pdf.get_page(0).append_stamp_annotation( - name=name, - contents="Approved by Joris Schellekens", - color=X11Color("White"), - rectangle=Rectangle( - Decimal(128), Decimal(128 + index * 34), Decimal(64), Decimal(32) - ), + pdf.get_page(0).append_annotation( + RubberStampAnnotation( + name=name, + contents="Approved by Joris Schellekens", + color=X11Color("White"), + bounding_box=Rectangle( + Decimal(128), + Decimal(128 + index * 34), + Decimal(64), + Decimal(32), + ), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_circle_annotation.py b/tests/pdf/page/annotations/test_add_circle_annotation.py index d782a4f22..f2e1034dc 100644 --- a/tests/pdf/page/annotations/test_add_circle_annotation.py +++ b/tests/pdf/page/annotations/test_add_circle_annotation.py @@ -3,18 +3,18 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.circle_annotation import CircleAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth class TestAddCircleAnnotation(unittest.TestCase): @@ -58,15 +58,17 @@ def test_add_circle_annotation(self): # add annotation w: Decimal = pdf.get_page(0).get_page_info().get_width() h: Decimal = pdf.get_page(0).get_page_info().get_height() - pdf.get_page(0).append_circle_annotation( - rectangle=Rectangle( - w / Decimal(2) - Decimal(32), - h / Decimal(2) - Decimal(32), - Decimal(64), - Decimal(64), - ), - stroke_color=HexColor("0B3954"), - fill_color=HexColor("f1cd2e"), + pdf.get_page(0).append_annotation( + CircleAnnotation( + bounding_box=Rectangle( + w / Decimal(2) - Decimal(32), + h / Decimal(2) - Decimal(32), + Decimal(64), + Decimal(64), + ), + stroke_color=HexColor("0B3954"), + fill_color=HexColor("f1cd2e"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_free_text_annotation.py b/tests/pdf/page/annotations/test_add_free_text_annotation.py index 142e49c2f..42f9cd0a2 100644 --- a/tests/pdf/page/annotations/test_add_free_text_annotation.py +++ b/tests/pdf/page/annotations/test_add_free_text_annotation.py @@ -3,23 +3,23 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.font.simple_font.font_type_1 import StandardType1Font from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.free_text_annotation import FreeTextAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( RegularExpressionTextExtraction, ) +from tests.test_util import compare_visually_to_ground_truth unittest.TestLoader.sortTestMethodsUsing = None @@ -93,12 +93,16 @@ def test_add_text_annotation(self): doc = PDF.loads(in_file_handle, [l]) bb = l.get_matches_for_page(0)[0].get_bounding_boxes()[0] - doc.get_page(0).append_free_text_annotation( - rectangle=Rectangle(Decimal(59), Decimal(500), Decimal(200), Decimal(100)), - font=StandardType1Font("Helvetica"), - font_size=Decimal(12), - text="""Lorem Ipsum""", - font_color=HexColor("F1CD2E"), + doc.get_page(0).append_annotation( + FreeTextAnnotation( + bounding_box=Rectangle( + Decimal(59), Decimal(500), Decimal(200), Decimal(100) + ), + font=StandardType1Font("Helvetica"), + font_size=Decimal(12), + contents="""Lorem Ipsum""", + font_color=HexColor("F1CD2E"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_highlight_annotation.py b/tests/pdf/page/annotations/test_add_highlight_annotation.py index 5c23e1659..184c3c756 100644 --- a/tests/pdf/page/annotations/test_add_highlight_annotation.py +++ b/tests/pdf/page/annotations/test_add_highlight_annotation.py @@ -3,20 +3,20 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - +from borb.pdf.canvas.layout.annotation.highlight_annotation import HighlightAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( RegularExpressionTextExtraction, ) +from tests.test_util import compare_visually_to_ground_truth class TestAddHighlightAnnotation(unittest.TestCase): @@ -89,7 +89,7 @@ def test_add_highlight_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_highlight_annotation(bb) + doc.get_page(0).append_annotation(HighlightAnnotation(bb)) # attempt to store PDF with open(self.output_dir / "output_002.pdf", "wb") as out_file_handle: diff --git a/tests/pdf/page/annotations/test_add_line_annotation.py b/tests/pdf/page/annotations/test_add_line_annotation.py index f01d600cd..d7298f4ee 100644 --- a/tests/pdf/page/annotations/test_add_line_annotation.py +++ b/tests/pdf/page/annotations/test_add_line_annotation.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.line_annotation import LineAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -90,10 +91,12 @@ def test_add_line_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_line_annotation( - (bb.get_x(), bb.get_y()), - (bb.get_x() + bb.get_width(), bb.get_y()), - stroke_color=HexColor("f1cd2e"), + doc.get_page(0).append_annotation( + LineAnnotation( + (bb.get_x(), bb.get_y()), + (bb.get_x() + bb.get_width(), bb.get_y()), + stroke_color=HexColor("f1cd2e"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_polygon_annotation_using_line_art_factory.py b/tests/pdf/page/annotations/test_add_polygon_annotation_using_line_art_factory.py index 605c53f19..ab3717a0c 100644 --- a/tests/pdf/page/annotations/test_add_polygon_annotation_using_line_art_factory.py +++ b/tests/pdf/page/annotations/test_add_polygon_annotation_using_line_art_factory.py @@ -3,10 +3,9 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.polygon_annotion import PolygonAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( @@ -14,9 +13,10 @@ ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth class TestAddAllLineArtAnnotations(unittest.TestCase): @@ -152,9 +152,11 @@ def test_add_line_art_annotation(self): # add annotation for i, s in enumerate(shapes): - pdf.get_page(0).append_polygon_annotation( - points=s, - stroke_color=colors[i % len(colors)], + pdf.get_page(0).append_annotation( + PolygonAnnotation( + points=s, + stroke_color=colors[i % len(colors)], + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_polyline_annotation_using_line_art_factory.py b/tests/pdf/page/annotations/test_add_polyline_annotation_using_line_art_factory.py index 4f39c6998..d1af0a3ee 100644 --- a/tests/pdf/page/annotations/test_add_polyline_annotation_using_line_art_factory.py +++ b/tests/pdf/page/annotations/test_add_polyline_annotation_using_line_art_factory.py @@ -5,13 +5,14 @@ from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.polyline_annotation import PolylineAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF @@ -149,10 +150,12 @@ def test_add_line_art_annotation(self): # add annotation for i, s in enumerate(shapes): - pdf.get_page(0).append_polyline_annotation( - points=s, - fill_color=colors[(i + 1) % len(colors)], - stroke_color=colors[i % len(colors)], + pdf.get_page(0).append_annotation( + PolylineAnnotation( + points=s, + fill_color=colors[(i + 1) % len(colors)], + stroke_color=colors[i % len(colors)], + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_redact_annotation.py b/tests/pdf/page/annotations/test_add_redact_annotation.py index 11490165b..95880012b 100644 --- a/tests/pdf/page/annotations/test_add_redact_annotation.py +++ b/tests/pdf/page/annotations/test_add_redact_annotation.py @@ -4,10 +4,9 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.font.simple_font.true_type_font import TrueTypeFont +from borb.pdf.canvas.layout.annotation.redact_annotation import RedactAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout @@ -15,12 +14,13 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( RegularExpressionTextExtraction, ) +from tests.test_util import compare_visually_to_ground_truth unittest.TestLoader.sortTestMethodsUsing = None @@ -96,9 +96,11 @@ def test_add_redact_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, - stroke_color=HexColor("FF0000"), + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, + stroke_color=HexColor("FF0000"), + ) ) # attempt to store PDF @@ -121,9 +123,11 @@ def test_add_redact_annotation_to_wild_caught_document(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, - stroke_color=HexColor("FF0000"), + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, + stroke_color=HexColor("FF0000"), + ) ) # attempt to store PDF @@ -167,9 +171,11 @@ def test_add_redact_annotation_to_document_with_truetype_font(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, - stroke_color=HexColor("FF0000"), + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, + stroke_color=HexColor("FF0000"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_remote_go_to_annotation.py b/tests/pdf/page/annotations/test_add_remote_go_to_annotation.py index 7a1dca266..81cfa7140 100644 --- a/tests/pdf/page/annotations/test_add_remote_go_to_annotation.py +++ b/tests/pdf/page/annotations/test_add_remote_go_to_annotation.py @@ -4,18 +4,20 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.remote_go_to_annotation import ( + RemoteGoToAnnotation, +) from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.chunk_of_text import ChunkOfText from borb.pdf.canvas.layout.text.chunks_of_text import HeterogeneousParagraph from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth unittest.TestLoader.sortTestMethodsUsing = None @@ -72,8 +74,8 @@ def test_add_remote_go_to_annotation(self): pdf.get_page(0), r ) - pdf.get_page(0).append_remote_go_to_annotation( - rectangle=r, uri="https://www.borbpdf.com" + pdf.get_page(0).append_annotation( + RemoteGoToAnnotation(bounding_box=r, uri="https://www.borbpdf.com") ) # attempt to store PDF @@ -123,8 +125,10 @@ def test_add_remote_go_to_annotation_by_regex(self): layout.add(hp) # add annotation - pdf.get_page(0).append_remote_go_to_annotation( - rectangle=chunks[4].get_bounding_box(), uri="https://www.borbpdf.com" + pdf.get_page(0).append_annotation( + RemoteGoToAnnotation( + bounding_box=chunks[4].get_bounding_box(), uri="https://www.borbpdf.com" + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_square_annotation.py b/tests/pdf/page/annotations/test_add_square_annotation.py index 0ab2643b8..72b8d7f28 100644 --- a/tests/pdf/page/annotations/test_add_square_annotation.py +++ b/tests/pdf/page/annotations/test_add_square_annotation.py @@ -3,18 +3,18 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth class TestAddSquareAnnotation(unittest.TestCase): @@ -58,15 +58,17 @@ def test_add_square_annotation(self): # add annotation w: Decimal = pdf.get_page(0).get_page_info().get_width() h: Decimal = pdf.get_page(0).get_page_info().get_height() - pdf.get_page(0).append_square_annotation( - rectangle=Rectangle( - w / Decimal(2) - Decimal(32), - h / Decimal(2) - Decimal(32), - Decimal(64), - Decimal(64), - ), - stroke_color=HexColor("0B3954"), - fill_color=HexColor("f1cd2e"), + pdf.get_page(0).append_annotation( + SquareAnnotation( + bounding_box=Rectangle( + w / Decimal(2) - Decimal(32), + h / Decimal(2) - Decimal(32), + Decimal(64), + Decimal(64), + ), + stroke_color=HexColor("0B3954"), + fill_color=HexColor("f1cd2e"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_square_annotation_in_free_space.py b/tests/pdf/page/annotations/test_add_square_annotation_in_free_space.py index a6b91443f..479985763 100644 --- a/tests/pdf/page/annotations/test_add_square_annotation_in_free_space.py +++ b/tests/pdf/page/annotations/test_add_square_annotation_in_free_space.py @@ -3,12 +3,12 @@ from math import ceil from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.free_space_finder import FreeSpaceFinder from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth unittest.TestLoader.sortTestMethodsUsing = None @@ -44,10 +44,12 @@ def test_document_write_grid(self): continue x = Decimal(i * 10) y = Decimal(j * 10) - doc.get_page(0).append_square_annotation( - Rectangle(x, y, Decimal(10), Decimal(10)), - stroke_color=HexColor("BF4E30"), - fill_color=HexColor("BF4E30"), + doc.get_page(0).append_annotation( + SquareAnnotation( + Rectangle(x, y, Decimal(10), Decimal(10)), + stroke_color=HexColor("BF4E30"), + fill_color=HexColor("BF4E30"), + ) ) # attempt to store PDF @@ -73,10 +75,12 @@ def test_document_write_annotation(self): free_rectangle = l.get_free_space_for_page(0, ideal_rectangle) # add annotation - doc.get_page(0).append_square_annotation( - free_rectangle, - stroke_color=HexColor("0B3954"), - fill_color=HexColor("f1cd2e"), + doc.get_page(0).append_annotation( + SquareAnnotation( + free_rectangle, + stroke_color=HexColor("0B3954"), + fill_color=HexColor("f1cd2e"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_squiggle_annotation.py b/tests/pdf/page/annotations/test_add_squiggle_annotation.py index fcb27dd0a..97621dd5f 100644 --- a/tests/pdf/page/annotations/test_add_squiggle_annotation.py +++ b/tests/pdf/page/annotations/test_add_squiggle_annotation.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.squiggly_annotation import SquigglyAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -90,10 +91,12 @@ def test_add_squiggle_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_squiggly_annotation( - bb, - line_width=Decimal(2), - stroke_color=HexColor("DE6449"), + doc.get_page(0).append_annotation( + SquigglyAnnotation( + bb, + stroke_width=Decimal(2), + stroke_color=HexColor("DE6449"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_strikeout_annotation.py b/tests/pdf/page/annotations/test_add_strikeout_annotation.py index 5385482a4..ea02ad081 100644 --- a/tests/pdf/page/annotations/test_add_strikeout_annotation.py +++ b/tests/pdf/page/annotations/test_add_strikeout_annotation.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.strike_out_annotation import StrikeOutAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -90,10 +91,12 @@ def test_add_strike_out_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_strike_out_annotation( - bb, - line_width=Decimal(2), - stroke_color=HexColor("DE6449"), + doc.get_page(0).append_annotation( + StrikeOutAnnotation( + bb, + stroke_width=Decimal(2), + stroke_color=HexColor("DE6449"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_super_mario_annotation.py b/tests/pdf/page/annotations/test_add_super_mario_annotation.py index 39f1fbe2b..e39ed85f7 100644 --- a/tests/pdf/page/annotations/test_add_super_mario_annotation.py +++ b/tests/pdf/page/annotations/test_add_super_mario_annotation.py @@ -5,13 +5,17 @@ from borb.pdf.canvas.color.color import X11Color from borb.pdf.canvas.geometry.rectangle import Rectangle +from borb.pdf.canvas.layout.annotation.link_annotation import ( + DestinationType, + LinkAnnotation, +) from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document -from borb.pdf.page.page import DestinationType, Page +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth @@ -91,16 +95,18 @@ def test_add_supermario_annotation(self): continue x = pixel_size * j + float(page_width) / 2 y = pixel_size * (len(m) - i) + float(page_height) / 2 - pdf.get_page(0).append_link_annotation( - page=Decimal(0), - color=c[m[i][j]], - destination_type=DestinationType.FIT, - rectangle=Rectangle( - Decimal(x), - Decimal(y), - Decimal(pixel_size), - Decimal(pixel_size), - ), + pdf.get_page(0).append_annotation( + LinkAnnotation( + page=Decimal(0), + color=c[m[i][j]], + destination_type=DestinationType.FIT, + bounding_box=Rectangle( + Decimal(x), + Decimal(y), + Decimal(pixel_size), + Decimal(pixel_size), + ), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_text_annotation.py b/tests/pdf/page/annotations/test_add_text_annotation.py index f4335141c..be90b84bc 100644 --- a/tests/pdf/page/annotations/test_add_text_annotation.py +++ b/tests/pdf/page/annotations/test_add_text_annotation.py @@ -4,14 +4,18 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.text_annotation import ( + TextAnnotationIconType, + TextAnnotation, +) from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document -from borb.pdf.page.page import Page, TextAnnotationIconType +from borb.pdf.document.document import Document +from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( RegularExpressionTextExtraction, @@ -90,9 +94,10 @@ def test_add_text_annotation(self): doc = PDF.loads(in_file_handle, [l]) bb = l.get_matches_for_page(0)[0].get_bounding_boxes()[0] - doc.get_page(0).append_text_annotation( - bb, - contents=""" + doc.get_page(0).append_annotation( + TextAnnotation( + bb, + contents=""" Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. @@ -101,8 +106,9 @@ def test_add_text_annotation(self): It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. """, - text_annotation_icon=TextAnnotationIconType.COMMENT, - color=HexColor("F1CD2E"), + text_annotation_icon=TextAnnotationIconType.COMMENT, + color=HexColor("F1CD2E"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_add_underline_annotation.py b/tests/pdf/page/annotations/test_add_underline_annotation.py index 266d82e0f..52832d2f7 100644 --- a/tests/pdf/page/annotations/test_add_underline_annotation.py +++ b/tests/pdf/page/annotations/test_add_underline_annotation.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.underline_annotation import UnderlineAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -91,9 +92,11 @@ def test_add_underline_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_underline_annotation( - bb.grow(Decimal(2)), - stroke_color=HexColor("DE6449"), + doc.get_page(0).append_annotation( + UnderlineAnnotation( + bb.grow(Decimal(2)), + stroke_color=HexColor("DE6449"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_count_annotations.py b/tests/pdf/page/annotations/test_count_annotations.py index 67bd1e643..a71d1e5aa 100644 --- a/tests/pdf/page/annotations/test_count_annotations.py +++ b/tests/pdf/page/annotations/test_count_annotations.py @@ -5,13 +5,14 @@ from borb.io.read.types import List from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.redact_annotation import RedactAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -93,9 +94,11 @@ def test_add_redact_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, - stroke_color=HexColor("FF0000"), + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, + stroke_color=HexColor("FF0000"), + ) ) # attempt to store PDF diff --git a/tests/pdf/page/annotations/test_remove_annotation.py b/tests/pdf/page/annotations/test_remove_annotation.py index 054c07285..2a083165b 100644 --- a/tests/pdf/page/annotations/test_remove_annotation.py +++ b/tests/pdf/page/annotations/test_remove_annotation.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.io.read.types import List +from borb.pdf.canvas.layout.annotation.redact_annotation import RedactAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -93,8 +94,10 @@ def test_add_redact_annotation(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, + ) ) # attempt to store PDF diff --git a/tests/pdf/page/model/test_get_size_of_newly_created_page.py b/tests/pdf/page/model/test_get_size_of_newly_created_page.py index 21bf1d17d..140ca3b2f 100644 --- a/tests/pdf/page/model/test_get_size_of_newly_created_page.py +++ b/tests/pdf/page/model/test_get_size_of_newly_created_page.py @@ -1,6 +1,6 @@ import unittest -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page diff --git a/tests/pdf/page/redact/test_apply_redaction_annotations.py b/tests/pdf/page/redact/test_apply_redaction_annotations.py index 05c86db8b..7d2e85299 100644 --- a/tests/pdf/page/redact/test_apply_redaction_annotations.py +++ b/tests/pdf/page/redact/test_apply_redaction_annotations.py @@ -4,11 +4,10 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.io.read.types import Decimal as bDecimal from borb.io.read.types import Dictionary, List, Name, Stream from borb.pdf.canvas.color.color import X11Color +from borb.pdf.canvas.layout.annotation.redact_annotation import RedactAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout @@ -16,12 +15,13 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( RegularExpressionTextExtraction, ) +from tests.test_util import compare_visually_to_ground_truth unittest.TestLoader.sortTestMethodsUsing = None @@ -102,8 +102,10 @@ def test_add_redact_annotation_001(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black") + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black") + ) ) # attempt to store PDF @@ -204,8 +206,10 @@ def test_add_redact_annotation_002(self): for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): bb = bb.grow(Decimal(2)) - doc.get_page(0).append_redact_annotation( - bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black") + doc.get_page(0).append_annotation( + RedactAnnotation( + bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black") + ) ) # attempt to store PDF diff --git a/tests/pdf/page/rotate/test_rotate_page.py b/tests/pdf/page/rotate/test_rotate_page.py index e26b709aa..a2419ced3 100644 --- a/tests/pdf/page/rotate/test_rotate_page.py +++ b/tests/pdf/page/rotate/test_rotate_page.py @@ -8,7 +8,7 @@ from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/pdf/page/shape/test_page_has_empty_resource_dictionary.py b/tests/pdf/page/shape/test_page_has_empty_resource_dictionary.py index 026fda7a9..4003018cc 100644 --- a/tests/pdf/page/shape/test_page_has_empty_resource_dictionary.py +++ b/tests/pdf/page/shape/test_page_has_empty_resource_dictionary.py @@ -2,16 +2,15 @@ from decimal import Decimal from pathlib import Path -from tests.test_util import compare_visually_to_ground_truth - from borb.io.read.types import Dictionary from borb.pdf.canvas.color.color import HexColor from borb.pdf.canvas.geometry.rectangle import Rectangle from borb.pdf.canvas.layout.shape.shape import Shape from borb.pdf.canvas.line_art.line_art_factory import LineArtFactory -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF +from tests.test_util import compare_visually_to_ground_truth class TestPageHasEmptyResourceDictionary(unittest.TestCase): diff --git a/tests/pdf/trailer/profile_read_document.py b/tests/pdf/trailer/profile_read_document.py index 948af27a8..24b0c79a5 100644 --- a/tests/pdf/trailer/profile_read_document.py +++ b/tests/pdf/trailer/profile_read_document.py @@ -2,7 +2,7 @@ import typing from pathlib import Path -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.pdf import PDF diff --git a/tests/pdf/trailer/test_change_info_dictionary_author.py b/tests/pdf/trailer/test_change_info_dictionary_author.py index ed0ef80a9..cb93d1207 100644 --- a/tests/pdf/trailer/test_change_info_dictionary_author.py +++ b/tests/pdf/trailer/test_change_info_dictionary_author.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF diff --git a/tests/toolkit/export/html_to_pdf/test_export_html_to_pdf.py b/tests/toolkit/export/html_to_pdf/test_export_html_to_pdf.py index a04769ce4..c895708b9 100644 --- a/tests/toolkit/export/html_to_pdf/test_export_html_to_pdf.py +++ b/tests/toolkit/export/html_to_pdf/test_export_html_to_pdf.py @@ -1,7 +1,7 @@ import unittest from pathlib import Path -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.pdf import PDF from borb.toolkit.export.html_to_pdf.html_to_pdf import HTMLToPDF from tests.test_util import compare_visually_to_ground_truth diff --git a/tests/toolkit/export/markdown_to_pdf/test_export_markdown_to_pdf.py b/tests/toolkit/export/markdown_to_pdf/test_export_markdown_to_pdf.py index 264860f0d..9622e68ef 100644 --- a/tests/toolkit/export/markdown_to_pdf/test_export_markdown_to_pdf.py +++ b/tests/toolkit/export/markdown_to_pdf/test_export_markdown_to_pdf.py @@ -1,7 +1,7 @@ import unittest from pathlib import Path -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.pdf import PDF from borb.toolkit.export.markdown_to_pdf.markdown_to_pdf import MarkdownToPDF diff --git a/tests/toolkit/redact/test_redact_common_regular_expressions.py b/tests/toolkit/redact/test_redact_common_regular_expressions.py index b15183857..be700f3f6 100644 --- a/tests/toolkit/redact/test_redact_common_regular_expressions.py +++ b/tests/toolkit/redact/test_redact_common_regular_expressions.py @@ -5,12 +5,13 @@ from borb.io.read.types import List from borb.pdf.canvas.color.color import X11Color +from borb.pdf.canvas.layout.annotation.redact_annotation import RedactAnnotation from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.redact.common_regular_expressions import CommonRegularExpression @@ -102,7 +103,7 @@ def test_add_redact_annotation_001(self): # fmt: off for m in l.get_matches_for_page(0): for bb in m.get_bounding_boxes(): - doc.get_page(0).append_redact_annotation(bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black")) + doc.get_page(0).append_annotation(RedactAnnotation(bb, stroke_color=X11Color("Black"), fill_color=X11Color("Black"))) # fmt: on # attempt to store PDF diff --git a/tests/toolkit/table/test_detect_table.py b/tests/toolkit/table/test_detect_table.py index 888f9830d..0575b60c8 100644 --- a/tests/toolkit/table/test_detect_table.py +++ b/tests/toolkit/table/test_detect_table.py @@ -5,6 +5,7 @@ from pathlib import Path from borb.pdf.canvas.color.color import X11Color +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.page_layout.page_layout import PageLayout @@ -14,7 +15,7 @@ ) from borb.pdf.canvas.layout.table.table import Table, TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.table.table_detection_by_lines import TableDetectionByLines @@ -181,15 +182,19 @@ def test_find_table(self): # add annotation around table for t in tables: r = t.get_bounding_box().grow(Decimal(5)) - doc.get_page(0).append_square_annotation( - r, stroke_color=X11Color("Red") + doc.get_page(0).append_annotation( + SquareAnnotation(r, stroke_color=X11Color("Red")) ) for tc in t._content: r = tc.get_bounding_box() r = r.shrink(Decimal(2)) - doc.get_page(0).append_square_annotation( - r, stroke_color=X11Color("Green"), fill_color=X11Color("Green") + doc.get_page(0).append_annotation( + SquareAnnotation( + r, + stroke_color=X11Color("Green"), + fill_color=X11Color("Green"), + ) ) # determine output name diff --git a/tests/toolkit/text/test_extract_courier_text.py b/tests/toolkit/text/test_extract_courier_text.py index c1ef8f03d..4c999a5e8 100644 --- a/tests/toolkit/text/test_extract_courier_text.py +++ b/tests/toolkit/text/test_extract_courier_text.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.font_name_filter import FontNameFilter diff --git a/tests/toolkit/text/test_extract_keywords.py b/tests/toolkit/text/test_extract_keywords.py index eb17a56f2..31c043f97 100644 --- a/tests/toolkit/text/test_extract_keywords.py +++ b/tests/toolkit/text/test_extract_keywords.py @@ -9,7 +9,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.stop_words import ENGLISH_STOP_WORDS diff --git a/tests/toolkit/text/test_extract_red_text.py b/tests/toolkit/text/test_extract_red_text.py index f1d12606c..128327297 100644 --- a/tests/toolkit/text/test_extract_red_text.py +++ b/tests/toolkit/text/test_extract_red_text.py @@ -11,7 +11,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.font_color_filter import FontColorFilter diff --git a/tests/toolkit/text/test_extract_regex.py b/tests/toolkit/text/test_extract_regex.py index d60256f39..68e908363 100644 --- a/tests/toolkit/text/test_extract_regex.py +++ b/tests/toolkit/text/test_extract_regex.py @@ -4,13 +4,14 @@ from pathlib import Path from borb.pdf.canvas.color.color import HexColor +from borb.pdf.canvas.layout.annotation.square_annotation import SquareAnnotation from borb.pdf.canvas.layout.layout_element import Alignment from borb.pdf.canvas.layout.page_layout.multi_column_layout import SingleColumnLayout from borb.pdf.canvas.layout.table.fixed_column_width_table import ( FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.regular_expression_text_extraction import ( @@ -97,9 +98,11 @@ def test_match_regular_expression(self): assert 6 <= int(bb.height) <= 8 bb = bb.grow(Decimal(2)) - doc.get_page(0).append_square_annotation( - bb, - stroke_color=HexColor("DE6449"), + doc.get_page(0).append_annotation( + SquareAnnotation( + bb, + stroke_color=HexColor("DE6449"), + ) ) # attempt to store PDF diff --git a/tests/toolkit/text/test_extract_text.py b/tests/toolkit/text/test_extract_text.py index 3943e4ca1..f6bad83d4 100644 --- a/tests/toolkit/text/test_extract_text.py +++ b/tests/toolkit/text/test_extract_text.py @@ -10,7 +10,7 @@ FixedColumnWidthTable as Table, ) from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.text.simple_text_extraction import SimpleTextExtraction diff --git a/tests/toolkit/text/test_extract_text_from_self_made_invoice.py b/tests/toolkit/text/test_extract_text_from_self_made_invoice.py index 1132f1e10..e9548d43c 100644 --- a/tests/toolkit/text/test_extract_text_from_self_made_invoice.py +++ b/tests/toolkit/text/test_extract_text_from_self_made_invoice.py @@ -14,7 +14,7 @@ from borb.pdf.canvas.layout.table.fixed_column_width_table import FixedColumnWidthTable from borb.pdf.canvas.layout.table.table import Table, TableCell from borb.pdf.canvas.layout.text.paragraph import Paragraph -from borb.pdf.document import Document +from borb.pdf.document.document import Document from borb.pdf.page.page import Page from borb.pdf.pdf import PDF from borb.toolkit.location.location_filter import LocationFilter