madam.image module

class madam.image.FlipOrientation(value)[source]

Bases: Enum

Represents an axis for image flip operations.

HORIZONTAL = 0

Horizontal axis

VERTICAL = 1

Vertical axis

class madam.image.PillowProcessor(config: Mapping[str, Any] | None = None)[source]

Bases: Processor

Represents a processor that uses Pillow as a backend.

__init__(config: Mapping[str, Any] | None = None) None[source]

Initializes a new PillowProcessor.

Parameters:

config – Mapping with settings.

adjust_brightness(asset: Asset, factor: float) Asset[source]

Creates a new asset whose essence has adjusted brightness.

A factor of 0.0 produces a black image. A factor of 1.0 returns an image identical to the input. Values above 1.0 increase brightness; values between 0.0 and 1.0 decrease it.

Parameters:
  • asset (Asset) – Asset whose brightness will be adjusted

  • factor (float) – Brightness enhancement factor; 1.0 means no change

Returns:

Asset with adjusted brightness

Return type:

Asset

adjust_contrast(asset: Asset, factor: float) Asset[source]

Creates a new asset whose essence has adjusted contrast.

A factor of 0.0 produces a solid gray image (the mean color of the original). A factor of 1.0 returns an image identical to the input. Values above 1.0 increase contrast; values between 0.0 and 1.0 decrease it.

Parameters:
  • asset (Asset) – Asset whose contrast will be adjusted

  • factor (float) – Contrast enhancement factor; 1.0 means no change

Returns:

Asset with adjusted contrast

Return type:

Asset

adjust_saturation(asset: Asset, factor: float) Asset[source]

Creates a new asset whose essence has adjusted color saturation.

A factor of 0.0 produces a greyscale image. A factor of 1.0 returns an image identical to the input. Values above 1.0 increase saturation; values between 0.0 and 1.0 decrease it.

Parameters:
  • asset (Asset) – Asset whose saturation will be adjusted

  • factor (float) – Saturation enhancement factor; 1.0 means no change

Returns:

Asset with adjusted saturation

Return type:

Asset

adjust_sharpness(asset: Asset, factor: float) Asset[source]

Creates a new asset whose essence has adjusted sharpness.

A factor of 0.0 produces a blurred (smoothed) image. A factor of 1.0 returns an image identical to the input. Values above 1.0 sharpen the image; values between 0.0 and 1.0 blur it.

Parameters:
  • asset (Asset) – Asset whose sharpness will be adjusted

  • factor (float) – Sharpness enhancement factor; 1.0 means no change

Returns:

Asset with adjusted sharpness

Return type:

Asset

apply_mask(asset: Asset, mask_asset: Asset) Asset[source]

Creates a new asset whose alpha channel is replaced by a mask image.

The luminance of mask_asset controls the alpha of the output: white (255) is fully opaque and black (0) is fully transparent. mask_asset must have the same dimensions as the base image. The output is always an RGBA PNG image.

Parameters:
  • asset (Asset) – Base image Asset

  • mask_asset (Asset) – Greyscale mask Asset; must match the base dimensions

Returns:

RGBA PNG Asset with the mask applied as its alpha channel

Return type:

Asset

auto_orient(asset: Asset) Asset[source]

Creates a new asset whose essence is rotated according to the Exif orientation. If no orientation metadata exists or asset is not rotated, an identical asset object is returned.

Parameters:

asset (Asset) – Asset with orientation metadata

Returns:

Asset with rotated essence

Return type:

Asset

blur(asset: Asset, radius: float = 2) Asset[source]

Creates a new asset whose essence is blurred using a Gaussian kernel.

Higher radius values produce stronger blur. A radius of 0 leaves the image unchanged.

Parameters:
  • asset (Asset) – Asset whose essence will be blurred

  • radius (float) – Blur radius in pixels; 0 means no blur

Returns:

Asset with blurred essence

Return type:

Asset

can_read(file: IO) bool[source]

Returns whether the specified MIME type is supported by this processor.

Parameters:

file (IO) – file-like object to be tested

Returns:

whether the data format of the specified file is supported or not

Return type:

bool

composite(asset: Asset, overlay_asset: Asset, x: int = 0, y: int = 0, gravity: str = 'north_west', opacity: float = 1.0) Asset[source]

Creates a new asset whose essence has another image composited on top.

The overlay_asset is placed over the base image at the position determined by (x, y) or gravity. When both x/y and gravity are specified, gravity is ignored and (x, y) is used directly. opacity scales the overlay’s alpha channel.

