pillow_wmf
WMF codec, GDI recording and Pillow loading with an RGB raster backend.
pillow_wmf.objects
Immutable GDI inputs, independent of metafile record layouts.
EncodedText Objects
@dataclass(frozen=True)
class EncodedText()
Text bytes decoded with the selected font and code-page environment.
Explicit advances retain source-byte indexing until decoding determines character spans and the environment’s spacing convention.
GlyphIndices Objects
@dataclass(frozen=True)
class GlyphIndices()
Font-local glyph IDs; advances index glyphs, not encoded bytes.
EncodedFaceName Objects
@dataclass(frozen=True)
class EncodedFaceName()
A legacy face name decoded using the caller’s ANSI environment.
RegionGeometry Objects
@dataclass(frozen=True)
class RegionGeometry()
Logical rectangles; empty geometry is a valid empty region.
BitmapData Objects
@dataclass(frozen=True)
class BitmapData()
Encoded bitmap bytes, not decoded or certified as renderable.
pillow_wmf.environment_codepages
Native Windows OEM/Mac mapping additions to Python codecs.
Byte tables preserve vendor/private-use values without normalization. The three full upper-half tables cover pages without a matching Python codec. Regressions fingerprint every byte against the native NLS probe.
decode_environment
def decode_environment(data, codepage)
Decode a verified, single-byte legacy environment page.
pillow_wmf.wingdings
Wingdings bytes mapped to Unicode character identities, not matching outlines.
Source: Unicode/WG2 N4363, mapping appendix: https://www.unicode.org/wg2/docs/n4363.pdf Rows start at byte 0x20. Zero marks an undefined/unencoded character; notably 0xFF is the Windows logo, not a Unicode symbol. Space is preserved separately from the reference’s printable-symbol repertoire.
decode_wingdings
def decode_wingdings(data)
Preserve one character per byte, including supplementary-plane symbols.
pillow_wmf.stroke
Solid GDI strokes: realized polygonal pens and cosmetic grid lines.
The pen is realized once from the mapping. Every wide segment then uses the same support-vertex sweep, independent of its slope or the mapping scale.
realize_pen
def realize_pen(width: int,
scale_x=1,
scale_y=1,
*,
geometric=False) -> PenGeometry
Realize CreatePen width in device space, including the hairline rule.
frame_footprint
def frame_footprint(width, height, scale_x, scale_y)
Rectangular frame support realized through GDI’s geometric pen.
widen_segment
def widen_segment(segment: StrokeSegment,
pen: PenGeometry,
*,
cap_start=True,
cap_end=True,
miter=False) -> Polygon
Construct a stroke body and requested endpoint caps in 28.4 units.
join_outline
def join_outline(first: StrokeSegment,
second: StrokeSegment,
pen: PenGeometry,
*,
miter=False) -> Polygon
Cover the exterior turn between two incident stroke bodies.
line_outline
def line_outline(start: Point, end: Point, width: int, scale_x,
scale_y) -> Polygon
Device-integer convenience entry point for diagnostic path probes.
cosmetic_span
def cosmetic_span(start: Point, end: Point) -> range
Unclipped, directed major-axis pixel span, in constant time.
Only endpoint diamonds can shorten the span; interior grid intersections each own a pixel. This counts style steps even when the whole line is off screen, without enumerating arbitrarily distant coordinates.
cosmetic_line
def cosmetic_line(start: Point, end: Point, width: int, height: int)
GIQ coverage for a 28.4 segment, including fractional curve vertices.
Choose the closest minor-coordinate pixel at each major grid intersection (ties to the smaller coordinate). A pixel is emitted when the segment exits its half-pixel diamond. Endpoint ownership uses the legacy GIQ boundary rules (including slope +/-1 edges), not a blanket start/end convention. Bounds restrict grid enumeration without changing the original line.
pillow_wmf.text
Explicit font inputs, glyph masks and compatible-mode GDI text layout.
Font files, aliases and missing-glyph policy are supplied by the caller, not by a WMF. There is no host-font discovery or registry-based font substitution.
text_rotation
def text_rotation(escapement)
Share the font scaler’s 16.16 rotation with baseline placement.
decode_single_byte
def decode_single_byte(data, codepage)
Decode using Windows NLS mappings, including undefined/vendor bytes.
decode_codepage
def decode_codepage(data, codepage)
Decode characters and their source spans through one code-page policy.
RasterFont Objects
@dataclass
class RasterFont()
Glyph generation is independent of GDI alignment and DC state.
glyph_index
def glyph_index(index, max_pixels)
Realize a physical glyph without character mapping or font linking.
FontFace Objects
class FontFace()
A pinned TrueType face with its Windows metrics, not Pillow’s metrics.
bundled_wingdings
@classmethod
def bundled_wingdings(cls)
Load the prebuilt Unicode Wingdings fallback; selection stays explicit.
bundled_symbol
@classmethod
def bundled_symbol(cls)
Wine’s unmodified Symbol face, retaining its legacy symbol cmap.
realize
def realize(request, scale, *, missing_glyph="error")
Classic compatible-mode realization; natural width follows height.
FontCollection Objects
class FontCollection()
Supplied faces and explicit aliases; never discover or silently replace.
layout_font
def layout_font(request, face, scale, *, characters=None)
Prepare a run; controlled fonts never depend on host discovery.
face_name
def face_name(request)
Resolve a logical name, or a legacy name in this ANSI environment.
FontRun Objects
@dataclass(frozen=True)
class FontRun()
Use base line metrics, selecting supplied fallback faces only for holes.
shape
def shape(characters, max_pixels, *, raw=False)
Shape SBCS control runs before choosing masks and advances.
A control run containing an unshapable character falls back to raw character output. Its formerly invisible controls then participate in font linking too. Separators terminate runs; they are not tab stops or multiline layout commands. Paired advances request raw glyph output, bypassing the control-run shaper without disabling font linking.
layout_text
def layout_text(font,
text,
x,
y,
alignment,
advances,
*,
opaque,
max_pixels,
scale=1,
extra=0,
justification=(0, 0),
characters=None,
escapement=0,
glyph_indices=None,
vertical_advances=(),
vertical_scale=1,
mirrored_layout=False,
precise_origin=None,
byte_lengths=(),
byte_indexed_advances=True)
Place independently realized glyphs; explicit advances replace metrics.
paired_background
def paired_background(glyphs, offsets, vertical_offsets, origin_x, baseline,
cell, x, y, escapement)
Bound positioned glyph cells in font space, then realize their corners.
pillow_wmf.recording
Draw and record the same GDI commands through exclusively owned contexts.
RecordingContext Objects
class RecordingContext(TraceContext)
Pair fresh staged backends, rejecting work before either side applies it.
Issue all drawing through this wrapper after construction. Direct changes to the image, backend state or recorder records are not captured. Rendering a recording requires the same canvas, initial background and font setup. Unexpected execution failures invalidate the pair; no pixel rollback is attempted. Failed native creations are rejected rather than recorded with potentially different object-slot lifetimes.
image
@property
def image()
The live image; mutating it directly bypasses recording.
pillow_wmf.plugin
Pillow’s WMF entry point; EMF remains with Pillow’s existing handler.
WmfImageFile Objects
class WmfImageFile(ImageFile.ImageFile)
load
def load(*, size=None, dpi=None, fonts=None)
Rasterize once; choose size or placeable DPI before the first load.
Plain WMFs have no physical size. Invalid placeable bounds fall back to the same 128-square canvas. Records can override the initial mapping. Unsupported drawing raises OSError rather than returning partial art. Invalid caller options raise ValueError.
pillow_wmf.flood
Four-connected scanline discovery, independent of brush realization.
flood_spans
def flood_spans(width, height, seed, eligible)
Return disjoint (y, left, right) spans; right is exclusive.
Mark whole runs when discovered, then search their vertical neighbours.
No recursion and no dependence on whether painting changes a pixel.
eligible must describe the unchanged source surface and clip.
pillow_wmf.constants
GDI values used by the emulator, independent of WMF record opcodes.
pillow_wmf.halftone
Native RGB HALFTONE: 13-bit area weights, sharpening and tent expansion.
Includes the native colour census and fast replication-run enlargement filter.
replication_candidate
def replication_candidate(sw, sh, width, height)
ComputeAABBP’s integer eligibility test, before image classification.
The +500 is literal: it is not half of the source dimension. A decrease in total pixel area overrides the small-image replication decision.
fixup_candidate
def fixup_candidate(sw, sh, width, height)
Eligibility for the colour census and its buffered source reader.
classify_content
def classify_content(bitmap, x, y, width, height, *, depth=24)
CheckBMPNeedFixup’s bounded colour census of the source rectangle.
Small images bypass the census. Medium images discount rows introducing no new colours; large images sample every sixth row with a 20-colour cap. The native key coarsens channels when red equals blue (not just greys).
halftone_bitmap
def halftone_bitmap(bitmap, x, y, sw, sh, width, height, *, content=None)
Return a filtered view, no-op, or explicit request for scan replication.
A view with valid=False means no output, never replication.
ExpansionAxis Objects
class ExpansionAxis()
Integrate a power-adjusted discrete tent over source pixel cells.
RunExpansionAxis Objects
class RunExpansionAxis()
Native FastExpAA’s five replication-run stencils, in units of 1/32.
HalftoneExpansion Objects
class HalftoneExpansion()
Source Laplacian, then horizontal and vertical fixed-point expansion.
area_weights
def area_weights(source_length, destination_length, index)
Integrate source cells using quantized cumulative boundaries.
Taking differences after quantization carries the division remainder across contributions. Rounding independently computed overlap weights does not. Coordinates use the common integer grid: source cells are D units wide, destination cells S units wide. Each output’s weights sum to exactly 8192.
HalftoneReduction Objects
class HalftoneReduction()
Lazy bitmap view; destination clipping does not change filtering phase.
Bounded per-transfer caches avoid allocating the destination or a potentially large source-height intermediate image. Output pixels remain ordinary RGB samples consumed by the shared transfer compositor.
pillow_wmf._values
Snapshot sequence inputs so recorded commands cannot change underneath us.
pillow_wmf.system_fonts
Opt-in host font discovery, separate from controlled-font rendering.
font_paths
def font_paths()
Use Fontconfig’s configured inventory, or conventional system directories.
SystemFontCollection Objects
class SystemFontCollection(FontCollection)
Best-effort installed fonts; construct one collection per rendering job.
Discovery is lazy. Pass paths to use a bounded application font inventory instead of the host. Unsupported outline formats are ignored. Missing glyphs use .notdef after installed Unicode fallbacks have been exhausted. Immutable catalogues are shared across jobs, including host discovery. Call clear_cache() after installing, removing or replacing fonts, then construct a new collection. Existing jobs retain their inventory snapshot.
clear_cache
@staticmethod
def clear_cache()
Refresh discovery/catalogues for future jobs; live jobs stay unchanged.
Loaded FreeType faces and substitution reports are never shared. Changes to files at existing paths also require this explicit refresh.
pillow_wmf.paint
Boolean raster operations for RGB pattern, source and destination pixels.
rop3
def rop3(rop: int, pattern: RGB, source: RGB, destination: RGB) -> RGB
Evaluate the eight-entry P,S,D table in bits 16..23 of a GDI ROP.
Split on P: each half is an S,D binary table. This covers all 256 functions without a catalogue of named raster-operation exceptions.
pattern_rop2
def pattern_rop2(rop: int) -> int | None
Reduce a source-independent ROP3 to ROP2; otherwise return None.
rop2
def rop2(mode: int, source: RGB, destination: RGB) -> RGB
Apply the four-entry P,D truth table encoded by a WMF ROP2 value.
The entries are ordered (P,D) = 00, 01, 10, 11. Windows numbers the sixteen possible tables from 1 through 16, so the table bits are mode-1.
pillow_wmf.dbcs
Decoded text retains byte spans for ANSI GDI’s byte-indexed advances.
collapse_advances
def collapse_advances(advances, byte_lengths, *, byte_indexed=True)
Map ANSI advances to characters, including signed x or y offsets.
GDI collapses byte entries only for CP932/936/949/950. Johab and Mac pages keep the first character-count entries; trailing byte entries are unused. The WMF array must still supply an entry for every source byte.
decode_cp932
def decode_cp932(data)
Decode Windows Japanese text with source-byte spans.
decode_dbcs
def decode_dbcs(data, codepage)
Decode Windows DBCS text, preserving NLS replacement boundaries.
A malformed pair consumes both bytes and becomes the page’s replacement character: KATAKANA MIDDLE DOT for Japanese pages, question mark for others. NUL is the exception: it is retained as a separate character. A dangling lead byte also becomes the replacement. Python codecs provide the base mappings; explicit Windows extensions preserve vendor and Jamo mappings.
pillow_wmf.numeric
Storage precision shared by GDI arithmetic, not a universal rounding rule.
float32
def float32(value: float) -> float
Round one arithmetic result to IEEE-754 binary32.
pillow_wmf.geometry
Device paths in 28.4 fixed point, retained through scan conversion.
DevicePath Objects
@dataclass(frozen=True)
class DevicePath()
Connected line/cubic commands, retained until the stroke is realized.
rectangle
@classmethod
def rectangle(cls, left: int, top: int, right: int, bottom: int)
A closed rectangle in fixed device coordinates, starting top-right.
_CurveAxis Objects
@dataclass
class _CurveAxis()
One axis of an adaptive forward-difference cubic.
Curvature terms describe the end and start of the current interval. Keeping them alongside position and advance lets us walk the curve or change interval size without repeatedly evaluating its polynomial.
controls
def controls() -> tuple[int, int, int, int]
Recover rounded controls for one coarse interval of a large curve.
flatten_cubic
def flatten_cubic(control: Cubic) -> Polygon
Flatten using GDI’s integer adaptive curve walk; see gdi-curves.md.
Arithmetic shifts during step changes are observable. Exact recursive subdivision can choose identical sample parameters but different vertices.
contains
def contains(polygons: tuple[Polygon, ...],
x: int,
y: int,
*,
fill_mode: int = 1) -> bool
Evaluate alternate or winding coverage at a device-pixel coordinate.
pillow_wmf.wmf.records
Record envelopes and the explicit typed-record registry.
Unknown records stay opaque. Known records retain their original function word and any uninterpreted trailing bytes independently of their decoded fields.
pillow_wmf.wmf.objects
Wire-level graphics structures. Bitmap pixels are deliberately undecoded.
pillow_wmf.wmf.constants
WMF record function values, MS-WMF 2.1.1.1.
pillow_wmf.wmf.player
Translate WMF records to backend calls without rasterizing or decoding text.
PlaybackError Objects
class PlaybackError(ValueError)
A stream’s handle references or backend results are invalid.
play
def play(metafile: Metafile,
backend: GDI,
*,
strict: bool = False,
limits: Limits | None = None) -> tuple[Omission, ...]
Play into a supplied context; return diagnostics for unsupported work.
The caller owns the backend and its initial state. No implicit drawing-state reset, object deletion, or source-byte rewrite is inserted into the trace. Unsupported creations occupy their WMF slots to prevent handle aliasing.
pillow_wmf.wmf.variable
Variable-length vector, text, object and escape records.
pillow_wmf.wmf.bindings
Explicit WMF/GDI bindings. File handle indexes never cross into a backend.
pillow_wmf.wmf.file
WMF file framing and preserving/canonical serialization.
Metafile Objects
@dataclass(frozen=True)
class Metafile()
build
@classmethod
def build(cls,
records,
*,
placeable: PlaceableHeader | None = None,
version: int = 0x0300)
Build a new stream, inserting EOF and calculating header accounting.
Direct records may intentionally contain semantically invalid handle references for test fixtures. Use Recorder for checked handle lifetimes.
to_bytes
def to_bytes(*, canonical: bool = False) -> bytes
Preserve metadata by default; canonical=True recomputes file sizes.
Trailing file bytes are retained but excluded from canonical stream size. Reserved/padding bytes in records remain explicit data in either mode.
pillow_wmf.wmf.recorder
Record GDI commands into WMF with deterministic file-handle allocation.
Recorder Objects
class Recorder(TraceContext)
A checked command recorder, not a rendering device-context emulator.
Use direct Record construction for reserved fields, unknown opcodes and intentionally invalid test cases. Public calls use logical backend handles.
pillow_wmf.wmf.adapters
Translate logical GDI objects into representable WMF wire objects.
pillow_wmf.wmf.binary
Compatibility imports for shared bounded binary helpers.
pillow_wmf.wmf.fixed
Fixed-field records. Field order follows MS-WMF, not the GDI argument order.
pillow_wmf.wmf
WMF reader/writer. Import record classes from fixed, variable and bitmaps.
pillow_wmf.wmf.bitmaps
Bitmap transfer envelopes; BitmapData explicitly preserves opaque pixels.
pillow_wmf.render
Complete WMF rendering; use play when collecting omissions is required.
render
def render(data: bytes,
size: tuple[int, int],
*,
fonts: FontCollection | None = None,
background=(255, 255, 255),
limits: Limits | None = None,
max_bitmap_pixels: int = DEFAULT_MAX_BITMAP_PIXELS) -> Image.Image
Render to an RGB image, raising if any record cannot be rendered.
Size is the output canvas in pixels. Playback uses the WMF’s mapping calls;
neither placeable bounds nor drawing bounds implicitly fit the image.
Fonts are supplied explicitly. For partial rendering with diagnostics, use
play(metafile, context, strict=False) and inspect its omissions instead.
pillow_wmf.clip
Immutable region algebra and application clipping.
The bitmap bounds are applied when pixels are written. They must not trim an application clip: a later OffsetClipRgn can move an off-surface clip into view.
RegionMask Objects
@dataclass(frozen=True)
class RegionMask()
Finite union of half-open rectangles, indexed as disjoint y bands.
spans
def spans(y)
Disjoint half-open intervals on a scan line.
difference
def difference(other)
Subtract bands without introducing pixel-sized storage.
frame
def frame(width, height, *, point=None)
Inner rectangular border: subtract the rectangular erosion.
Dilating the complement includes holes and concave corners, without exposing the artificial boundaries between a region’s scan bands. Half-integral device thickness represents an odd full footprint; the extra pixel belongs to the left/top side of the inner border.
ClipRegion Objects
@dataclass(frozen=True)
class ClipRegion()
within
def within(bounds: Rectangle) -> RegionMask
Resolve the application clip inside finite device bounds.
pillow_wmf.halftone_fixup
Native source scan fixup, before HALFTONE resampling.
FixupColorScan detects alternating 2x2 cells. Extended checker runs collapse to their rounded mean; otherwise the brighter diagonal is blended with its four surrounding samples. Decisions use original scans, writes accumulate in scan order. Border lookahead reflects the adjacent row/pixel, not the edge itself.
pillow_wmf.trace
A non-rendering GDI backend with checked handle and save-stack bookkeeping.
This records requested operations. It does not emulate mapping, selected-object deletion quirks, clipping, palette realization or any pixel effects.
pillow_wmf.symbol
Defined byte positions in Windows Symbol’s legacy encoding.
The other positions select the missing glyph, including 0xA0 (not Euro) and 0xF0 (not the Apple glyph found in some PostScript-compatible Symbol fonts). This repertoire is verified through WMF playback and native glyph lookup. Glyph identities and outlines come from the selected Symbol font’s cmap.
pillow_wmf.gdi_math
Table-based angular arithmetic used by the native GDI Arc constructor.
These are mathematical lookup tables, not drawing-specific correction data. Angular arithmetic rounds each stage to binary32 before device-coordinate conversion.
circle_control
def circle_control(radius: int, *, upward: bool) -> int
GDI’s signed 0.32 circle-inset multiply, expressed as a handle length.
The complement of the usual cubic circle coefficient is stored as 0x729d7775, not recomputed from sqrt(2). Arithmetic shifts preserve the oriented rounding used by ellipse, rounded-rectangle and pen constructors.
atan2_degrees
def atan2_degrees(y: float, x: float) -> float
Reduce to the arctangent table’s [0, 1] ratio interval.
sincos_degrees
def sincos_degrees(angle: float, *, accurate=False) -> tuple[float, float]
Return (sine, cosine), with quadrant signs and FLOAT results.
arc_control_normals
def arc_control_normals(first: float, last: float, start, end)
Intersect endpoint tangents and blend their FLOAT control normals.
pillow_wmf.bitmap16
Legacy device-dependent bitmap storage, independent of DIB headers.
encode_bitmap16
def encode_bitmap16(width,
height,
samples,
*,
depth=1,
pattern=False,
native_pattern=False)
Write WORD rows without a colour table.
pattern=True writes the documented 32-byte Pattern Object header.
Add native_pattern=True for Windows’ 36-byte playback layout.
pillow_wmf.palette
Logical palette objects for the RGB reference device.
DC snapshots retain an object reference, not a copy of its mutable entries. There is no display-wide hardware palette to animate on this device.
pillow_wmf.raster
GDI rasterization into a Pillow RGB image.
PreparedEffect Objects
@dataclass(frozen=True)
class PreparedEffect()
Decoded inputs shared by validation and application, never DC state.
TextState Objects
@dataclass(frozen=True)
class TextState()
Logical font, alignment and spacing retained by SaveDC/RestoreDC.
font
None uses the caller’s configured default, if any.
SavedDC Objects
@dataclass(frozen=True)
class SavedDC()
Saved drawing state; selected objects retain their identity.
Mapping is copied at save time. The image and handle allocation table are not part of a snapshot, and palette mutations remain visible after restore.
RasterContext Objects
class RasterContext(TraceContext)
Draw the currently supported GDI calls into an RGB Pillow image.
Unsupported modes and primitives raise rather than silently draw an
approximate image. Playback with strict=True exposes that boundary.
pillow_wmf.halftone_scan
HALFTONE source addressing, separate from filter weights and arithmetic.
These are random-access descriptions of the native scan readers: evaluating a destination pixel out of order must not change the reader’s history. None is an unfilled buffer slot, not a black pixel fetched from the source bitmap.
has_source
def has_source(bitmap, x, y, width, height)
Physical intersection, independent of filter output’s closing cells.
pillow_wmf.dib_rle
Bounded RLE4/RLE8 command decoding in bottom-up storage coordinates.
decode_rle
def decode_rle(data, width, height, depth, *, clip_spans=None)
Decode storage rows, optionally clipped during the native scan transfer.
clip_spans(y) supplies disjoint half-open intervals in storage coordinates.
Encoded RLE4 runs restart at their high nibble after left clipping; absolute
runs retain their source phase. Clipping an already decoded bitmap differs.
pillow_wmf.binary
Bounded little-endian IO and resource policy shared by graphics codecs.
FormatError Objects
class FormatError(ValueError)
The input cannot be interpreted safely as a graphics structure.
ResourceLimitError Objects
class ResourceLimitError(FormatError)
A configured safety limit was exceeded; never a recoverable omission.
Limits Objects
@dataclass(frozen=True)
class Limits()
Allocation/work limits; these are policy, not WMF format limits.
pillow_wmf.mac_dbcs
Windows Macintosh DBCS mappings, distinct from the similarly named ANSI pages.
pillow_wmf.blit
Integer source-transfer geometry and scan selection.
StretchAxis Objects
@dataclass(frozen=True)
class StretchAxis()
samples
def samples(coordinate, mode)
Centre-phase DDA; reduction modes accumulate through each chosen scan.
pillow_wmf.dbcs_tables
Windows NLS additions to Python’s DBCS codecs.
These are encoding mappings, not font substitutions. User-defined character areas retain their private-use code points even without a matching EUDC font. Rows are traversed in lead-byte, then trail-byte order. GBK hole-range endpoints below are inclusive.
pillow_wmf.ellipse
Construct the exclusive-bound ellipse as a fixed-point device path.
box_corners
def box_corners(bounds)
Native box traversal: retain the upper edge, reflect about its centre.
box_axes
def box_axes(bounds)
Quantize the box’s half-edge vectors before angular/corner scaling.
ellipse_cubics
def ellipse_cubics(
left: int,
top: int,
right: int,
bottom: int,
*,
null_pen=False,
drawing_bounds=None,
clockwise=False) -> tuple[tuple[Point, Point, Point, Point], ...]
Four GDI-style cubics, with orientation applied before quantization.
round_rect_figure
def round_rect_figure(left,
top,
right,
bottom,
ellipse_width,
ellipse_height,
*,
null_pen=False,
drawing_bounds=None,
clockwise=False) -> DevicePath
Place canonical ellipse quarters at four centres and connect the edges.
ellipse_path
def ellipse_path(left: int, top: int, right: int, bottom: int) -> Polygon
Flatten the four GDI-style cubic arcs of an exclusive-bound ellipse.
arc_cubics
def arc_cubics(
left: int,
top: int,
right: int,
bottom: int,
start: tuple[int, int],
end: tuple[int, int],
*,
null_pen=False,
drawing_bounds=None,
radial_bounds=None,
clockwise=False) -> tuple[tuple[Point, Point, Point, Point], ...]
Cut an exclusive-bound ellipse at two radial directions.
Normalize radials in the inclusive device box, then construct cubics in the exclusive-bound drawing box. WMF stores points on the radials, not points required to lie on the ellipse.
arc_figure
def arc_figure(left: int,
top: int,
right: int,
bottom: int,
start: Point,
end: Point,
*,
closure: Literal["open", "chord", "pie"] = "open",
null_pen=False,
drawing_bounds=None,
radial_bounds=None,
clockwise=False) -> DevicePath
Retain one arc figure, optionally closed directly or through its centre.
pillow_wmf.halftone_power
Six-decimal GDI tent-weight powers, using reproducible logarithm samples.
The native packed tables encode rounded log10 samples at 0.001 intervals on [1, 10]. Generate those mathematical values, not copies of proprietary tables. Only table construction uses Decimal; interpolation and powers use integers.
round_ratio
def round_ratio(numerator, denominator)
Round a signed ratio to nearest, with ties away from zero.
tent_power
def tent_power(value)
Native asymmetric power curve; the exact half-weight bypasses power.
pillow_wmf.bitmap
Packed DIB codecs, separate from WMF record framing and brush sampling.
RGBBitmap Objects
@dataclass(frozen=True)
class RGBBitmap()
Immutable, top-down RGB pixels; storage orientation is a codec concern.
monochrome
def monochrome(background: tuple[int, int,
int] = (255, 255, 255)) -> "RGBBitmap"
Realize RGB-to-mono colour-key conversion, not a brightness filter.
encode_dib24
def encode_dib24(bitmap: RGBBitmap, *, top_down: bool = False) -> BitmapData
Build a 40-byte BITMAPINFOHEADER and DWORD-aligned BGR scanlines.
encode_dib
def encode_dib(width,
height,
samples,
*,
depth,
colors=(),
masks=None,
header_size=40,
top_down=False,
rle=False,
color_usage=0)
Record exact integer pixels, without quantization or palette selection.
Indexed samples are table indexes; direct-colour samples are packed words in the requested RGB/mask layout. Samples are supplied top-to-bottom. For DIB_PAL_COLORS, colors contains WORD logical-palette indexes instead of RGB triples. DIB_PAL_INDICES has no table.
DIBLayout Objects
@dataclass(frozen=True)
class DIBLayout()
Validated packed layout, before choosing full-image or scan-band decoding.
complete
@property
def complete() -> bool
Whether the packed object contains the entire declared image.
decode
def decode(rows: int | None = None,
*,
replicate_channels=True,
preserve_gaps=False,
palette=None,
clip_spans=None,
gap_color=None) -> RGBBitmap
Decode rows from the beginning of the pixel buffer, not a row offset.
For direct RLE scans, clip_spans provides top-down clip intervals.
gap_color selects a realized background instead of palette index 0;
preserve_gaps retains coverage so unwritten pixels can be skipped.
index
def index(x, y, *, rows=None)
Read an uncompressed indexed sample in top-down coordinates.
read_dib
def read_dib(bitmap: BitmapData,
*,
color_usage: int = 0,
max_pixels: int = DEFAULT_MAX_BITMAP_PIXELS) -> DIBLayout
Validate the supported packed DIB layout without allocating pixels.
Core/Info/V4/V5, RGB tables, direct RGB, bitfields and RLE4/RLE8. Logical-palette references remain unresolved until decoding. The decoder checks the required pixel extent; bands may omit other rows.
decode_dib
def decode_dib(bitmap: BitmapData,
*,
color_usage: int = 0,
max_pixels: int = DEFAULT_MAX_BITMAP_PIXELS,
palette=None) -> RGBBitmap
Decode a complete packed DIB into immutable top-down RGB pixels.
pillow_wmf.mapping
Logical-to-device coordinate state for the Windows reference bitmap profile.
fixed
def fixed(value: float) -> int
Convert to signed 28.4; exact half-unit ties go away from zero.
Mapping Objects
@dataclass
class Mapping()
linear_scale
@property
def linear_scale()
Signed linear transform for pen support and logical directions.
Point mapping separately preserves native product/translation rounding.
translation_only
@property
def translation_only() -> bool
Whether the realized FLOAT transform leaves both axes unchanged.
clip_point
def clip_point(x: int, y: int) -> tuple[int, int]
Rectangular clip edges use the driver’s fixed-point transform.
edge_point
def edge_point(x: int, y: int) -> tuple[int, int]
Map half-open device edges, rather than inclusive pixel centres.
device_point
def device_point(x: int, y: int) -> tuple[int, int]
Driver coordinates: quantize translation and product to 28.4.
The translation is realized separately, not reassociated with the
logical coordinate as (value - window_origin) * scale. Both stages
precede pixel rounding, which matters near half-pixel boundaries.
Driver scale coefficients and products are single precision before
fixed-point conversion; retaining Python doubles can miss a tie.
point retains the separate LPtoDP-style integer conversion.
fixed_point
def fixed_point(x, y)
Map a point without discarding its device-space sixteenths.
clip_displacement
def clip_displacement(x: int, y: int) -> tuple[int, int]
OffsetClipRgn rounds transformed distances symmetrically at ties.
pillow_wmf.gdi
GDI command interface used by recorders, trace sinks and future raster devices.
The interface retains primitive identity and logical coordinates. It does not claim to implement rasterization or the complete Windows device-context state.
UnsupportedOperation Objects
class UnsupportedOperation(NotImplementedError)
A backend does not implement this operation.
InvalidOperation Objects
class InvalidOperation(ValueError)
Invalid call data rejected before the backend changes drawing state.
PreparedCall Objects
@dataclass(frozen=True)
class PreparedCall()
Opaque, single-use preparation tied to one context revision.
Callers must not construct or modify these tokens. Preparation may warm caches but does not publish handles, append commands or draw pixels. Backends flag predicted null creations and recorders flag operations whose playback semantics differ, so a recording pair can reject them in advance.
GDI Objects
class GDI()
Override invoke to implement a backend. Arguments are immutable values.
is_null_object
def is_null_object(handle: Handle) -> bool
Whether a creation produced a native null object rather than a resource.
Logical handles still represent failed creations for subsequent calls; emulating backends may share a typed null handle across failures. WMF playback uses this result to preserve native file-slot allocation. Non-emulating backends may retain the default successful-creation model.
prepare
def prepare(call: Call) -> PreparedCall
Validate without drawing; backends must opt into staged execution.
apply
def apply(prepared: PreparedCall) -> Handle | int | None
Apply an unchanged preparation; execution failures are fatal.
set_dib_to_device
def set_dib_to_device(x: int, y: int, width: int, height: int, src_x: int,
src_y: int, start_scan: int, scan_count: int,
color_usage: int, source: BitmapData) -> None
Transfer a band from a complete packed DIB using logical coordinates.