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.