Parameters:
  • asset (Asset) – Base image asset

  • overlay_asset (Asset) – Asset to composite over the base

  • x (int) – Horizontal offset of the overlay from the left edge

  • y (int) – Vertical offset of the overlay from the top edge

  • gravity (str) – Anchor position when x and y are both 0; valid values are 'north_west', 'north', 'north_east', 'west', 'center', 'east', 'south_west', 'south', 'south_east'

  • opacity (float) – Overlay opacity in the range [0.0, 1.0]

Returns:

Asset with overlay composited onto the base

Return type:

Asset

convert(asset: Asset, mime_type: MimeType | str, color_space: str | None = None, depth: int | None = None, data_type: str | None = None) Asset[source]

Creates a new asset of the specified MIME type from the essence of the specified asset.

Parameters:
  • asset (Asset) – Asset whose contents will be converted

  • mime_type (MimeType or str) – Target MIME type

  • color_space (str or None) – Name of color space

  • depth (int or None) – Bit depth per channel

  • data_type (str or None) – Data type of the pixels, e.g. ‘uint’ or ‘float’

Returns:

New asset with converted essence

Return type:

Asset

crop(asset: Asset, *, width: int, height: int, x: int | None = None, y: int | None = None, gravity: str = 'north_west') Asset[source]

Creates a new asset whose essence is cropped to the specified rectangular area.

When x and y are both None (the default), the crop window is positioned using gravity. When either coordinate is supplied explicitly, both must be provided and gravity is ignored.

Valid gravity values: 'north_west', 'north', 'north_east', 'west', 'center', 'east', 'south_west', 'south', 'south_east'.

Parameters:
  • asset (Asset) – Asset whose contents will be cropped

  • width (int) – Width of the cropping area

  • height (int) – Height of the cropping area

  • x (int or None) – Horizontal offset of the cropping area from the left edge, or None to derive from gravity

  • y (int or None) – Vertical offset of the cropping area from the top edge, or None to derive from gravity

  • gravity (str) – Anchor position used when x and y are not specified

Returns:

New asset with cropped essence

Return type:

Asset

crop_to_focal_point(asset: Asset, width: int, height: int, focal_x: float, focal_y: float) Asset[source]

Creates a new asset cropped to the given dimensions, keeping the specified focal point as close to the center of the output as possible.

The focal point is expressed as relative coordinates in the range [0.0, 1.0], where (0.0, 0.0) is the top-left corner and (1.0, 1.0) is the bottom-right corner. The crop window is centered on the focal point and clamped so it stays within the image bounds.

This operator is intentionally geometry-only: the caller is responsible for computing the focal-point coordinates via face detection, saliency analysis, or any other content-aware strategy.

Parameters:
  • asset (Asset) – Asset whose essence will be cropped

  • width (int) – Crop width in pixels; must not exceed the source width

  • height (int) – Crop height in pixels; must not exceed the source height

  • focal_x (float) – Horizontal focal-point coordinate in [0.0, 1.0]

  • focal_y (float) – Vertical focal-point coordinate in [0.0, 1.0]

Returns:

Asset with cropped essence centered on the focal point

Return type:

Asset

Raises:

OperatorError – If the crop dimensions exceed the source dimensions

extract_frame(asset: Asset, frame: int = 0) Asset[source]

Extracts a single frame from an animated image asset as a static image.

The returned asset has the same MIME type as the source. Use frame_count from the asset metadata to know how many frames are available.

Parameters:
  • asset (Asset) – Animated image asset (GIF, WebP, …)

  • frame (int) – Zero-based frame index

Returns:

Static image asset for the requested frame

Return type:

Asset

Raises:

OperatorError – if frame is out of range

fill_background(asset: Asset, color: tuple[int, int, int]) Asset[source]

Creates a new asset whose alpha channel is merged into a solid colour background.

Transparent and semi-transparent pixels are composited over the specified background colour. If the source image has no alpha channel, the pixels are returned unchanged. The output is always an opaque RGB image in the same format as the input.

Parameters:
  • asset (Asset) – Asset whose essence will have its background filled

  • color (tuple[int, int, int]) – Background colour as an (red, green, blue) tuple with values in the range [0, 255]

Returns:

Asset with alpha composited over the fill colour

Return type:

Asset

flip(asset: Asset, orientation: FlipOrientation) Asset[source]

Creates a new asset whose essence is flipped according the specified orientation.

