Source code for pdftools_toolbox.pdf.page

from __future__ import annotations
import io
from typing import List, Iterator, Tuple, Optional, Any, TYPE_CHECKING, Callable
from ctypes import *
from datetime import datetime
from numbers import Number
from pdftools_toolbox.internal import _lib
from pdftools_toolbox.internal.utils import _string_to_utf16, _utf16_to_string
from pdftools_toolbox.internal.streams import _StreamDescriptor, _NativeStream
from pdftools_toolbox.internal.native_base import _NativeBase
from pdftools_toolbox.internal.native_object import _NativeObject

import pdftools_toolbox.internal

if TYPE_CHECKING:
    from pdftools_toolbox.pdf.document import Document
    from pdftools_toolbox.geometry.real.size import Size
    from pdftools_toolbox.pdf.page_copy_options import PageCopyOptions
    from pdftools_toolbox.geometry.real.rectangle import Rectangle
    from pdftools_toolbox.geometry.rotation import Rotation
    from pdftools_toolbox.pdf.content.content import Content
    from pdftools_toolbox.pdf.annotations.annotation_list import AnnotationList
    from pdftools_toolbox.pdf.navigation.link_list import LinkList
    from pdftools_toolbox.pdf.forms.widget_list import WidgetList
    from pdftools_toolbox.pdf.metadata import Metadata

else:
    Document = "pdftools_toolbox.pdf.document.Document"
    Size = "pdftools_toolbox.geometry.real.size.Size"
    PageCopyOptions = "pdftools_toolbox.pdf.page_copy_options.PageCopyOptions"
    Rectangle = "pdftools_toolbox.geometry.real.rectangle.Rectangle"
    Rotation = "pdftools_toolbox.geometry.rotation.Rotation"
    Content = "pdftools_toolbox.pdf.content.content.Content"
    AnnotationList = "pdftools_toolbox.pdf.annotations.annotation_list.AnnotationList"
    LinkList = "pdftools_toolbox.pdf.navigation.link_list.LinkList"
    WidgetList = "pdftools_toolbox.pdf.forms.widget_list.WidgetList"
    Metadata = "pdftools_toolbox.pdf.metadata.Metadata"


