Bump fpdf2 to 2.7.7 (#11149)

Closes: #11145
This commit is contained in:
Sebastian Rittau
2023-12-13 01:31:37 +01:00
committed by GitHub
parent 0e5277c847
commit 3171cb44aa
15 changed files with 300 additions and 59 deletions

View File

@@ -1,4 +1,4 @@
version = "2.7.6"
version = "2.7.7"
upstream_repository = "https://github.com/PyFPDF/fpdf2"
requires = ["types-Pillow>=9.2.0"]

View File

@@ -1,6 +1,7 @@
from pathlib import Path
from .enums import Align as Align, TextMode as TextMode, XPos as XPos, YPos as YPos
from .fonts import FontFace as FontFace
from .fpdf import FPDF as FPDF, FPDFException as FPDFException, TitleStyle as TitleStyle
from .html import HTML2FPDF as HTML2FPDF, HTMLMixin as HTMLMixin
from .prefs import ViewerPreferences as ViewerPreferences
@@ -16,6 +17,7 @@ __all__ = [
"__license__",
"FPDF",
"FPDFException",
"FontFace",
"Align",
"TextMode",
"XPos",

View File

@@ -6,7 +6,7 @@ from .actions import Action
from .enums import AnnotationFlag, AnnotationName, FileAttachmentAnnotationName
from .syntax import Destination, Name, PDFContentStream, PDFObject
DEFAULT_ANNOT_FLAGS: Incomplete
DEFAULT_ANNOT_FLAGS: tuple[AnnotationFlag, ...]
class AnnotationMixin:
type: Name
@@ -27,6 +27,7 @@ class AnnotationMixin:
name: AnnotationName | FileAttachmentAnnotationName | None
ink_list: str | None
f_s: str | None
d_a: str | None
def __init__(
self,
subtype: str,
@@ -48,6 +49,7 @@ class AnnotationMixin:
file_spec: str | None = None,
field_type: str | None = None,
value: Incomplete | None = None,
default_appearance: str | None = None,
) -> None: ...
class PDFAnnotation(AnnotationMixin, PDFObject): ...

View File

@@ -1,11 +1,11 @@
import decimal
from _typeshed import Incomplete
from collections import OrderedDict
from collections.abc import Callable, Generator, Iterator
from collections.abc import Callable, Generator, Iterator, Sequence
from contextlib import contextmanager
from re import Pattern
from typing import Any, ClassVar, NamedTuple, TypeVar
from typing_extensions import Self, TypeAlias
from typing import Any, ClassVar, NamedTuple, TypeVar, overload
from typing_extensions import Literal, Self, TypeAlias
from .syntax import Name, Raw
@@ -70,6 +70,14 @@ class DeviceCMYK(_DeviceCMYKBase):
def rgb8(r, g, b, a: Incomplete | None = None) -> DeviceRGB: ...
def gray8(g, a: Incomplete | None = None) -> DeviceGray: ...
@overload
def convert_to_device_color(r: DeviceGray, g: int = -1, b: int = -1) -> DeviceGray: ...
@overload
def convert_to_device_color(r: DeviceRGB, g: int = -1, b: int = -1) -> DeviceRGB: ...
@overload
def convert_to_device_color(r: int, g: Literal[-1] = -1, b: Literal[-1] = -1) -> DeviceGray: ...
@overload
def convert_to_device_color(r: Sequence[int] | int, g: int, b: int) -> DeviceGray | DeviceRGB: ...
def cmyk8(c, m, y, k, a: Incomplete | None = None) -> DeviceCMYK: ...
def color_from_hex_string(hexstr) -> DeviceRGB: ...
def color_from_rgb_string(rgbstr) -> DeviceRGB: ...

View File

@@ -70,6 +70,8 @@ class TableCellFillMode(CoerciveEnum):
ROWS: str
COLUMNS: str
def should_fill_cell(self, i: int, j: int) -> bool: ...
class RenderStyle(CoerciveEnum):
D: str
F: str

View File

@@ -2,6 +2,7 @@ import dataclasses
from _typeshed import Incomplete
from collections.abc import Generator
from dataclasses import dataclass
from typing import overload
from .drawing import DeviceGray, DeviceRGB, Number
from .enums import TextEmphasis
@@ -12,8 +13,8 @@ class FontFace:
family: str | None
emphasis: TextEmphasis | None
size_pt: int | None
color: int | tuple[Number, Number, Number] | DeviceGray | DeviceRGB | None
fill_color: int | tuple[Number, Number, Number] | DeviceGray | DeviceRGB | None
color: DeviceGray | DeviceRGB | None
fill_color: DeviceGray | DeviceRGB | None
def __init__(
self,
@@ -26,6 +27,13 @@ class FontFace:
replace = dataclasses.replace
@overload
@staticmethod
def combine(default_style: None, override_style: None) -> None: ... # type: ignore[misc]
@overload
@staticmethod
def combine(default_style: FontFace | None, override_style: FontFace | None) -> FontFace: ...
class _FontMixin:
i: int
type: str

View File

@@ -6,7 +6,7 @@ from io import BytesIO
from pathlib import PurePath
from re import Pattern
from typing import Any, ClassVar, NamedTuple, overload
from typing_extensions import Literal, TypeAlias
from typing_extensions import Final, Literal, TypeAlias, deprecated
from fpdf import ViewerPreferences
from PIL import Image
@@ -35,6 +35,13 @@ from .errors import FPDFException as FPDFException
from .fonts import FontFace
from .graphics_state import GraphicsStateMixin
from .html import HTML2FPDF
from .image_datastructures import (
ImageCache,
ImageInfo as ImageInfo,
RasterImageInfo as RasterImageInfo,
VectorImageInfo as VectorImageInfo,
_AlignLiteral,
)
from .output import OutputProducer, PDFPage
from .recorder import FPDFRecorder
from .structure_tree import StructureTreeBuilder
@@ -42,23 +49,26 @@ from .syntax import DestinationXYZ
from .table import Table
from .util import _Unit
__all__ = ["FPDF", "XPos", "YPos", "get_page_format", "ImageInfo", "TextMode", "TitleStyle", "PAGE_FORMATS"]
__all__ = [
"FPDF",
"XPos",
"YPos",
"get_page_format",
"ImageInfo",
"RasterImageInfo",
"VectorImageInfo",
"TextMode",
"TitleStyle",
"PAGE_FORMATS",
]
_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"]
_FontStyles: TypeAlias = Literal["", "B", "I", "U", "BU", "UB", "BI", "IB", "IU", "UI", "BIU", "BUI", "IBU", "IUB", "UBI", "UIB"]
PAGE_FORMATS: dict[_Format, tuple[float, float]]
class ImageInfo(dict[str, Any]):
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def rendered_width(self) -> int: ...
@property
def rendered_height(self) -> int: ...
FPDF_VERSION: Final[str]
PAGE_FORMATS: dict[_Format, tuple[float, float]]
class TitleStyle(FontFace):
t_margin: int | None
@@ -87,7 +97,6 @@ def get_page_format(format: _Format | tuple[float, float], k: float | None = Non
# TODO: TypedDicts
_Font: TypeAlias = dict[str, Any]
_Image: TypeAlias = dict[str, Any]
class FPDF(GraphicsStateMixin):
MARKDOWN_BOLD_MARKER: ClassVar[str]
@@ -102,15 +111,14 @@ class FPDF(GraphicsStateMixin):
page: int
pages: dict[int, PDFPage]
fonts: dict[str, _Font]
images: dict[str, _Image]
links: dict[int, DestinationXYZ]
embedded_files: list[PDFEmbeddedFile]
image_cache: ImageCache
in_footer: bool
str_alias_nb_pages: str
xmp_metadata: str | None
image_filter: str
page_duration: int
page_transition: Incomplete | None
allow_images_transparency: bool
@@ -148,6 +156,8 @@ class FPDF(GraphicsStateMixin):
w: float
h: float
text_shaping: dict[str, Incomplete] | None # TODO: TypedDict
def __init__(
self,
orientation: _Orientation = "portrait",
@@ -371,7 +381,16 @@ class FPDF(GraphicsStateMixin):
h: float = 1,
name: AnnotationName | str | None = None,
flags: tuple[AnnotationFlag, ...] | tuple[str, ...] = ...,
) -> None: ...
) -> AnnotationDict: ...
def free_text_annotation(
self,
text: str,
x: float | None = None,
y: float | None = None,
w: float | None = None,
h: float | None = None,
flags: tuple[AnnotationFlag, ...] | tuple[str, ...] = ...,
) -> AnnotationDict: ...
def add_action(self, action, x: float, y: float, w: float, h: float) -> None: ...
def highlight(
self,
@@ -466,10 +485,12 @@ class FPDF(GraphicsStateMixin):
def text_columns(
self,
text: str | None = None,
img: str | None = None,
img_fill_width: bool = False,
ncols: int = 1,
gutter: float = 10,
balance: bool = False,
text_align: Align | str = "LEFT",
text_align: Align | _AlignLiteral = "LEFT",
line_height: float = 1,
l_margin: float | None = None,
r_margin: float | None = None,
@@ -490,7 +511,8 @@ class FPDF(GraphicsStateMixin):
alt_text: str | None = None,
dims: tuple[float, float] | None = None,
keep_aspect_ratio: bool = False,
) -> _Image: ...
) -> RasterImageInfo | VectorImageInfo: ...
@deprecated("Deprecated since 2.7.7; use fpdf.image_parsing.preload_image() instead")
def preload_image(
self, name: str | Image.Image | BytesIO, dims: tuple[float, float] | None = None
) -> tuple[str, Any, ImageInfo]: ...

View File

@@ -102,4 +102,8 @@ class GraphicsStateMixin:
def denom_lift(self): ...
@denom_lift.setter
def denom_lift(self, v) -> None: ...
@property
def text_shaping(self): ...
@text_shaping.setter
def text_shaping(self, v) -> None: ...
def font_face(self) -> FontFace: ...

View File

@@ -0,0 +1,59 @@
from _typeshed import Incomplete
from dataclasses import dataclass
from typing import Any
from typing_extensions import Literal, TypeAlias
from fpdf.enums import Align
from fpdf.fpdf import FPDF
from .image_parsing import _ImageFilter
_AlignLiteral: TypeAlias = Literal[
"",
"CENTER",
"X_CENTER",
"LEFT",
"RIGHT",
"JUSTIFY",
"center",
"x_center",
"left",
"right",
"justify",
"C",
"X",
"L",
"R",
"J",
"c",
"x",
"l",
"r",
"j",
]
class ImageInfo(dict[str, Any]):
@property
def width(self) -> int: ...
@property
def height(self) -> int: ...
@property
def rendered_width(self) -> int: ...
@property
def rendered_height(self) -> int: ...
def scale_inside_box(self, x: float, y: float, w: float, h: float) -> tuple[float, float, float, float]: ...
@staticmethod
def x_by_align(x: Align | _AlignLiteral, w: float, pdf: FPDF, keep_aspect_ratio: Literal[False]) -> float: ...
class RasterImageInfo(ImageInfo):
def size_in_document_units(self, w: float, h: float, scale=1) -> tuple[float, float]: ...
class VectorImageInfo(ImageInfo): ...
@dataclass
class ImageCache:
images: dict[str, dict[Incomplete, Incomplete]] = ...
icc_profiles: dict[bytes, int] = ...
image_filter: _ImageFilter = "AUTO"
def reset_usages(self) -> None: ...

View File

@@ -1,4 +1,5 @@
from _typeshed import Incomplete
from dataclasses import dataclass
from io import BytesIO
from logging import Logger
from types import TracebackType
@@ -7,15 +8,29 @@ from typing_extensions import Literal, TypeAlias
from PIL import Image
from .image_datastructures import ImageCache, ImageInfo, VectorImageInfo
from .svg import SVGObject
_ImageFilter: TypeAlias = Literal["AUTO", "FlateDecode", "DCTDecode", "JPXDecode"]
RESAMPLE: Image.Resampling
@dataclass
class ImageSettings:
compression_level: int = -1
LOGGER: Logger
SUPPORTED_IMAGE_FILTERS: tuple[_ImageFilter, ...]
SETTINGS: ImageSettings
TIFFBitRevTable: list[int]
def preload_image(
image_cache: ImageCache, name: str | BytesIO | Image.Image, dims: tuple[float, float] | None = None
) -> tuple[str, BytesIO | Image.Image | None, ImageInfo]: ...
def load_image(filename): ...
def is_iccp_valid(iccp, filename) -> bool: ...
def get_svg_info(filename: str, img: BytesIO, image_cache: ImageCache) -> tuple[str, SVGObject, VectorImageInfo]: ...
# Returned dict could be typed as a TypedDict.
def get_img_info(

View File

@@ -1,14 +1,16 @@
from _typeshed import Incomplete
from collections.abc import Callable, Sequence
from typing import NamedTuple
from typing_extensions import Final
from .enums import Align, WrapMode
SOFT_HYPHEN: str
HYPHEN: str
SPACE: str
NBSP: str
NEWLINE: str
SOFT_HYPHEN: Final[str]
HYPHEN: Final[str]
SPACE: Final[str]
NBSP: Final[str]
NEWLINE: Final[str]
FORM_FEED: Final[str]
class Fragment:
characters: list[str]
@@ -70,7 +72,8 @@ class TextLine(NamedTuple):
align: Align
height: float
max_width: float
trailing_nl: bool = ...
trailing_nl: bool = False
trailing_form_feed: bool = False
class SpaceHint(NamedTuple):
original_fragment_index: int
@@ -114,8 +117,8 @@ class CurrentLine:
url: str | None = None,
): ...
def trim_trailing_spaces(self) -> None: ...
def manual_break(self, align: Align, trailing_nl: bool = False): ...
def automatic_break_possible(self): ...
def manual_break(self, align: Align, trailing_nl: bool = False, trailing_form_feed: bool = False) -> TextLine: ...
def automatic_break_possible(self) -> bool: ...
def automatic_break(self, align: Align): ...
class MultiLineBreak:

View File

@@ -5,6 +5,8 @@ from typing_extensions import Final
from .annotations import AnnotationDict
from .encryption import StandardSecurityHandler
from .fpdf import FPDF
from .image_datastructures import RasterImageInfo
from .syntax import Name, PDFArray, PDFContentStream, PDFObject, PDFString
LOGGER: Logger
@@ -172,12 +174,23 @@ class PDFXrefAndTrailer(ContentWithoutID):
def serialize(self, _security_handler: StandardSecurityHandler | None = None) -> str: ...
class OutputProducer:
fpdf: Incomplete
fpdf: FPDF
pdf_objs: list[Incomplete]
obj_id: int
offsets: dict[Incomplete, Incomplete]
trace_labels_per_obj_id: dict[Incomplete, Incomplete]
sections_size_per_trace_label: defaultdict[Incomplete, int]
buffer: bytearray
def __init__(self, fpdf) -> None: ...
def __init__(self, fpdf: FPDF) -> None: ...
def bufferize(self) -> bytearray: ...
def stream_content_for_raster_image(
info: RasterImageInfo,
x: float,
y: float,
w: float,
h: float,
keep_aspect_ratio: bool = False,
scale: float = 1,
pdf_height_to_flip: float | None = None,
) -> str: ...

View File

@@ -1,10 +1,16 @@
from _typeshed import Incomplete
from _typeshed import Incomplete, Unused
from collections.abc import Callable
from logging import Logger
from re import Pattern
from fpdf.drawing import PaintedPath
from typing import NamedTuple, overload
from typing_extensions import Literal
from ._fonttools_shims import BasePen, _TTGlyphSet
from .drawing import ClippingPath, PaintedPath
from .fpdf import FPDF
from .image_datastructures import ImageCache
LOGGER: Logger
__pdoc__: dict[str, bool]
@@ -40,20 +46,40 @@ def parse_style(svg_element) -> None: ...
def apply_styles(stylable, svg_element) -> None: ...
class ShapeBuilder:
@overload
@staticmethod
def new_path(tag): ...
def new_path(tag, clipping_path: Literal[True]) -> ClippingPath: ...
@overload
@staticmethod
def new_path(tag, clipping_path: Literal[False] = False) -> PaintedPath: ...
@overload
@classmethod
def rect(cls, tag): ...
def rect(cls, tag, clipping_path: Literal[True]) -> ClippingPath: ...
@overload
@classmethod
def circle(cls, tag): ...
def rect(cls, tag, clipping_path: Literal[False] = False) -> PaintedPath: ...
@overload
@classmethod
def ellipse(cls, tag): ...
def circle(cls, tag, clipping_path: Literal[True]) -> ClippingPath: ...
@overload
@classmethod
def line(cls, tag): ...
def circle(cls, tag, clipping_path: Literal[False] = False) -> PaintedPath: ...
@overload
@classmethod
def polyline(cls, tag): ...
def ellipse(cls, tag, clipping_path: Literal[True]) -> ClippingPath: ...
@overload
@classmethod
def polygon(cls, tag): ...
def ellipse(cls, tag, clipping_path: Literal[False] = False) -> PaintedPath: ...
@classmethod
def line(cls, tag) -> PaintedPath: ...
@classmethod
def polyline(cls, tag) -> PaintedPath: ...
@overload
@classmethod
def polygon(cls, tag, clipping_path: Literal[True]) -> ClippingPath: ...
@overload
@classmethod
def polygon(cls, tag, clipping_path: Literal[False] = False) -> PaintedPath: ...
def convert_transforms(tfstr): ...
@@ -67,14 +93,17 @@ class PathPen(BasePen):
def svg_path_converter(pdf_path: PaintedPath, svg_path: str) -> None: ...
class SVGObject:
image_cache: ImageCache | None
@classmethod
def from_file(cls, filename, *args, encoding: str = "utf-8", **kwargs): ...
cross_references: Incomplete
def __init__(self, svg_text) -> None: ...
def __init__(self, svg_text, image_cache: ImageCache | None = None) -> None: ...
preserve_ar: Incomplete
width: Incomplete
height: Incomplete
viewbox: Incomplete
def update_xref(self, key: str | None, referenced) -> None: ...
def extract_shape_info(self, root_tag) -> None: ...
base_group: Incomplete
def convert_graphics(self, root_tag) -> None: ...
@@ -83,9 +112,29 @@ class SVGObject:
self, scale, width, height, align_viewbox: bool = True, ignore_svg_top_attrs: bool = False
): ...
def draw_to_page(
self, pdf, x: Incomplete | None = None, y: Incomplete | None = None, debug_stream: Incomplete | None = None
self, pdf: FPDF, x: Incomplete | None = None, y: Incomplete | None = None, debug_stream: Incomplete | None = None
) -> None: ...
def handle_defs(self, defs) -> None: ...
def build_xref(self, xref): ...
def build_group(self, group, pdf_group: Incomplete | None = None): ...
def build_path(self, path): ...
def build_shape(self, shape): ...
def build_clipping_path(self, shape, clip_id): ...
def apply_clipping_path(self, stylable, svg_element) -> None: ...
def build_image(self, image) -> SVGImage: ...
class SVGImage(NamedTuple):
href: str
x: float
y: float
width: float
height: float
svg_obj: SVGObject
def __deepcopy__(self, _memo: Unused) -> SVGImage: ...
def render(
self, _gsd_registry: Unused, _style: Unused, last_item, initial_point
) -> tuple[Incomplete, Incomplete, Incomplete]: ...
def render_debug(
self, gsd_registry: Unused, style: Unused, last_item, initial_point, debug_stream, _pfx: Unused
) -> tuple[Incomplete, Incomplete, Incomplete]: ...

View File

@@ -14,13 +14,6 @@ from .util import Padding
DEFAULT_HEADINGS_STYLE: FontFace
def draw_box_borders(pdf: FPDF, x1, y1, x2, y2, border: str | Literal[0, 1], fill_color: Incomplete | None = None) -> None: ...
@dataclass(frozen=True)
class RowLayoutInfo:
height: int
triggers_page_jump: bool
rendered_height: dict[Incomplete, Incomplete]
class Table:
rows: list[Row]
@@ -48,14 +41,14 @@ class Table:
outer_border_width: float | None = None,
num_heading_rows: int = 1,
) -> None: ...
def row(self, cells: Iterable[str] = ()) -> Row: ...
def row(self, cells: Iterable[str] = (), style: FontFace | None = None) -> Row: ...
def render(self) -> None: ...
def get_cell_border(self, i, j) -> str | Literal[0, 1]: ...
class Row:
cells: list[Cell]
style: FontFace
def __init__(self, fpdf: FPDF) -> None: ...
def __init__(self, table: Table, style: FontFace | None = None) -> None: ...
@property
def cols_count(self) -> int: ...
@property
@@ -86,3 +79,11 @@ class Cell:
link: str | int | None
def write(self, text, align: Incomplete | None = None): ...
@dataclass(frozen=True)
class RowLayoutInfo:
height: int
triggers_page_jump: bool
rendered_height: dict[Incomplete, Incomplete]
def draw_box_borders(pdf: FPDF, x1, y1, x2, y2, border: str | Literal[0, 1], fill_color: Incomplete | None = None) -> None: ...

View File

@@ -1,8 +1,10 @@
from _typeshed import Incomplete
from collections.abc import Sequence
from typing import NamedTuple
from typing_extensions import Self
from .enums import Align, WrapMode
from .image_datastructures import RasterImageInfo, VectorImageInfo, _AlignLiteral
class Extents(NamedTuple):
left: float
@@ -45,9 +47,43 @@ class Paragraph:
def ln(self, h: float | None = None) -> None: ...
def build_lines(self, print_sh: bool) -> list[LineWrapper]: ...
class ImageParagraph:
region: Incomplete
name: Incomplete
align: Align | None
width: float | None
height: float | None
fill_width: bool
keep_aspect_ratio: bool
top_margin: float
bottom_margin: float
link: Incomplete | None
title: Incomplete | None
alt_text: Incomplete | None
img: Incomplete | None
info: Incomplete | None
def __init__(
self,
region,
name,
align: Align | _AlignLiteral | None = None,
width: float | None = None,
height: float | None = None,
fill_width: bool = False,
keep_aspect_ratio: bool = False,
top_margin: float = 0,
bottom_margin: float = 0,
link: Incomplete | None = None,
title: Incomplete | None = None,
alt_text: Incomplete | None = None,
) -> None: ...
def build_line(self) -> Self: ...
def render(self, col_left: float, col_width: float, max_height: float) -> VectorImageInfo | RasterImageInfo: ...
class ParagraphCollectorMixin:
pdf: Incomplete
text_align: Align | str = "LEFT"
text_align: Align
line_height: Incomplete
print_sh: Incomplete
wrapmode: Incomplete
@@ -57,11 +93,13 @@ class ParagraphCollectorMixin:
pdf,
*args,
text: str | None = None,
text_align: str = "LEFT",
text_align: Align | _AlignLiteral = "LEFT",
line_height: float = 1.0,
print_sh: bool = False,
skip_leading_spaces: bool = False,
wrapmode: WrapMode | None = None,
img: Incomplete | None = None,
img_fill_width: bool = False,
**kwargs,
) -> None: ...
def __enter__(self): ...
@@ -78,6 +116,20 @@ class ParagraphCollectorMixin:
wrapmode: WrapMode | None = None,
): ...
def end_paragraph(self) -> None: ...
def image(
self,
name,
align: Align | _AlignLiteral | None = None,
width: float | None = None,
height: float | None = None,
fill_width: bool = False,
keep_aspect_ratio: bool = False,
top_margin: float = 0,
bottom_margin: float = 0,
link: Incomplete | None = None,
title: Incomplete | None = None,
alt_text: Incomplete | None = None,
) -> None: ...
class TextRegion(ParagraphCollectorMixin):
def current_x_extents(self, y, height) -> None: ...
@@ -93,6 +145,7 @@ class TextColumnarMixin:
class TextColumns(TextRegion, TextColumnarMixin):
balance: Incomplete
def __init__(self, pdf, *args, ncols: int = 1, gutter: float = 10, balance: bool = False, **kwargs) -> None: ...
def __enter__(self): ...
def __enter__(self) -> Self: ...
def new_column(self) -> None: ...
def render(self) -> None: ...
def current_x_extents(self, y, height): ...