Parameters:
  • asset (Asset) – Asset whose essence is to be flipped

  • orientation (FlipOrientation) – axis of the flip operation

Returns:

Asset with flipped essence

Return type:

Asset

optimize_quality(asset: Asset, min_ssim_score: float = 80.0, mime_type: str | MimeType | None = None, min_quality: int = 20, max_quality: int = 95) Asset[source]

Re-encodes asset at the lowest quality whose SSIMULACRA2 score against the original is at least min_ssim_score.

SSIMULACRA2 is a perceptual quality metric in (−∞, 100] where 100 means identical. Typical thresholds: ≥ 90 nearly imperceptible, ≥ 80 good quality, ≥ 70 acceptable.

The operator binary-searches quality values in [min_quality, max_quality] (Pillow quality scale, 1–95) and returns the highest-compression encoding that still meets the score threshold. If no quality value satisfies the constraint the result is encoded at max_quality (best achievable).

Accepts lossless source formats (PNG, TIFF, …) when mime_type names a lossy target format. Requires the ssimulacra2 optional dependency (pip install "madam[analysis]").

Supported output formats: JPEG, WebP, AVIF.

Parameters:
  • asset – Source image asset (any format readable by Pillow)

  • min_ssim_score – Minimum acceptable SSIMULACRA2 score (default 80.0)

  • mime_type – Output MIME type; defaults to the asset’s own MIME type

  • min_quality – Lower bound for Pillow quality value (1–95)

  • max_quality – Upper bound for Pillow quality value (1–95)

Returns:

Re-encoded image asset

Raises:

OperatorError – if the target format does not support quality-based compression, or if ssimulacra2 is not installed

pad(asset: Asset, width: int, height: int, color: tuple[int, int, int] | tuple[int, int, int, int] = (0, 0, 0, 0), gravity: str = 'center') Asset[source]

Creates a new asset whose essence is placed on a larger canvas.

The source image is pasted onto a canvas of size (width, height) filled with color. The position on the canvas is determined by gravity.

Valid gravity values: 'north_west', 'north', 'north_east', 'west', 'center', 'east', 'south_west', 'south', 'south_east'.

Parameters:
  • asset (Asset) – Asset whose essence will be padded

  • width (int) – Canvas width; must be >= the source image width

  • height (int) – Canvas height; must be >= the source image height

  • color (tuple) – Fill color for the added area as an RGB or RGBA tuple

  • gravity (str) – Anchor position of the source image on the canvas

Returns:

Asset with padded essence

Return type:

Asset

Raises:

OperatorError – If the canvas is smaller than the source image

read(file: IO) Asset[source]

Returns an Asset object whose essence is identical to the contents of the specified file.

Parameters:

file (IO) – file-like object to be read

Returns:

Asset with essence

Return type:

Asset

Raises:

UnsupportedFormatError – if the specified data format is not supported

resize(asset: Asset, width: int, height: int, mode: ResizeMode = ResizeMode.EXACT, gravity: str = 'center') Asset[source]

Creates a new Asset whose essence is resized according to the specified parameters.

In FILL mode the image is scaled up until it covers the target dimensions, then cropped to the exact target size. The gravity parameter controls which part of the scaled image is kept; it has no effect in EXACT or FIT mode.

Valid gravity values: 'north_west', 'north', 'north_east', 'west', 'center', 'east', 'south_west', 'south', 'south_east'.

Parameters:
  • asset (Asset) – Asset to be resized

  • width (int) – Target width in pixels

  • height (int) – Target height in pixels

  • mode (ResizeMode) – Resize behavior

  • gravity (str) – Crop anchor used in FILL mode

Returns:

Asset with resized essence

Return type:

Asset

rotate(asset: Asset, angle: float, expand: bool = False) Asset[source]

Creates an asset whose essence is rotated by the specified angle in degrees.

Parameters:
  • asset (Asset) – Asset whose contents will be rotated

  • angle (float) – Angle in degrees, counter clockwise

  • expand (bool) – If true, changes the dimensions of the new asset so it can hold the entire rotated essence, otherwise the dimensions of the original asset will be used.

Returns:

New asset with rotated essence

Return type:

Asset

round_corners(asset: Asset, radius: int) Asset[source]

Creates a new asset whose essence has rounded corners.

The corners are cut to the specified radius using a smooth circular mask. Pixels outside the rounded rectangle become fully transparent. The output is always an RGBA PNG image.

Parameters:
  • asset (Asset) – Asset whose corners will be rounded

  • radius (int) – Corner radius in pixels