[docs] class Page(_NativeObject): """ Represents a page, which may be either associated with a document or part of a document. When the page is associated with a document, changes to the page are still possible. Any changes made to the page will be reflected in the associated document, after the page is appended to the document's :attr:`pdftools_toolbox.pdf.document.Document.pages` . After a page is appended to a document's :attr:`pdftools_toolbox.pdf.document.Document.pages` , the page becomes part of the document and no further changes to the page are possible. """
[docs] @staticmethod def create(target_document: Document, size: Size) -> Page: """ Create an empty page The page is associated with the given target document but not yet part of it. It can be appended to the document's :attr:`pdftools_toolbox.pdf.document.Document.pages` . Args: targetDocument (pdftools_toolbox.pdf.document.Document): the output document with which the returned object is associated size (pdftools_toolbox.geometry.real.size.Size): the page size Returns: pdftools_toolbox.pdf.page.Page: the newly created page object Raises: ValueError: if the `targetDocument` argument has already been closed ValueError: if the `targetDocument` argument is read-only """ from pdftools_toolbox.pdf.document import Document from pdftools_toolbox.geometry.real.size import Size if not isinstance(target_document, Document): raise TypeError(f"Expected type {Document.__name__}, but got {type(target_document).__name__}.") if not isinstance(size, Size): raise TypeError(f"Expected type {Size.__name__}, but got {type(size).__name__}.") _lib.PtxPdf_Page_Create.argtypes = [c_void_p, POINTER(Size)] _lib.PtxPdf_Page_Create.restype = c_void_p ret_val = _lib.PtxPdf_Page_Create(target_document._handle, size) if ret_val is None: _NativeBase._throw_last_error(False) return Page._create_dynamic_type(ret_val)
[docs] @staticmethod def copy(target_document: Document, page: Page, options: Optional[PageCopyOptions]) -> Page: """ Copy a page Copy a page object from an input document to the given `targetDocument`. The returned object is associated with the given target document but not yet part of it. It can be appended to the document's :attr:`pdftools_toolbox.pdf.document.Document.pages` . Args: targetDocument (pdftools_toolbox.pdf.document.Document): the output document with which the returned object is associated page (pdftools_toolbox.pdf.page.Page): a page of a different document options (Optional[pdftools_toolbox.pdf.page_copy_options.PageCopyOptions]): the copy options Returns: pdftools_toolbox.pdf.page.Page: the copied page, associated with the current document. Raises: OSError: Error reading from the source document or writing to the target document pdftools_toolbox.corrupt_error.CorruptError: The source document is corrupt pdftools_toolbox.conformance_error.ConformanceError: The conformance level of the source document is not compatible with the conformance level of the target document. pdftools_toolbox.conformance_error.ConformanceError: The explicitly requested conformance level is PDF/A Level A (:attr:`pdftools_toolbox.pdf.conformance.Conformance.PDFA1A` , :attr:`pdftools_toolbox.pdf.conformance.Conformance.PDFA2A` , or :attr:`pdftools_toolbox.pdf.conformance.Conformance.PDFA3A` ) and the copy option :attr:`pdftools_toolbox.pdf.page_copy_options.PageCopyOptions.copy_logical_structure` is not set. ValueError: if the `targetDocument` argument has already been closed ValueError: if the `targetDocument` argument is read-only ValueError: if the `page` object is not associated with an input document ValueError: if the document associated with the `page` object has already been closed ValueError: if the argument `options` has :attr:`pdftools_toolbox.pdf.page_copy_options.PageCopyOptions.form_fields` set to :attr:`pdftools_toolbox.pdf.forms.form_field_copy_strategy.FormFieldCopyStrategy.COPY` and the `targetDocument` contains form fields that have either been copied explicitly with :meth:`pdftools_toolbox.pdf.forms.field_node.FieldNode.copy` or created with :meth:`pdftools_toolbox.pdf.forms.check_box.CheckBox.create` , :meth:`pdftools_toolbox.pdf.forms.combo_box.ComboBox.create` , :meth:`pdftools_toolbox.pdf.forms.comb_text_field.CombTextField.create` , :meth:`pdftools_toolbox.pdf.forms.general_text_field.GeneralTextField.create` , :meth:`pdftools_toolbox.pdf.forms.list_box.ListBox.create` , :meth:`pdftools_toolbox.pdf.forms.radio_button_group.RadioButtonGroup.create` , or :meth:`pdftools_toolbox.pdf.forms.sub_form.SubForm.create` . ValueError: if the argument `options` has :attr:`pdftools_toolbox.pdf.page_copy_options.PageCopyOptions.unsigned_signatures` set to :attr:`pdftools_toolbox.pdf.copy_strategy.CopyStrategy.COPY` and the `targetDocument` contains form fields that have either been copied explicitly with :meth:`pdftools_toolbox.pdf.forms.field_node.FieldNode.copy` or created with :meth:`pdftools_toolbox.pdf.forms.check_box.CheckBox.create` , :meth:`pdftools_toolbox.pdf.forms.combo_box.ComboBox.create` , :meth:`pdftools_toolbox.pdf.forms.comb_text_field.CombTextField.create` , :meth:`pdftools_toolbox.pdf.forms.general_text_field.GeneralTextField.create` , :meth:`pdftools_toolbox.pdf.forms.list_box.ListBox.create` , :meth:`pdftools_toolbox.pdf.forms.radio_button_group.RadioButtonGroup.create` , or :meth:`pdftools_toolbox.pdf.forms.sub_form.SubForm.create` . ValueError: if `options` has :attr:`pdftools_toolbox.pdf.page_copy_options.PageCopyOptions.copy_outline_items` set to `True` and the `targetDocument` contains outline items that have been copied explicitly with :meth:`pdftools_toolbox.pdf.navigation.outline_item.OutlineItem.copy` . """ from pdftools_toolbox.pdf.document import Document from pdftools_toolbox.pdf.page_copy_options import PageCopyOptions if not isinstance(target_document, Document): raise TypeError(f"Expected type {Document.__name__}, but got {type(target_document).__name__}.") if not isinstance(page, Page): raise TypeError(f"Expected type {Page.__name__}, but got {type(page).__name__}.") if options is not None and not isinstance(options, PageCopyOptions): raise TypeError(f"Expected type {PageCopyOptions.__name__} or None, but got {type(options).__name__}.") _lib.PtxPdf_Page_Copy.argtypes = [c_void_p, c_void_p, c_void_p] _lib.PtxPdf_Page_Copy.restype = c_void_p ret_val = _lib.PtxPdf_Page_Copy(target_document._handle, page._handle, options._handle if options is not None else None) if ret_val is None: _NativeBase._throw_last_error(False) return Page._create_dynamic_type(ret_val)
[docs] def update_size(self, rectangle: Rectangle) -> None: """ Update the page size to a specified rectangle. Note that all page-related coordinates are normalized to the crop box of the page. Updating the page size thus changes the coordinate system, rendering all previously extracted coordinates invalid. Args: rectangle (pdftools_toolbox.geometry.real.rectangle.Rectangle): the rectangle to update the page size to. Raises: StateError: if the owning document has already been closed StateError: if the page has already been closed OperationError: if the page is read-only """ from pdftools_toolbox.geometry.real.rectangle import Rectangle if not isinstance(rectangle, Rectangle): raise TypeError(f"Expected type {Rectangle.__name__}, but got {type(rectangle).__name__}.") _lib.PtxPdf_Page_UpdateSize.argtypes = [c_void_p, POINTER(Rectangle)] _lib.PtxPdf_Page_UpdateSize.restype = c_bool if not _lib.PtxPdf_Page_UpdateSize(self._handle, rectangle): _NativeBase._throw_last_error(False)
[docs] def rotate(self, rotate: Rotation) -> None: """ Rotate the page by a multiple of 90 degrees. Args: rotate (pdftools_toolbox.geometry.rotation.Rotation): the desired rotation Raises: StateError: if the owning document has already been closed StateError: if the page has already been closed OperationError: if the page is read-only """ from pdftools_toolbox.geometry.rotation import Rotation if not isinstance(rotate, Rotation): raise TypeError(f"Expected type {Rotation.__name__}, but got {type(rotate).__name__}.") _lib.PtxPdf_Page_Rotate.argtypes = [c_void_p, c_int] _lib.PtxPdf_Page_Rotate.restype = c_bool if not _lib.PtxPdf_Page_Rotate(self._handle, c_int(rotate.value)): _NativeBase._throw_last_error(False)
@property def rotation(self) -> Rotation: """ The current page rotation Returns: pdftools_toolbox.geometry.rotation.Rotation """ from pdftools_toolbox.geometry.rotation import Rotation _lib.PtxPdf_Page_GetRotation.argtypes = [c_void_p] _lib.PtxPdf_Page_GetRotation.restype = c_int ret_val = _lib.PtxPdf_Page_GetRotation(self._handle) if ret_val == 0: _NativeBase._throw_last_error() return Rotation(ret_val) @property def size(self) -> Size: """ The visible size of the page (crop box). The page size corresponds to the size of the crop box. Since all coordinates are normalized to the origin of the crop box, the normalized origin of the crop box is always (0,0) and thus only the size is required. The crop box defines the region to which the contents of the page shall be clipped (cropped) when displayed or printed. Unlike the other boxes, the crop box has no defined meaning in terms of physical page geometry or intended use; it merely imposes clipping on the page contents. However, in the absence of additional information (such as imposition instructions specified in a JDF job ticket), the crop box determines how the page's contents shall be positioned on the output medium. The default value is the page's media box. This property cannot be `None`. Returns: pdftools_toolbox.geometry.real.size.Size Raises: StateError: if the page has already been closed """ from pdftools_toolbox.geometry.real.size import Size _lib.PtxPdf_Page_GetSize.argtypes = [c_void_p, POINTER(Size)] _lib.PtxPdf_Page_GetSize.restype = c_bool ret_val = Size() if not _lib.PtxPdf_Page_GetSize(self._handle, byref(ret_val)): _NativeBase._throw_last_error(False) return ret_val @property def media_box(self) -> Rectangle: """ The media box of the page. The media box defines the boundaries of the physical medium on which the page is to be printed. It may include any extended area surrounding the finished page for bleed, printing marks, or other such purposes. It may also include areas close to the edges of the medium that cannot be marked because of physical limitations of the output device. Content falling outside this boundary may safely be discarded without affecting the meaning of the PDF file. This property cannot be `None`. Returns: pdftools_toolbox.geometry.real.rectangle.Rectangle Raises: StateError: if the page has already been closed """ from pdftools_toolbox.geometry.real.rectangle import Rectangle _lib.PtxPdf_Page_GetMediaBox.argtypes = [c_void_p, POINTER(Rectangle)] _lib.PtxPdf_Page_GetMediaBox.restype = c_bool ret_val = Rectangle() if not _lib.PtxPdf_Page_GetMediaBox(self._handle, byref(ret_val)): _NativeBase._throw_last_error(False) return ret_val @property def bleed_box(self) -> Optional[Rectangle]: """ The bleed box of the page. The bleed box (PDF 1.3) defines the region to which the contents of the page shall be clipped when output in a production environment. This may include any extra bleed area needed to accommodate the physical limitations of cutting, folding, and trimming equipment. The actual printed page may include printing marks that fall outside the bleed box. The default value is the page's crop box. This property is `None` if the page contains no explicit bleed box. Returns: Optional[pdftools_toolbox.geometry.real.rectangle.Rectangle] Raises: StateError: if the page has already been closed """ from pdftools_toolbox.geometry.real.rectangle import Rectangle _lib.PtxPdf_Page_GetBleedBox.argtypes = [c_void_p, POINTER(Rectangle)] _lib.PtxPdf_Page_GetBleedBox.restype = c_bool ret_val = Rectangle() if not _lib.PtxPdf_Page_GetBleedBox(self._handle, byref(ret_val)): _NativeBase._throw_last_error() return None return ret_val @property def trim_box(self) -> Optional[Rectangle]: """ The trim box of the page. The trim box (PDF 1.3) defines the intended dimensions of the finished page after trimming. It may be smaller than the media box to allow for production-related content, such as printing instructions, cut marks, or colour bars. The default value is the page's crop box. This property is `None` if the page contains no explicit trim box. Returns: Optional[pdftools_toolbox.geometry.real.rectangle.Rectangle] Raises: StateError: if the page has already been closed """ from pdftools_toolbox.geometry.real.rectangle import Rectangle _lib.PtxPdf_Page_GetTrimBox.argtypes = [c_void_p, POINTER(Rectangle)] _lib.PtxPdf_Page_GetTrimBox.restype = c_bool ret_val = Rectangle() if not _lib.PtxPdf_Page_GetTrimBox(self._handle, byref(ret_val)): _NativeBase._throw_last_error() return None return ret_val @property def art_box(self) -> Optional[Rectangle]: """ The art box of the page. The art box (PDF 1.3) defines the extent of the page's meaningful content (including potential white-space) as intended by the page’s creator. The default value is the page's crop box. This property is `None` if the page contains no explicit art box. Returns: Optional[pdftools_toolbox.geometry.real.rectangle.Rectangle] Raises: StateError: if the page has already been closed """ from pdftools_toolbox.geometry.real.rectangle import Rectangle _lib.PtxPdf_Page_GetArtBox.argtypes = [c_void_p, POINTER(Rectangle)] _lib.PtxPdf_Page_GetArtBox.restype = c_bool ret_val = Rectangle() if not _lib.PtxPdf_Page_GetArtBox(self._handle, byref(ret_val)): _NativeBase._throw_last_error() return None return ret_val @property def content(self) -> Content: """ the page content. If the page is writable, the content object can be used to apply new content on the page, for example overlays or underlays. Returns: pdftools_toolbox.pdf.content.content.Content Raises: StateError: if the page has already been closed """ from pdftools_toolbox.pdf.content.content import Content _lib.PtxPdf_Page_GetContent.argtypes = [c_void_p] _lib.PtxPdf_Page_GetContent.restype = c_void_p ret_val = _lib.PtxPdf_Page_GetContent(self._handle) if ret_val is None: _NativeBase._throw_last_error(False) return Content._create_dynamic_type(ret_val) @property def annotations(self) -> AnnotationList: """ the list of this page's annotations. Adding to this list results in an error: - *IllegalState* if the list has already been closed - *UnsupportedOperation* if the document is read-only - *IllegalArgument* - if the given annotation is `None` - if the given annotation object has already been closed - if the given annotation does not belong to the same document as the list - if the given annotation is already associated with a page This list does not support removing or setting elements or clearing. Returns: pdftools_toolbox.pdf.annotations.annotation_list.AnnotationList Raises: StateError: if the page has already been closed """ from pdftools_toolbox.pdf.annotations.annotation_list import AnnotationList _lib.PtxPdf_Page_GetAnnotations.argtypes = [c_void_p] _lib.PtxPdf_Page_GetAnnotations.restype = c_void_p ret_val = _lib.PtxPdf_Page_GetAnnotations(self._handle) if ret_val is None: _NativeBase._throw_last_error(False) return AnnotationList._create_dynamic_type(ret_val) @property def links(self) -> LinkList: """ the list of this page's links. Adding to this list results in an error: - *IllegalState* if the list has already been closed - *UnsupportedOperation* if the document is read-only - *IllegalArgument* - if the given link is `None` - if the given link object has already been closed - if the given link does not belong to the same document as the list - if the given link is already associated with a page This list does not support removing or setting elements or clearing. Returns: pdftools_toolbox.pdf.navigation.link_list.LinkList Raises: StateError: if the page has already been closed """ from pdftools_toolbox.pdf.navigation.link_list import LinkList _lib.PtxPdf_Page_GetLinks.argtypes = [c_void_p] _lib.PtxPdf_Page_GetLinks.restype = c_void_p ret_val = _lib.PtxPdf_Page_GetLinks(self._handle) if ret_val is None: _NativeBase._throw_last_error(False) return LinkList._create_dynamic_type(ret_val) @property def widgets(self) -> WidgetList: """ the list of this page's form field widgets. Adding to this list results in an error: - *IllegalState* if the list has already been closed - *UnsupportedOperation* if the document is read-only - *IllegalArgument* - if the given widget is `None` - if the given widget object has already been closed - if the given widget does not belong to the same document as the list - if the given widget is already associated with a page This list does not support removing or setting elements or clearing. Returns: pdftools_toolbox.pdf.forms.widget_list.WidgetList Raises: StateError: if the page has already been closed """ from pdftools_toolbox.pdf.forms.widget_list import WidgetList _lib.PtxPdf_Page_GetWidgets.argtypes = [c_void_p] _lib.PtxPdf_Page_GetWidgets.restype = c_void_p ret_val = _lib.PtxPdf_Page_GetWidgets(self._handle) if ret_val is None: _NativeBase._throw_last_error(False) return WidgetList._create_dynamic_type(ret_val) @property def metadata(self) -> Optional[Metadata]: """ the metadata of the page. If the document is writable, the metadata object will be writable too and all changes to the metadata object are reflected in the document. This property is `None` if the page has not metadata. Returns: Optional[pdftools_toolbox.pdf.metadata.Metadata] Raises: StateError: if the document has already been closed """ from pdftools_toolbox.pdf.metadata import Metadata _lib.PtxPdf_Page_GetMetadata.argtypes = [c_void_p] _lib.PtxPdf_Page_GetMetadata.restype = c_void_p ret_val = _lib.PtxPdf_Page_GetMetadata(self._handle) if ret_val is None: _NativeBase._throw_last_error() return None return Metadata._create_dynamic_type(ret_val) @metadata.setter def metadata(self, val: Optional[Metadata]) -> None: """ the metadata of the page. If the document is writable, the metadata object will be writable too and all changes to the metadata object are reflected in the document. This property is `None` if the page has not metadata. Args: val (Optional[pdftools_toolbox.pdf.metadata.Metadata]): property value Raises: StateError: if the document has already been closed OperationError: if the document is read-only ValueError: if the given :class:`pdftools_toolbox.pdf.metadata.Metadata` object belongs to a different document ValueError: if the given :class:`pdftools_toolbox.pdf.metadata.Metadata` object has already been closed """ from pdftools_toolbox.pdf.metadata import Metadata if val is not None and not isinstance(val, Metadata): raise TypeError(f"Expected type {Metadata.__name__} or None, but got {type(val).__name__}.") _lib.PtxPdf_Page_SetMetadata.argtypes = [c_void_p, c_void_p] _lib.PtxPdf_Page_SetMetadata.restype = c_bool if not _lib.PtxPdf_Page_SetMetadata(self._handle, val._handle if val is not None else None): _NativeBase._throw_last_error(False) @property def page_label(self) -> str: """ Page label The label for this page. A page does not have to have a label and if it doesn't this property will be an empty string. If it exists, a page label is designed to replace the page number in visual presentations and consists of an optional prefix and a number. Number can be in one of several styles (arabic, Roman, alphabetic) and starts at an arbitrary number for a range of pages. Page labels are used to set distinct names or numbers, most often for preface, appendices and similar sections of the document. Returns: str Raises: StateError: If the document has already been closed. """ _lib.PtxPdf_Page_GetPageLabelW.argtypes = [c_void_p, POINTER(c_wchar), c_size_t] _lib.PtxPdf_Page_GetPageLabelW.restype = c_size_t ret_val_size = _lib.PtxPdf_Page_GetPageLabelW(self._handle, None, 0) if ret_val_size == 0: _NativeBase._throw_last_error(False) ret_val = create_unicode_buffer(ret_val_size) _lib.PtxPdf_Page_GetPageLabelW(self._handle, ret_val, c_size_t(ret_val_size)) return _utf16_to_string(ret_val, ret_val_size) @staticmethod def _create_dynamic_type(handle): return Page._from_handle(handle) @classmethod def _from_handle(cls, handle): """ Internal factory method for constructing an instance using an internal handle. This method creates an instance of the class by bypassing the public constructor. """ instance = Page.__new__(cls) # Bypass __init__ instance._initialize(handle) return instance def _initialize(self, handle): super()._initialize(handle)