[fpdf2] Update to 2.8.3 (#13871)

This commit is contained in:
Sebastian Rittau
2025-04-25 12:16:28 +02:00
committed by GitHub
parent e07284f7d9
commit dd8532343d
15 changed files with 320 additions and 41 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
version = "2.8.2"
version = "2.8.3"
upstream_repository = "https://github.com/PyFPDF/fpdf2"
requires = ["Pillow>=10.3.0"]
+4 -1
View File
@@ -2,7 +2,7 @@
from abc import ABCMeta, abstractmethod
from collections.abc import Mapping
from logging import Logger
from typing import Protocol
from typing import Any, Protocol
from typing_extensions import TypeAlias
# from fonttools.ttLib.ttGlyphSet
@@ -13,6 +13,9 @@ class _TTGlyph(Protocol):
_TTGlyphSet: TypeAlias = Mapping[str, _TTGlyph] # Simplified for our needs
# fonttools.ttLib.TTFont
_TTFont: TypeAlias = Any # noqa: Y047
# from fontTools.misc.loggingTools
class LogMixin:
+16
View File
@@ -56,6 +56,7 @@ class TextEmphasis(CoerciveIntFlag):
B = 1
I = 2
U = 4
S = 8
@property
def style(self) -> str: ...
@@ -296,6 +297,11 @@ class TextDirection(CoerciveEnum):
TTB = "TTB"
BTT = "BTT"
class OutputIntentSubType(CoerciveEnum):
PDFX = "GTS_PDFX"
PDFA = "GTS_PDFA1"
ISOPDF = "ISO_PDFE1"
class PageLabelStyle(CoerciveEnum):
NUMBER = "D"
UPPER_ROMAN = "R"
@@ -322,3 +328,13 @@ class PageOrientation(CoerciveEnum):
@classmethod
def coerce(cls, value: Self | str) -> Self: ... # type: ignore[override]
class PDFResourceType(Enum):
EXT_G_STATE = "ExtGState"
COLOR_SPACE = "ColorSpace"
PATTERN = "Pattern"
SHADDING = "Shading"
X_OBJECT = "XObject"
FONT = "Font"
PROC_SET = "ProcSet"
PROPERTIES = "Properties"
+34 -18
View File
@@ -1,14 +1,19 @@
import dataclasses
from _typeshed import Incomplete
from _typeshed import Incomplete, Unused
from collections import defaultdict
from collections.abc import Generator
from dataclasses import dataclass
from logging import Logger
from typing import Final, overload
from typing_extensions import Self, deprecated
from ._fonttools_shims import _TTFont
from .drawing import DeviceGray, DeviceRGB, Number
from .enums import Align, TextEmphasis
from .syntax import PDFObject
LOGGER: Logger
# Only defined if harfbuzz is installed.
class HarfBuzzFont(Incomplete): # derives from uharfbuzz.Font
def __deepcopy__(self, _memo: object) -> Self: ...
@@ -73,37 +78,48 @@ class TitleStyle(TextStyle): ...
__pdoc__: Final[dict[str, bool]]
class _FontMixin:
class CoreFont:
i: int
type: str
name: str
up: int
ut: int
sp: int
ss: int
cw: int
fontkey: str
emphasis: TextEmphasis
def encode_text(self, text: str): ...
class CoreFont(_FontMixin):
def __init__(self, fpdf, fontkey: str, style: int) -> None: ...
def get_text_width(self, text: str, font_size_pt: int, _): ...
def get_text_width(self, text: str, font_size_pt: int, _: Unused) -> float: ...
def encode_text(self, text: str) -> str: ...
class TTFFont(_FontMixin):
class TTFFont:
i: int
type: str
ttffile: Incomplete
ttfont: Incomplete
scale: Incomplete
desc: Incomplete
fontkey: str
ttfont: _TTFont
scale: float
desc: PDFFontDescriptor
cw: defaultdict[str, int]
cmap: Incomplete
glyph_ids: Incomplete
missing_glyphs: Incomplete
subset: Incomplete
glyph_ids: dict[Incomplete, Incomplete]
missing_glyphs: list[Incomplete]
name: str
up: int
ut: int
sp: int
ss: int
emphasis: TextEmphasis
subset: SubsetMap
hbfont: HarfBuzzFont | None # Not always defined.
def __init__(self, fpdf, font_file_path, fontkey: str, style: int) -> None: ...
def close(self) -> None: ...
def get_text_width(self, text: str, font_size_pt: int, text_shaping_parms): ...
def shaped_text_width(self, text: str, font_size_pt: int, text_shaping_parms): ...
def perform_harfbuzz_shaping(self, text: str, font_size_pt: int, text_shaping_parms): ...
def shape_text(self, text: str, font_size_pt: int, text_shaping_parms): ...
def get_text_width(self, text: str, font_size_pt: int, text_shaping_params): ...
def shaped_text_width(self, text: str, font_size_pt: int, text_shaping_params): ...
def perform_harfbuzz_shaping(self, text: str, font_size_pt: int, text_shaping_params): ...
def encode_text(self, text: str) -> str: ...
def shape_text(self, text: str, font_size_pt: int, text_shaping_params): ...
class PDFFontDescriptor(PDFObject):
type: Incomplete
@@ -128,7 +144,7 @@ class Glyph:
class SubsetMap:
font: TTFFont
def __init__(self, font: TTFFont, identities: list[int]) -> None: ...
def __init__(self, font: TTFFont) -> None: ...
def __len__(self) -> int: ...
def items(self) -> Generator[Incomplete, None, None]: ...
def pick(self, unicode: int): ...
+53 -5
View File
@@ -23,6 +23,7 @@ from .enums import (
EncryptionMethod,
FileAttachmentAnnotationName,
MethodReturnValue,
OutputIntentSubType,
PageLabelStyle,
PageLayout,
PageMode,
@@ -53,7 +54,7 @@ from .image_datastructures import (
VectorImageInfo as VectorImageInfo,
_TextAlign,
)
from .output import OutputProducer, PDFPage
from .output import OutputProducer, PDFICCProfile, PDFPage
from .recorder import FPDFRecorder
from .structure_tree import StructureTreeBuilder
from .syntax import DestinationXYZ
@@ -77,7 +78,35 @@ __all__ = [
_Orientation: TypeAlias = Literal["", "portrait", "p", "P", "landscape", "l", "L"]
_Format: TypeAlias = Literal["", "a3", "A3", "a4", "A4", "a5", "A5", "letter", "Letter", "legal", "Legal"]
_FontStyle: TypeAlias = Literal["", "B", "I", "BI"]
_FontStyles: TypeAlias = Literal["", "B", "I", "U", "BU", "UB", "BI", "IB", "IU", "UI", "BIU", "BUI", "IBU", "IUB", "UBI", "UIB"]
_FontStyles: TypeAlias = Literal[
"",
"B",
"I",
"U",
"S",
"BU",
"UB",
"BI",
"IB",
"IU",
"UI",
"BS",
"SB",
"IS",
"SI",
"BIU",
"BUI",
"IBU",
"IUB",
"UBI",
"UIB",
"BIS",
"BSI",
"IBS",
"ISB",
"SBI",
"SIB",
]
FPDF_VERSION: Final[str]
PAGE_FORMATS: dict[_Format, tuple[float, float]]
@@ -88,12 +117,14 @@ class ToCPlaceholder(NamedTuple):
y: int
page_orientation: str
pages: int = 1
reset_page_indices: bool = True
def get_page_format(format: _Format | tuple[float, float], k: float | None = None) -> tuple[float, float]: ...
class FPDF(GraphicsStateMixin):
MARKDOWN_BOLD_MARKER: ClassVar[str]
MARKDOWN_ITALICS_MARKER: ClassVar[str]
MARKDOWN_STRIKETHROUGH_MARKER: ClassVar[str]
MARKDOWN_UNDERLINE_MARKER: ClassVar[str]
MARKDOWN_ESCAPE_CHARACTER: ClassVar[str]
MARKDOWN_LINK_REGEX: ClassVar[Pattern[str]]
@@ -145,7 +176,6 @@ class FPDF(GraphicsStateMixin):
compress: bool
pdf_version: str
creation_date: datetime.datetime
graphics_style_names_per_page_number: dict[int, set[str]]
buffer: bytearray | None
@@ -179,6 +209,19 @@ class FPDF(GraphicsStateMixin):
def is_ttf_font(self) -> bool: ...
@property
def page_mode(self) -> PageMode: ...
@page_mode.setter
def page_mode(self, page_mode: PageMode) -> None: ...
@property
def output_intents(self): ...
def add_output_intent(
self,
subtype: OutputIntentSubType,
output_condition_identifier: str | None = None,
output_condition: str | None = None,
registry_name: str | None = None,
dest_output_profile: PDFICCProfile | None = None,
info: str | None = None,
) -> None: ...
@property
def epw(self) -> float: ...
@property
@@ -336,6 +379,7 @@ class FPDF(GraphicsStateMixin):
closed: bool = False,
style: RenderStyle | Literal["D", "F", "DF", "FD"] | None = None,
) -> None: ...
def use_pattern(self, shading) -> _GeneratorContextManager[None]: ...
def add_font(
self,
family: str | None = None,
@@ -343,7 +387,7 @@ class FPDF(GraphicsStateMixin):
fname: str | PurePath | None = None,
uni: bool | Literal["DEPRECATED"] = "DEPRECATED",
) -> None: ...
def set_font(self, family: str | None = None, style: _FontStyles = "", size: int = 0) -> None: ...
def set_font(self, family: str | None = None, style: _FontStyles | TextEmphasis = "", size: int = 0) -> None: ...
def set_font_size(self, size: float) -> None: ...
def set_char_spacing(self, spacing: float) -> None: ...
def set_stretching(self, stretching: float) -> None: ...
@@ -618,7 +662,11 @@ class FPDF(GraphicsStateMixin):
def unbreakable(self) -> _GeneratorContextManager[FPDFRecorder]: ...
def offset_rendering(self) -> _GeneratorContextManager[FPDFRecorder]: ...
def insert_toc_placeholder(
self, render_toc_function: Callable[[FPDF, list[OutlineSection]], object], pages: int = 1, allow_extra_pages: bool = False
self,
render_toc_function: Callable[[FPDF, list[OutlineSection]], object],
pages: int = 1,
allow_extra_pages: bool = False,
reset_page_indices: bool = True,
) -> None: ...
def set_section_title_styles(
self,
+11 -1
View File
@@ -1,4 +1,4 @@
from typing import Any, ClassVar, Literal, TypedDict, type_check_only
from typing import Any, ClassVar, Final, Literal, TypedDict, type_check_only
from .drawing import DeviceGray, DeviceRGB
from .enums import TextMode
@@ -36,6 +36,10 @@ class GraphicsStateMixin:
@underline.setter
def underline(self, v: bool) -> None: ...
@property
def strikethrough(self) -> bool: ...
@strikethrough.setter
def strikethrough(self, v: bool) -> None: ...
@property
def font_style(self) -> str: ...
@font_style.setter
def font_style(self, v: str) -> None: ...
@@ -64,6 +68,10 @@ class GraphicsStateMixin:
@current_font.setter
def current_font(self, v: dict[str, Any]) -> None: ...
@property
def current_font_is_set_on_page(self) -> bool: ...
@current_font_is_set_on_page.setter
def current_font_is_set_on_page(self, v: bool) -> None: ...
@property
def dash_pattern(self) -> dict[str, float]: ...
@dash_pattern.setter
def dash_pattern(self, v: dict[str, float]) -> None: ...
@@ -116,3 +124,5 @@ class GraphicsStateMixin:
@text_shaping.setter
def text_shaping(self, v: _TextShaping | None) -> None: ...
def font_face(self) -> FontFace: ...
__pdoc__: Final[dict[str, bool]]
+9 -3
View File
@@ -43,7 +43,9 @@ class Fragment:
@property
def text_mode(self): ...
@property
def underline(self): ...
def underline(self) -> bool: ...
@property
def strikethrough(self) -> bool: ...
@property
def draw_color(self): ...
@property
@@ -90,6 +92,7 @@ class TextLine(NamedTuple):
max_width: float
trailing_nl: bool = False
trailing_form_feed: bool = False
indent: float = 0
def get_ordered_fragments(self) -> tuple[Fragment, ...]: ...
class SpaceHint(NamedTuple):
@@ -114,13 +117,14 @@ class HyphenHint(NamedTuple):
class CurrentLine:
max_width: float
print_sh: Incomplete
print_sh: bool
indent: float
fragments: list[Fragment]
height: int
number_of_spaces: int
space_break_hint: Incomplete
hyphen_break_hint: Incomplete
def __init__(self, max_width: float, print_sh: bool = False) -> None: ...
def __init__(self, max_width: float, print_sh: bool = False, indent: float = 0) -> None: ...
@property
def width(self) -> float: ...
def add_character(
@@ -150,6 +154,7 @@ class MultiLineBreak:
fragment_index: int
character_index: int
idx_last_forced_break: int | None
first_line_indent: float
def __init__(
self,
fragments: Sequence[Fragment],
@@ -160,5 +165,6 @@ class MultiLineBreak:
wrapmode: WrapMode = ...,
line_height: float = 1.0,
skip_leading_spaces: bool = False,
first_line_indent: float = 0,
) -> None: ...
def get_line(self) -> TextLine: ...
+3 -2
View File
@@ -1,13 +1,14 @@
from _typeshed import Incomplete
from collections.abc import Generator, Iterable
from typing import NamedTuple
from dataclasses import dataclass
from .fonts import TextStyle
from .fpdf import FPDF
from .structure_tree import StructElem
from .syntax import Destination, PDFObject, PDFString
class OutlineSection(NamedTuple):
@dataclass
class OutlineSection:
name: str
level: int
page_number: int
+37 -4
View File
@@ -5,7 +5,7 @@ from typing import Final
from .annotations import AnnotationDict
from .encryption import StandardSecurityHandler
from .enums import PageLabelStyle
from .enums import OutputIntentSubType, PageLabelStyle, PDFResourceType
from .fpdf import FPDF
from .image_datastructures import RasterImageInfo
from .line_break import TotalPagesSubstitutionFragment
@@ -86,6 +86,7 @@ class PDFCatalog(PDFObject):
metadata: Incomplete | None
names: Incomplete | None
outlines: Incomplete | None
output_intents: Incomplete | None
struct_tree_root: Incomplete | None
def __init__(
self,
@@ -100,7 +101,9 @@ class PDFResources(PDFObject):
font: Incomplete
x_object: Incomplete
ext_g_state: Incomplete
def __init__(self, proc_set, font, x_object, ext_g_state) -> None: ...
shading: Incomplete
pattern: Incomplete
def __init__(self, proc_set, font, x_object, ext_g_state, shading, pattern) -> None: ...
class PDFFontStream(PDFContentStream):
length1: int
@@ -135,7 +138,7 @@ class PDFXObject(PDFContentStream):
decode_parms: Incomplete | None = None,
) -> None: ...
class PDFICCPObject(PDFContentStream):
class PDFICCProfile(PDFContentStream):
n: Incomplete
alternate: Name
def __init__(self, contents: bytes, n, alternate: str) -> None: ...
@@ -164,7 +167,8 @@ class PDFPage(PDFObject):
resources: Incomplete | None
parent: Incomplete | None
def __init__(self, duration: Incomplete | None, transition, contents, index) -> None: ...
def index(self): ...
def index(self) -> int: ...
def set_index(self, i: int) -> None: ...
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: ...
@@ -192,6 +196,35 @@ class PDFXrefAndTrailer(ContentWithoutID):
def __init__(self, output_builder) -> None: ...
def serialize(self, _security_handler: StandardSecurityHandler | None = None) -> str: ...
class OutputIntentDictionary:
type: Name
s: Name
output_condition_identifier: PDFString | None
output_condition: PDFString | None
registry_name: PDFString | None
dest_output_profile: Incomplete | None
info: PDFString | None
def __init__(
self,
subtype: OutputIntentSubType | str,
output_condition_identifier: str,
output_condition: str | None = None,
registry_name: str | None = None,
dest_output_profile: PDFICCProfile | None = None,
info: str | None = None,
) -> None: ...
def serialize(self, _security_handler: StandardSecurityHandler | None = None, _obj_id: Incomplete | None = None): ...
class ResourceCatalog:
resources: defaultdict[PDFResourceType, dict[Incomplete, Incomplete]]
resources_per_page: defaultdict[tuple[int, PDFResourceType], set[Incomplete]]
def add(self, resource_type: PDFResourceType, resource, page_number: int) -> Incomplete | None: ...
def get_items(self, resource_type: PDFResourceType): ...
def get_resources_per_page(self, page_number: int, resource_type: PDFResourceType): ...
def get_used_resources(self, resource_type: PDFResourceType) -> set[Incomplete]: ...
class OutputProducer:
fpdf: FPDF
pdf_objs: list[Incomplete]
+104
View File
@@ -0,0 +1,104 @@
from _typeshed import Incomplete
from abc import ABC
from collections.abc import Iterable
from typing import Final, Literal
from .drawing import DeviceCMYK, DeviceGray, DeviceRGB
from .fpdf import FPDF
from .syntax import Name, PDFObject
class Pattern(PDFObject):
type: Name
pattern_type: int
def __init__(self, shading: LinearGradient | RadialGradient) -> None: ...
@property
def shading(self) -> str: ...
class Type2Function(PDFObject):
function_type: Final = 2
domain: str
c0: str
c1: str
n: int
def __init__(self, color_1, color_2) -> None: ...
class Type3Function(PDFObject):
function_type: Final = 3
domain: str
bounds: str
encode: str
n: int
def __init__(self, functions: Iterable[Incomplete], bounds: Iterable[Incomplete]) -> None: ...
@property
def functions(self) -> str: ...
class Shading(PDFObject):
shading_type: Literal[2, 3]
background: str | None
color_space: Name
coords: list[int]
function: str
extend: str
def __init__(
self,
shading_type: Literal[2, 3],
background: DeviceRGB | DeviceGray | DeviceCMYK | None,
color_space: str,
coords: list[int],
function: Type2Function | Type3Function,
extend_before: bool,
extend_after: bool,
) -> None: ...
class Gradient(ABC):
color_space: str
colors: list[Incomplete]
background: Incomplete | None
extend_before: Incomplete
extend_after: Incomplete
bounds: Incomplete
functions: Incomplete
pattern: Pattern
coords: Incomplete | None
shading_type: int
def __init__(self, colors, background, extend_before, extend_after, bounds): ...
def get_shading_object(self) -> Shading: ...
def get_pattern(self) -> Pattern: ...
class LinearGradient(Gradient):
coords: list[str]
shading_type: int
def __init__(
self,
fpdf: FPDF,
from_x: float,
from_y: float,
to_x: float,
to_y: float,
colors: list[Incomplete],
background: Incomplete | None = None,
extend_before: bool = False,
extend_after: bool = False,
bounds: list[int] | None = None,
) -> None: ...
class RadialGradient(Gradient):
coords: list[str]
shading_type: int
def __init__(
self,
fpdf: FPDF,
start_circle_x: float,
start_circle_y: float,
start_circle_radius: float,
end_circle_x: float,
end_circle_y: float,
end_circle_radius: float,
colors: list[Incomplete],
background=None,
extend_before: bool = False,
extend_after: bool = False,
bounds: list[int] | None = None,
): ...
+20 -3
View File
@@ -1,3 +1,6 @@
from _typeshed import Incomplete
from typing import Literal
from .enums import Duplex, PageBoundaries, PageMode, TextDirection
class ViewerPreferences:
@@ -6,9 +9,6 @@ class ViewerPreferences:
hide_window_u_i: bool
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,
@@ -26,16 +26,29 @@ class ViewerPreferences:
view_clip: PageBoundaries | None = None,
print_area: PageBoundaries | None = None,
print_clip: PageBoundaries | None = None,
print_scaling: Incomplete | None = None,
) -> None: ...
@property
def non_full_screen_page_mode(self) -> PageMode | None: ...
@non_full_screen_page_mode.setter
def non_full_screen_page_mode(self, page_mode: PageMode | str | None) -> None: ...
@property
def num_copies(self) -> int | None: ...
@num_copies.setter
def num_copies(self, num_copies: int | None) -> None: ...
@property
def print_page_range(self) -> list[int] | None: ...
@print_page_range.setter
def print_page_range(self, print_page_range: list[int] | None) -> None: ...
@property
def direction(self) -> TextDirection | None: ...
@direction.setter
def direction(self, direction: TextDirection | str | None) -> None: ...
@property
def display_doc_title(self) -> bool: ...
@display_doc_title.setter
def display_doc_title(self, display_doc_title: bool) -> None: ...
@property
def duplex(self) -> Duplex | None: ...
@duplex.setter
def duplex(self, duplex: Duplex | str | None) -> None: ...
@@ -55,4 +68,8 @@ class ViewerPreferences:
def print_clip(self) -> PageBoundaries | None: ...
@print_clip.setter
def print_clip(self, view_area: PageBoundaries | str | None) -> None: ...
@property
def print_scaling(self) -> Literal["None", "AppDefault"] | None: ...
@print_scaling.setter
def print_scaling(self, print_scaling: Literal["None", "AppDefault"] | None) -> None: ...
def serialize(self) -> str: ...
+7
View File
@@ -77,3 +77,10 @@ class DestinationXYZ(Destination):
page_ref: Incomplete | None
def __init__(self, page: int, top: float, left: float = 0, zoom: float | Literal["null"] = "null") -> None: ...
def serialize(self) -> str: ...
def replace(
self,
page: Incomplete | None = None,
top: float | None = None,
left: float | None = None,
zoom: float | Literal["null"] | None = None,
) -> DestinationXYZ: ...
+17 -2
View File
@@ -52,15 +52,30 @@ class Table:
outer_border_width: float | None = None,
num_heading_rows: int = 1,
repeat_headings: TableHeadingsDisplay | int = 1,
min_row_height: Incomplete | None = None,
) -> None: ...
def row(self, cells: Iterable[str] = (), style: FontFace | None = None) -> Row: ...
def row(
self,
cells: Iterable[str] = (),
style: FontFace | None = None,
v_align: VAlign | str | None = None,
min_height: Incomplete | None = None,
) -> Row: ...
def render(self) -> None: ...
def get_cell_border(self, i: int, j: int, cell: Cell) -> str | Literal[0, 1]: ...
class Row:
cells: list[Cell]
style: FontFace
def __init__(self, table: Table, style: FontFace | None = None) -> None: ...
v_align: VAlign | None
min_height: Incomplete | None
def __init__(
self,
table: Table,
style: FontFace | None = None,
v_align: VAlign | str | None = None,
min_height: Incomplete | None = None,
) -> None: ...
@property
def cols_count(self) -> int: ...
@property
+3
View File
@@ -41,6 +41,7 @@ class Paragraph:
skip_leading_spaces: bool
wrapmode: Incomplete
bullet: Bullet | None
first_line_indent: float
def __init__(
self,
@@ -54,6 +55,7 @@ class Paragraph:
bullet_string: str = "",
skip_leading_spaces: bool = False,
wrapmode: WrapMode | None = None,
first_line_indent: float = 0,
) -> None: ...
def __enter__(self): ...
def __exit__(self, exc_type, exc_value, traceback) -> None: ...
@@ -134,6 +136,7 @@ class ParagraphCollectorMixin:
bullet_string: str = "",
bullet_r_margin: float | None = None,
wrapmode: WrapMode | None = None,
first_line_indent: float = 0,
) -> Paragraph: ...
def end_paragraph(self) -> None: ...
def image(
+1 -1
View File
@@ -26,7 +26,7 @@ def convert_unit(
ROMAN_NUMERAL_MAP: Final[tuple[tuple[str, int], ...]]
def int2roman(n: int) -> str: ...
def int2roman(n: int | None) -> str: ...
def int_to_letters(n: int) -> str: ...
def print_mem_usage(prefix: str) -> None: ...
def get_mem_usage(prefix: str) -> str: ...