Returns:

RGBA PNG Asset with rounded corners

Return type:

Asset

sepia(asset: Asset) Asset[source]

Creates a new asset whose essence has a sepia tone applied.

The image is first converted to greyscale, then colorised with warm brown tones characteristic of historical photographs. The output is always an RGB image in the same format as the input.

Parameters:

asset (Asset) – Asset whose essence will be toned

Returns:

Asset with sepia-toned essence

Return type:

Asset

sharpen(asset: Asset, radius: float = 2, percent: int = 150, threshold: int = 3) Asset[source]

Creates a new asset whose essence is sharpened using an unsharp mask.

The unsharp mask works by subtracting a blurred version of the image from itself. Higher percent values produce stronger sharpening; threshold controls which pixel differences are sharpened.

Parameters:
  • asset (Asset) – Asset whose essence will be sharpened

  • radius (float) – Blur radius for the unsharp mask

  • percent (int) – Strength of the sharpening effect as a percentage

  • threshold (int) – Minimum brightness difference to sharpen

Returns:

Asset with sharpened essence

Return type:

Asset

property supported_mime_types: frozenset

MIME types this processor can handle (used to build the Madam index).

tint(asset: Asset, color: tuple[int, int, int], opacity: float = 0.5) Asset[source]

Creates a new asset whose essence is tinted with the specified color.

The tint is blended over the image at the given opacity. An opacity of 0.0 leaves the image unchanged; 1.0 fills it entirely with color. The output is always an RGB image in the same format as the input.

Parameters:
  • asset (Asset) – Asset whose essence will be tinted

  • color (tuple[int, int, int]) – RGB tint color as a (red, green, blue) tuple with values in the range [0, 255]

  • opacity (float) – Tint opacity in the range [0.0, 1.0]

Returns:

Asset with tinted essence

Return type:

Asset

transpose(asset: Asset) Asset[source]

Creates a new image asset whose essence is the transpose of the specified asset’s essence.

Parameters:

asset (Asset) – Image asset whose essence is to be transposed

Returns:

New image asset with transposed essence

Return type:

Asset

vignette(asset: Asset, strength: float = 0.5) Asset[source]

Creates a new asset whose essence has a radial vignette applied.

The vignette darkens the edges of the image while leaving the center unaffected. strength controls how much darkening is applied at the corners: 0.0 leaves the image unchanged; 1.0 makes the corners completely black.

Parameters:
  • asset (Asset) – Asset whose essence will receive the vignette

  • strength (float) – Vignette intensity in the range [0.0, 1.0]

Returns:

Asset with vignette applied

Return type:

Asset

class madam.image.ResizeMode(value)[source]

Bases: Enum

Represents a behavior for image resize operations.

EXACT = 0

Image exactly matches the specified dimensions

FILL = 2

Image is resized to completely fill the specified dimensions

FIT = 1

Image is resized to fit completely into the specified dimensions

madam.image.extract_palette(asset: Asset, count: int = 5) list[tuple[int, int, int]][source]

Extract the dominant colors from an image asset.

Quantizes the image to count representative colors using Pillow’s median-cut algorithm and returns them as (r, g, b) tuples sorted by frequency (most frequent color first).

The returned list contains at most count entries; it may be shorter if the image has fewer unique colors than count.

Parameters:
  • asset – Source image asset (any format readable by Pillow)

  • count – Maximum number of colors to return (default 5)

Returns:

List of (r, g, b) tuples sorted by pixel frequency, descending

madam.image.render_text(text: str, font_path: str | None = None, font_size: int = 24, color: tuple[int, int, int] = (0, 0, 0), background: tuple[int, int, int, int] = (0, 0, 0, 0), padding: int = 0) Asset[source]

Renders the given text into a new RGBA PNG image Asset.

The canvas is sized to fit the text exactly, with an optional uniform padding added on all sides. A system font is used when font_path is None.

Parameters:
  • text (str) – Text string to render

  • font_path (str or None) – Path to a TrueType or OpenType font file, or None to use the default Pillow font

  • font_size (int) – Font size in points (ignored when font_path is None because the default font has a fixed size)

  • color (tuple[int, int, int]) – Text color as an (red, green, blue) tuple

  • background (tuple[int, int, int, int]) – Canvas background color as an (r, g, b, alpha) tuple; defaults to fully transparent

  • padding (int) – Uniform padding in pixels added around the text

Returns:

RGBA PNG Asset containing the rendered text

Return type:

Asset