[fpdf2] Update to 2.8.2 (#13264)

This commit is contained in:
Sebastian Rittau
2024-12-23 01:49:46 +01:00
committed by GitHub
parent 7c0974c0cd
commit 619e8f3680
14 changed files with 219 additions and 30 deletions

View File

@@ -1,4 +1,4 @@
version = "2.8.1"
version = "2.8.2"
upstream_repository = "https://github.com/PyFPDF/fpdf2"
requires = ["Pillow>=10.3.0"]

View File

@@ -6,6 +6,7 @@ from .fpdf import FPDF as FPDF, FPDFException as FPDFException, TitleStyle as Ti
from .html import HTML2FPDF as HTML2FPDF, HTMLMixin as HTMLMixin
from .prefs import ViewerPreferences as ViewerPreferences
from .template import FlexTemplate as FlexTemplate, Template as Template
from .util import get_scale_factor as get_scale_factor
__license__: str
__version__: str
@@ -31,4 +32,5 @@ __all__ = [
"HTML2FPDF",
"FPDF_VERSION",
"FPDF_FONT_DIR",
"get_scale_factor",
]

View File

@@ -15,7 +15,7 @@ class AnnotationMixin:
border: str
f_t: Name | None
v: Incomplete | None
f: int # AnnotationFlags
f: int # AnnotationFlags bitmask
contents: str | None
a: Action | None
dest: Destination | None
@@ -35,7 +35,7 @@ class AnnotationMixin:
y: int,
width: int,
height: int,
flags: tuple[AnnotationFlag, ...] = ...,
flags: tuple[AnnotationFlag | str, ...] = ...,
contents: str | None = None,
dest: Destination | None = None,
action: Action | None = None,

View File

@@ -10,7 +10,7 @@ class SignatureFlag(IntEnum):
class CoerciveEnum(Enum): # type: ignore[misc] # Enum with no members
@classmethod
def coerce(cls, value: Self | str) -> Self: ...
def coerce(cls, value: Self | str, case_sensitive: bool = False) -> Self: ...
class CoerciveIntEnum(IntEnum): # type: ignore[misc] # Enum with no members
@classmethod
@@ -38,6 +38,9 @@ class Align(CoerciveEnum):
R = "RIGHT"
J = "JUSTIFY"
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]
_Align: TypeAlias = Align | Literal["CENTER", "X_CENTER", "LEFT", "RIGHT", "JUSTIFY"] # noqa: Y047
class VAlign(CoerciveEnum):
@@ -45,6 +48,9 @@ class VAlign(CoerciveEnum):
T = "TOP"
B = "BOTTOM"
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]
class TextEmphasis(CoerciveIntFlag):
NONE = 0
B = 1
@@ -70,6 +76,15 @@ class TableBordersLayout(CoerciveEnum):
NO_HORIZONTAL_LINES = "NO_HORIZONTAL_LINES"
SINGLE_TOP_LINE = "SINGLE_TOP_LINE"
class CellBordersLayout(CoerciveIntFlag):
NONE = 0
LEFT = 1
RIGHT = 2
TOP = 4
BOTTOM = 8
ALL = 15
INHERIT = 16
class TableCellFillMode(CoerciveEnum):
NONE = "NONE"
ALL = "ALL"
@@ -79,6 +94,8 @@ class TableCellFillMode(CoerciveEnum):
EVEN_COLUMNS = "EVEN_COLUMNS"
def should_fill_cell(self, i: int, j: int) -> bool: ...
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]
class TableSpan(CoerciveEnum):
ROW = "ROW"
@@ -98,6 +115,8 @@ class RenderStyle(CoerciveEnum):
def is_draw(self) -> bool: ...
@property
def is_fill(self) -> bool: ...
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]
class TextMode(CoerciveIntEnum):
FILL = 0
@@ -276,3 +295,30 @@ class TextDirection(CoerciveEnum):
RTL = "RTL"
TTB = "TTB"
BTT = "BTT"
class PageLabelStyle(CoerciveEnum):
NUMBER = "D"
UPPER_ROMAN = "R"
LOWER_ROMAN = "r"
UPPER_LETTER = "A"
LOWER_LETTER = "a"
NONE = None
class Duplex(CoerciveEnum):
SIMPLEX = "Simplex"
DUPLEX_FLIP_SHORT_EDGE = "DuplexFlipShortEdge"
DUPLEX_FLIP_LONG_EDGE = "DuplexFlipLongEdge"
class PageBoundaries(CoerciveEnum):
ART_BOX = "ArtBox"
BLEED_BOX = "BleedBox"
CROP_BOX = "CropBox"
MEDIA_BOX = "MediaBox"
TRIM_BOX = "TrimBox"
class PageOrientation(CoerciveEnum):
PORTRAIT = "P"
LANDSCAPE = "L"
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]

