Source code for pdftools_toolbox.pdf.content.text_generator

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.geometry.real.point import Point
    from pdftools_toolbox.pdf.content.paint import Paint
    from pdftools_toolbox.pdf.content.stroke import Stroke
    from pdftools_toolbox.pdf.content.font import Font
    from pdftools_toolbox.pdf.content.text import Text

else:
    Point = "pdftools_toolbox.geometry.real.point.Point"
    Paint = "pdftools_toolbox.pdf.content.paint.Paint"
    Stroke = "pdftools_toolbox.pdf.content.stroke.Stroke"
    Font = "pdftools_toolbox.pdf.content.font.Font"
    Text = "pdftools_toolbox.pdf.content.text.Text"


[docs] class TextGenerator(_NativeObject): """ """
[docs] def __init__(self, text: Text, font: Font, font_size: float, location: Optional[Point]): """ Create a new text generator for appending text to a text content object. All parameters that cannot be set in the constructor are set to default values: - Rendering: fill text with black paint - CharacterSpacing: 0 - WordSpacing: 0 - HorizontalScaling: 1 - Leading: 1.2 times the `fontSize` (The `font`'s :attr:`pdftools_toolbox.pdf.content.font.Font.leading` is not used.) - Rise: 0 - Stroke: `None` - IntersectClipping: `False` Args: text (pdftools_toolbox.pdf.content.text.Text): the text object font (pdftools_toolbox.pdf.content.font.Font): the initial font fontSize (float): the initial font size and leading location (Optional[pdftools_toolbox.geometry.real.point.Point]): the initial position. If position is `None`, the default position *[0, 0]* is used. Raises: ValueError: if the document associated with the `text` object has already been closed ValueError: if the `text` and `font` objects are associated with different documents ValueError: if the document associated with the `font` object has already been closed ValueError: if the `font` has been obtained from :attr:`pdftools_toolbox.pdf.content.text_fragment.TextFragment.font` """ from pdftools_toolbox.pdf.content.text import Text from pdftools_toolbox.pdf.content.font import Font from pdftools_toolbox.geometry.real.point import Point if not isinstance(text, Text): raise TypeError(f"Expected type {Text.__name__}, but got {type(text).__name__}.") if not isinstance(font, Font): raise TypeError(f"Expected type {Font.__name__}, but got {type(font).__name__}.") if not isinstance(font_size, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(font_size).__name__}.") if location is not None and not isinstance(location, Point): raise TypeError(f"Expected type {Point.__name__} or None, but got {type(location).__name__}.") _lib.PtxPdfContent_TextGenerator_New.argtypes = [c_void_p, c_void_p, c_double, POINTER(Point)] _lib.PtxPdfContent_TextGenerator_New.restype = c_void_p ret_val = _lib.PtxPdfContent_TextGenerator_New(text._handle, font._handle, font_size, location) if ret_val is None: _NativeBase._throw_last_error(False) super()._initialize(ret_val)
[docs] def get_width(self, text: Optional[str]) -> float: """ Get the width of a text string. The width of a text string as if it would be shown with the current settings. Args: text (Optional[str]): the text fragment Returns: float: the width of the text Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the `text` argument is `None` """ if text is not None and not isinstance(text, str): raise TypeError(f"Expected type {str.__name__} or None, but got {type(text).__name__}.") _lib.PtxPdfContent_TextGenerator_GetWidthW.argtypes = [c_void_p, c_wchar_p] _lib.PtxPdfContent_TextGenerator_GetWidthW.restype = c_double ret_val = _lib.PtxPdfContent_TextGenerator_GetWidthW(self._handle, _string_to_utf16(text)) if ret_val == 0.0: _NativeBase._throw_last_error() return ret_val
[docs] def show(self, text: Optional[str]) -> None: """ Show a text string. The text is shown using the current settings. Args: text (Optional[str]): the text to be shown Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the `text` argument is `None` """ if text is not None and not isinstance(text, str): raise TypeError(f"Expected type {str.__name__} or None, but got {type(text).__name__}.") _lib.PtxPdfContent_TextGenerator_ShowW.argtypes = [c_void_p, c_wchar_p] _lib.PtxPdfContent_TextGenerator_ShowW.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_ShowW(self._handle, _string_to_utf16(text)): _NativeBase._throw_last_error(False)
[docs] def show_line(self, text: Optional[str]) -> None: """ Show a text string and go to the next line. Args: text (Optional[str]): the text to be shown Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the `text` argument is `None` """ if text is not None and not isinstance(text, str): raise TypeError(f"Expected type {str.__name__} or None, but got {type(text).__name__}.") _lib.PtxPdfContent_TextGenerator_ShowLineW.argtypes = [c_void_p, c_wchar_p] _lib.PtxPdfContent_TextGenerator_ShowLineW.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_ShowLineW(self._handle, _string_to_utf16(text)): _NativeBase._throw_last_error(False)
[docs] def move_to(self, target: Point) -> None: """ Move the current position. This also also sets the beginning of the current line to the specified position, which will affect the :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show_line` method. Args: target (pdftools_toolbox.geometry.real.point.Point): the target position Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ from pdftools_toolbox.geometry.real.point import Point if not isinstance(target, Point): raise TypeError(f"Expected type {Point.__name__}, but got {type(target).__name__}.") _lib.PtxPdfContent_TextGenerator_MoveTo.argtypes = [c_void_p, POINTER(Point)] _lib.PtxPdfContent_TextGenerator_MoveTo.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_MoveTo(self._handle, target): _NativeBase._throw_last_error(False)
@property def fill(self) -> Optional[Paint]: raise AttributeError("The 'fill' property is write-only.") @fill.setter def fill(self, val: Optional[Paint]) -> None: """ The paint for filling The fill paint or `None` if the text should not be filled. Args: val (Optional[pdftools_toolbox.pdf.content.paint.Paint]): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the given :class:`pdftools_toolbox.pdf.content.paint.Paint` object has already been closed. ValueError: if the given :class:`pdftools_toolbox.pdf.content.paint.Paint` object belongs to a different document. """ from pdftools_toolbox.pdf.content.paint import Paint if val is not None and not isinstance(val, Paint): raise TypeError(f"Expected type {Paint.__name__} or None, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetFill.argtypes = [c_void_p, c_void_p] _lib.PtxPdfContent_TextGenerator_SetFill.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetFill(self._handle, val._handle if val is not None else None): _NativeBase._throw_last_error(False) @property def stroke(self) -> Optional[Stroke]: raise AttributeError("The 'stroke' property is write-only.") @stroke.setter def stroke(self, val: Optional[Stroke]) -> None: """ The stroke properties The stroke properties or `None` if the text should not be stroked. Args: val (Optional[pdftools_toolbox.pdf.content.stroke.Stroke]): property value Raises: StateError: if the object has already been closed. StateError: if the underlying text object has already been closed. ValueError: if the document associated with the given :class:`pdftools_toolbox.pdf.content.stroke.Stroke` object has already been closed ValueError: if the given :class:`pdftools_toolbox.pdf.content.stroke.Stroke` object argument belongs to a different document. """ from pdftools_toolbox.pdf.content.stroke import Stroke if val is not None and not isinstance(val, Stroke): raise TypeError(f"Expected type {Stroke.__name__} or None, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetStroke.argtypes = [c_void_p, c_void_p] _lib.PtxPdfContent_TextGenerator_SetStroke.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetStroke(self._handle, val._handle if val is not None else None): _NativeBase._throw_last_error(False) @property def font(self) -> Font: raise AttributeError("The 'font' property is write-only.") @font.setter def font(self, val: Font) -> None: """ the current font. The font is used for all subsequent :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show` and :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show_line` calls. Args: val (pdftools_toolbox.pdf.content.font.Font): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the document associated with the given :class:`pdftools_toolbox.pdf.content.font.Font` object has already been closed ValueError: if the given :class:`pdftools_toolbox.pdf.content.font.Font` object is associated with a different document ValueError: if the given :class:`pdftools_toolbox.pdf.content.font.Font` object has been obtained from :attr:`pdftools_toolbox.pdf.content.text_fragment.TextFragment.font` """ from pdftools_toolbox.pdf.content.font import Font if not isinstance(val, Font): raise TypeError(f"Expected type {Font.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetFont.argtypes = [c_void_p, c_void_p] _lib.PtxPdfContent_TextGenerator_SetFont.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetFont(self._handle, val._handle): _NativeBase._throw_last_error(False) @property def font_size(self) -> float: raise AttributeError("The 'font_size' property is write-only.") @font_size.setter def font_size(self, val: float) -> None: """ the current font size. The font size is used for all subsequent :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show` and :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show_line` calls. Note that this sets the font size only. Also use :attr:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.leading` to set the leading. Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed ValueError: if the given value is smaller than 0. """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetFontSize.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetFontSize.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetFontSize(self._handle, val): _NativeBase._throw_last_error(False) @property def character_spacing(self) -> float: raise AttributeError("The 'character_spacing' property is write-only.") @character_spacing.setter def character_spacing(self, val: float) -> None: """ the current character spacing. When the glyph for each character in the string is rendered, the character spacing is added to the horizontal or vertical component of the glyph’s displacement, depending on the writing mode. It is subject to scaling by the horizontal scaling if the writing mode is horizontal. Default value: 0 Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetCharacterSpacing.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetCharacterSpacing.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetCharacterSpacing(self._handle, val): _NativeBase._throw_last_error(False) @property def word_spacing(self) -> float: raise AttributeError("The 'word_spacing' property is write-only.") @word_spacing.setter def word_spacing(self, val: float) -> None: """ the current word spacing. Word spacing works the same way as character spacing, but applies only to the space character, code 32. Default value: 0 Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetWordSpacing.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetWordSpacing.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetWordSpacing(self._handle, val): _NativeBase._throw_last_error(False) @property def horizontal_scaling(self) -> float: raise AttributeError("The 'horizontal_scaling' property is write-only.") @horizontal_scaling.setter def horizontal_scaling(self, val: float) -> None: """ the current horizontal scaling. The horizontal scaling parameter adjusts the width of glyphs by stretching or compressing them in the horizontal direction. Its value is specified relative to the normal width of the glyphs, with 1 being the normal width. Default value: 1 Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetHorizontalScaling.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetHorizontalScaling.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetHorizontalScaling(self._handle, val): _NativeBase._throw_last_error(False) @property def leading(self) -> float: raise AttributeError("The 'leading' property is write-only.") @leading.setter def leading(self, val: float) -> None: """ the current leading. The leading parameter specifies the vertical distance between the baselines of adjacent lines of text. It affects only the method :meth:`pdftools_toolbox.pdf.content.text_generator.TextGenerator.show_line` . Default value: 1.2 times the initial font size. See also :attr:`pdftools_toolbox.pdf.content.font.Font.leading` . Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetLeading.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetLeading.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetLeading(self._handle, val): _NativeBase._throw_last_error(False) @property def rise(self) -> float: raise AttributeError("The 'rise' property is write-only.") @rise.setter def rise(self, val: float) -> None: """ the current rise of the baseline. Text rise specifies the distance to move the baseline up or down from its default location. Positive values of text rise move the baseline up. Adjustments to the baseline are useful for drawing superscripts or subscripts. Default is 0 Args: val (float): property value Raises: StateError: if the object has already been closed StateError: if the underlying text object has already been closed """ if not isinstance(val, Number): raise TypeError(f"Expected type {Number.__name__}, but got {type(val).__name__}.") _lib.PtxPdfContent_TextGenerator_SetRise.argtypes = [c_void_p, c_double] _lib.PtxPdfContent_TextGenerator_SetRise.restype = c_bool if not _lib.PtxPdfContent_TextGenerator_SetRise(self._handle, val): _NativeBase._throw_last_error(False) def __exit__(self, exc_type, exc_value, traceback): _lib.PtxPdfContent_TextGenerator_Close.argtypes = [c_void_p] _lib.PtxPdfContent_TextGenerator_Close.restype = c_bool if self._handle is not None: try: if not _lib.PtxPdfContent_TextGenerator_Close(self._handle): super()._throw_last_error() finally: self._handle = None # Invalidate the handle def __enter__(self): return self @staticmethod def _create_dynamic_type(handle): return TextGenerator._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 = TextGenerator.__new__(cls) # Bypass __init__ instance._initialize(handle) return instance def _initialize(self, handle): super()._initialize(handle)