View File

@@ -6,7 +6,7 @@ from typing import Final, overload
from typing_extensions import Self, deprecated
from .drawing import DeviceGray, DeviceRGB, Number
from .enums import TextEmphasis
from .enums import Align, TextEmphasis
from .syntax import PDFObject
# Only defined if harfbuzz is installed.
@@ -41,7 +41,7 @@ class FontFace:
class TextStyle(FontFace):
t_margin: int
l_margin: int
l_margin: int | Align
b_margin: int
def __init__(
self,
@@ -52,7 +52,7 @@ class TextStyle(FontFace):
fill_color: int | tuple[int, int, int] | None = None,
underline: bool = False,
t_margin: int | None = None,
l_margin: int | None = None,
l_margin: int | Align | str | None = None,
b_margin: int | None = None,
): ...
def replace( # type: ignore[override]

View File

@@ -9,6 +9,7 @@ from typing import Any, ClassVar, Final, Literal, NamedTuple, overload
from typing_extensions import TypeAlias, deprecated
from fpdf import ViewerPreferences
from fpdf.outline import OutlineSection
from PIL import Image
from .annotations import AnnotationDict, PDFEmbeddedFile
@@ -22,8 +23,10 @@ from .enums import (
EncryptionMethod,
FileAttachmentAnnotationName,
MethodReturnValue,
PageLabelStyle,
PageLayout,
PageMode,
PageOrientation,
PathPaintRule,
RenderStyle,
TableBordersLayout,
@@ -55,6 +58,7 @@ from .recorder import FPDFRecorder
from .structure_tree import StructureTreeBuilder
from .syntax import DestinationXYZ
from .table import Table
from .transitions import Transition
from .util import Padding, _Unit
__all__ = [
@@ -79,9 +83,10 @@ FPDF_VERSION: Final[str]
PAGE_FORMATS: dict[_Format, tuple[float, float]]
class ToCPlaceholder(NamedTuple):
render_function: Callable[[FPDF, Any], object]
render_function: Callable[[FPDF, list[OutlineSection]], object]
start_page: int
y: int
page_orientation: str
pages: int = 1
def get_page_format(format: _Format | tuple[float, float], k: float | None = None) -> tuple[float, float]: ...
@@ -116,6 +121,9 @@ class FPDF(GraphicsStateMixin):
oversized_images: Incomplete | None
oversized_images_ratio: float
struct_builder: StructureTreeBuilder
toc_placeholder: ToCPlaceholder | None
in_toc_rendering: bool
title: str | None
section_title_styles: dict[int, TextStyle]
core_fonts: dict[str, str]
@@ -142,7 +150,7 @@ class FPDF(GraphicsStateMixin):
buffer: bytearray | None
# Set during call to _set_orientation(), called from __init__().
cur_orientation: Literal["P", "L"]
cur_orientation: PageOrientation
w_pt: float
h_pt: float
w: float
@@ -205,7 +213,6 @@ class FPDF(GraphicsStateMixin):
language: str | None = None,
) -> None: ...
def set_compression(self, compress: bool) -> None: ...
title: str
def set_title(self, title: str) -> None: ...
lang: str
def set_lang(self, lang: str) -> None: ...
@@ -224,17 +231,24 @@ class FPDF(GraphicsStateMixin):
def set_doc_option(self, opt: str, value: str) -> None: ...
def set_image_filter(self, image_filter: str) -> None: ...
def alias_nb_pages(self, alias: str = "{nb}") -> None: ...
def set_page_label(
self, label_style: PageLabelStyle | str | None = None, label_prefix: str | None = None, label_start: int | None = None
) -> None: ...
def add_page(
self,
orientation: _Orientation = "",
format: _Format | tuple[float, float] = "",
same: bool = False,
duration: int = 0,
transition: Incomplete | None = None,
duration: float = 0,
transition: Transition | None = None,
label_style: PageLabelStyle | str | None = None,
label_prefix: str | None = None,
label_start: int | None = None,
) -> None: ...
def header(self) -> None: ...
def footer(self) -> None: ...
def page_no(self) -> int: ...
def get_page_label(self) -> str: ...
def set_draw_color(self, r: int, g: int = -1, b: int = -1) -> None: ...
def set_fill_color(self, r: int, g: int = -1, b: int = -1) -> None: ...
def set_text_color(self, r: int, g: int = -1, b: int = -1) -> None: ...
@@ -337,7 +351,16 @@ class FPDF(GraphicsStateMixin):
def add_link(self, y: float = 0, x: float = 0, page: int = -1, zoom: float | Literal["null"] = "null") -> int: ...
def set_link(self, link, y: float = 0, x: float = 0, page: int = -1, zoom: float | Literal["null"] = "null") -> None: ...
def link(
self, x: float, y: float, w: float, h: float, link: str | int, alt_text: str | None = None, border_width: int = 0
self,
x: float,
y: float,
w: float,
h: float,
link: str | int,
alt_text: str | None = None,
*,
border_width: int = 0,
**kwargs, # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def embed_file(
self,
@@ -377,7 +400,9 @@ class FPDF(GraphicsStateMixin):
w: float = 1,
h: float = 1,
name: AnnotationName | str | None = None,
*,
flags: tuple[AnnotationFlag, ...] | tuple[str, ...] = ...,
**kwargs, # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def free_text_annotation(
self,
@@ -386,16 +411,22 @@ class FPDF(GraphicsStateMixin):
y: float | None = None,
w: float | None = None,
h: float | None = None,
*,
flags: tuple[AnnotationFlag, ...] | tuple[str, ...] = ...,
**kwargs, # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def add_action(
self, action, x: float, y: float, w: float, h: float, **kwargs # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def add_action(self, action, x: float, y: float, w: float, h: float) -> None: ...
def highlight(
self,
text: str,
title: str = "",
type: TextMarkupType | str = "Highlight",
color: tuple[float, float, float] = (1, 1, 0),
modification_time: datetime.datetime | None = None,
*,
title: str | None = None,
**kwargs, # accepts AnnotationDict arguments
) -> _GeneratorContextManager[None]: ...
add_highlight = highlight
def add_text_markup_annotation(
@@ -403,18 +434,22 @@ class FPDF(GraphicsStateMixin):
type: str,
text: str,
quad_points: Sequence[int],
title: str = "",
color: tuple[float, float, float] = (1, 1, 0),
modification_time: datetime.datetime | None = None,
page: int | None = None,
*,
title: str | None = None,
**kwargs, # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def ink_annotation(
self,
coords: Iterable[Incomplete],
contents: str = "",
title: str = "",
text: str = "",
color: Sequence[float] = (1, 1, 0),
border_width: int = 1,
border_width: float = 1,
*,
title: str | None = None,
**kwargs, # accepts AnnotationDict arguments
) -> AnnotationDict: ...
def text(self, x: float, y: float, text: str = "") -> None: ...
def rotate(self, angle: float, x: float | None = None, y: float | None = None) -> None: ...
@@ -582,7 +617,9 @@ class FPDF(GraphicsStateMixin):
def round_clip(self, x: float, y: float, r: float) -> _GeneratorContextManager[None]: ...
def unbreakable(self) -> _GeneratorContextManager[FPDFRecorder]: ...
def offset_rendering(self) -> _GeneratorContextManager[FPDFRecorder]: ...
def insert_toc_placeholder(self, render_toc_function, pages: int = 1) -> None: ...
def insert_toc_placeholder(
self, render_toc_function: Callable[[FPDF, list[OutlineSection]], object], pages: int = 1, allow_extra_pages: bool = False
) -> None: ...
def set_section_title_styles(
self,
level0: TextStyle,
@@ -594,6 +631,7 @@ class FPDF(GraphicsStateMixin):
level6: TextStyle | None = None,
) -> None: ...
def start_section(self, name: str, level: int = 0, strict: bool = True) -> None: ...
def use_text_style(self, text_style: TextStyle) -> _GeneratorContextManager[None]: ...
def use_font_face(self, font_face: FontFace) -> _GeneratorContextManager[None]: ...
def table(
self,

View File

@@ -55,6 +55,7 @@ class HTML2FPDF(HTMLParser):
ol_type: list[_OLType]
bullet: list[Incomplete]
heading_level: Incomplete | None
render_title_tag: bool
table_line_separators: bool
table: Table | None
table_row: Row | None
@@ -78,6 +79,7 @@ class HTML2FPDF(HTMLParser):
tag_indents: dict[str, int] | None = None,
tag_styles: Mapping[str, FontFace] | None = None,
font_family: str = "times",
render_title_tag: bool = False,
) -> None: ...
def handle_data(self, data) -> None: ...
def handle_starttag(self, tag, attrs) -> None: ...

View File

@@ -1,9 +1,10 @@
from _typeshed import Incomplete
from collections.abc import Iterable
from dataclasses import dataclass
from io import BytesIO
from logging import Logger
from types import TracebackType
from typing import Any, Literal
from typing import Any, Final, Literal
from typing_extensions import TypeAlias
from PIL import Image
@@ -11,7 +12,7 @@ from PIL import Image
from .image_datastructures import ImageCache, ImageInfo, VectorImageInfo
from .svg import SVGObject
_ImageFilter: TypeAlias = Literal["AUTO", "FlateDecode", "DCTDecode", "JPXDecode"]
_ImageFilter: TypeAlias = Literal["AUTO", "FlateDecode", "DCTDecode", "JPXDecode", "LZWDecode"]
RESAMPLE: Image.Resampling
@@ -25,6 +26,11 @@ SETTINGS: ImageSettings
TIFFBitRevTable: list[int]
LZW_CLEAR_TABLE_MARKER: Final = 256
LZW_EOD_MARKER: Final = 257
LZW_INITIAL_BITS_PER_CODE: Final = 9
LZW_MAX_BITS_PER_CODE: Final = 12
def preload_image(
image_cache: ImageCache, name: str | BytesIO | Image.Image, dims: tuple[float, float] | None = None
) -> tuple[str, BytesIO | Image.Image | None, ImageInfo]: ...
@@ -50,3 +56,5 @@ class temp_attr:
def ccitt_payload_location_from_pil(img: Image.Image) -> tuple[int, int]: ...
def transcode_monochrome(img: Image.Image): ...
def pack_codes_into_bytes(codes: Iterable[int]) -> bytes: ...
def clear_table() -> tuple[dict[bytes, int], int, int, int]: ...

View File

@@ -1,6 +1,7 @@
from _typeshed import Incomplete
from collections.abc import Callable, Sequence
from typing import Final, NamedTuple
from uuid import UUID
from .enums import Align, TextDirection, WrapMode
@@ -68,12 +69,18 @@ class Fragment:
def trim(self, index: int) -> None: ...
def __eq__(self, other: Fragment) -> bool: ... # type: ignore[override]
def get_width(self, start: int = 0, end: int | None = None, chars: str | None = None, initial_cs: bool = True) -> float: ...
def has_same_style(self, other: Fragment) -> bool: ...
def get_character_width(self, character: str, print_sh: bool = False, initial_cs: bool = True): ...
def render_pdf_text(self, frag_ws, current_ws, word_spacing, adjust_x, adjust_y, h): ...
def render_pdf_text_ttf(self, frag_ws, word_spacing): ...
def render_with_text_shaping(self, pos_x: float, pos_y: float, h: float, word_spacing: float) -> str: ...
def render_pdf_text_core(self, frag_ws, current_ws): ...
class TotalPagesSubstitutionFragment(Fragment):
uuid: UUID
def get_placeholder_string(self) -> str: ...
def render_text_substitution(self, replacement_text: str) -> str: ...
class TextLine(NamedTuple):
fragments: tuple[Fragment, ...]
text_width: float
@@ -120,13 +127,12 @@ class CurrentLine:
self,
character: str,
character_width: float,
graphics_state: dict[str, Incomplete],
k: float,
original_fragment: Fragment,
original_fragment_index: int,
original_character_index: int,
height: float,
url: str | None = None,
): ...
) -> None: ...
def trim_trailing_spaces(self) -> None: ...
def manual_break(self, align: Align, trailing_nl: bool = False, trailing_form_feed: bool = False) -> TextLine: ...
def automatic_break_possible(self) -> bool: ...

View File

@@ -2,6 +2,8 @@ from _typeshed import Incomplete
from collections.abc import Generator, Iterable
from typing import NamedTuple
from .fonts import TextStyle
from .fpdf import FPDF
from .structure_tree import StructElem
from .syntax import Destination, PDFObject, PDFString
@@ -34,3 +36,22 @@ class OutlineDictionary(PDFObject):
def build_outline_objs(
sections: Iterable[Incomplete],
) -> Generator[Incomplete, None, list[OutlineDictionary | OutlineItemDictionary]]: ...
class TableOfContents:
text_style: TextStyle
use_section_title_styles: bool
level_indent: float
line_spacing: float
ignore_pages_before_toc: bool
def __init__(
self,
text_style: TextStyle | None = None,
use_section_title_styles: bool = False,
level_indent: float = 7.5,
line_spacing: float = 1.5,
ignore_pages_before_toc: bool = True,
) -> None: ...
def get_text_style(self, pdf: FPDF, item: OutlineSection) -> TextStyle: ...
def render_toc_item(self, pdf: FPDF, item: OutlineSection) -> None: ...
def render_toc(self, pdf: FPDF, outline: Iterable[OutlineSection]) -> None: ...

View File

@@ -5,8 +5,10 @@ from typing import Final
from .annotations import AnnotationDict
from .encryption import StandardSecurityHandler
from .enums import PageLabelStyle
from .fpdf import FPDF
from .image_datastructures import RasterImageInfo
from .line_break import TotalPagesSubstitutionFragment
from .syntax import Name, PDFArray, PDFContentStream, PDFObject, PDFString
LOGGER: Logger
@@ -138,6 +140,18 @@ class PDFICCPObject(PDFContentStream):
alternate: Name
def __init__(self, contents: bytes, n, alternate: str) -> None: ...
class PDFPageLabel:
st: int
def __init__(self, label_style: PageLabelStyle, label_prefix: str, label_start: int) -> None: ...
@property
def s(self) -> Name: ...
@property
def p(self) -> PDFString: ...
def serialize(self) -> dict[str, str]: ...
def get_style(self) -> PageLabelStyle: ...
def get_prefix(self) -> str: ...
def get_start(self) -> int: ...
class PDFPage(PDFObject):
type: Name
contents: Incomplete
@@ -153,6 +167,11 @@ class PDFPage(PDFObject):
def index(self): ...
def dimensions(self) -> tuple[float | None, float | None]: ...
def set_dimensions(self, width_pt: float | None, height_pt: float | None) -> None: ...
def set_page_label(self, previous_page_label: PDFPageLabel, page_label: PDFPageLabel) -> None: ...
def get_page_label(self) -> PDFPageLabel: ...
def get_label(self) -> str: ...
def get_text_substitutions(self) -> list[TotalPagesSubstitutionFragment]: ...
def add_text_substitution(self, fragment: TotalPagesSubstitutionFragment) -> None: ...
class PDFPagesRoot(PDFObject):
type: Name

View File

@@ -1,4 +1,4 @@
from .enums import PageMode
from .enums import Duplex, PageBoundaries, PageMode, TextDirection
class ViewerPreferences:
hide_toolbar: bool
@@ -7,6 +7,8 @@ class ViewerPreferences:
fit_window: bool
center_window: bool
display_doc_title: bool
num_copies: int | None
print_page_range: list[int] | None
def __init__(
self,
hide_toolbar: bool = False,
@@ -15,10 +17,42 @@ class ViewerPreferences:
fit_window: bool = False,
center_window: bool = False,
display_doc_title: bool = False,
non_full_screen_page_mode: PageMode | str = ...,
non_full_screen_page_mode: PageMode | str | None = ...,
num_copies: int | None = None,
print_page_range: list[int] | None = None,
direction: TextDirection | str | None = None,
duplex: Duplex | str | None = None,
view_area: PageBoundaries | None = None,
view_clip: PageBoundaries | None = None,
print_area: PageBoundaries | None = None,
print_clip: PageBoundaries | None = None,
) -> None: ...
@property
def non_full_screen_page_mode(self): ...
def non_full_screen_page_mode(self) -> PageMode | None: ...
@non_full_screen_page_mode.setter
def non_full_screen_page_mode(self, page_mode) -> None: ...
def non_full_screen_page_mode(self, page_mode: PageMode | str | None) -> None: ...
@property
def direction(self) -> TextDirection | None: ...
@direction.setter
def direction(self, direction: TextDirection | str | None) -> None: ...
@property
def duplex(self) -> Duplex | None: ...
@duplex.setter
def duplex(self, duplex: Duplex | str | None) -> None: ...
@property
def view_area(self) -> PageBoundaries | None: ...
@view_area.setter
def view_area(self, view_area: PageBoundaries | str | None) -> None: ...
@property
def view_clip(self) -> PageBoundaries | None: ...
@view_clip.setter
def view_clip(self, view_area: PageBoundaries | str | None) -> None: ...
@property
def print_area(self) -> PageBoundaries | None: ...
@print_area.setter
def print_area(self, view_area: PageBoundaries | str | None) -> None: ...
@property
def print_clip(self) -> PageBoundaries | None: ...
@print_clip.setter
def print_clip(self, view_area: PageBoundaries | str | None) -> None: ...
def serialize(self) -> str: ...

View File

@@ -7,7 +7,16 @@ from typing import Literal, overload
from PIL import Image
from .drawing import DeviceGray, DeviceRGB
from .enums import Align, TableBordersLayout, TableCellFillMode, TableHeadingsDisplay, TableSpan, VAlign, WrapMode
from .enums import (
Align,
CellBordersLayout,
TableBordersLayout,
TableCellFillMode,
TableHeadingsDisplay,
TableSpan,
VAlign,
WrapMode,
)
from .fonts import FontFace
from .fpdf import FPDF
from .image_datastructures import _TextAlign
@@ -70,6 +79,7 @@ class Row:
rowspan: int = 1,
padding: tuple[float, ...] | None = None,
link: str | int | None = None,
border: CellBordersLayout | int = ...,
) -> str: ...
@overload
def cell(
@@ -84,6 +94,7 @@ class Row:
rowspan: int = 1,
padding: tuple[float, ...] | None = None,
link: str | int | None = None,
border: CellBordersLayout | int = ...,
) -> TableSpan: ...
@dataclass
@@ -98,6 +109,7 @@ class Cell:
rowspan: int
padding: int | tuple[float, ...] | None
link: str | int | None
border: CellBordersLayout | None
def write(self, text, align: Incomplete | None = None): ...

View File

@@ -27,6 +27,7 @@ def convert_unit(
ROMAN_NUMERAL_MAP: Final[tuple[tuple[str, int], ...]]
def int2roman(n: int) -> str: ...
def int_to_letters(n: int) -> str: ...
def print_mem_usage(prefix: str) -> None: ...
def get_mem_usage(prefix: str) -> str: ...
def get_process_rss() -> str: ...