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.Gravity(value)[source]

Bases: StrEnum

Named anchor positions for operators that place or crop images.

Because Gravity is a StrEnum, each member compares equal to its string value and can be passed wherever a plain gravity string is accepted:

from madam.image import Gravity

crop = processor.crop(width=800, height=600, gravity=Gravity.CENTER)
# equivalent to: processor.crop(width=800, height=600, gravity='center')

Members and their string values:

Member

String value

NORTH_WEST

'north_west'

NORTH

'north'

NORTH_EAST

'north_east'

WEST

'west'

CENTER

'center'

EAST

'east'

SOUTH_WEST

'south_west'

SOUTH

'south'

SOUTH_EAST

'south_east'

Added in version 1.0.

__init__(*args, **kwds)
capitalize()

Return a capitalized version of the string.

More specifically, make the first character have upper case and the rest lower case.

casefold()

Return a version of the string suitable for caseless comparisons.

center(width, fillchar=' ', /)

Return a centered string of length width.

Padding is done using the specified fill character (default is a space).

count(sub[, start[, end]]) int

Return the number of non-overlapping occurrences of substring sub in string S[start:end]. Optional arguments start and end are interpreted as in slice notation.

encode(encoding='utf-8', errors='strict')

Encode the string using the codec registered for encoding.

encoding

The encoding in which to encode the string.

errors

The error handling scheme to use for encoding errors. The default is ‘strict’ meaning that encoding errors raise a UnicodeEncodeError. Other possible values are ‘ignore’, ‘replace’ and ‘xmlcharrefreplace’ as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors.

endswith(suffix[, start[, end]]) bool

Return True if S ends with the specified suffix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. suffix can also be a tuple of strings to try.

expandtabs(tabsize=8)

Return a copy where all tab characters are expanded using spaces.

If tabsize is not given, a tab size of 8 characters is assumed.

find(sub[, start[, end]]) int

Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

Return -1 on failure.

format(*args, **kwargs) str

Return a formatted version of S, using substitutions from args and kwargs. The substitutions are identified by braces (‘{’ and ‘}’).

format_map(mapping) str

Return a formatted version of S, using substitutions from mapping. The substitutions are identified by braces (‘{’ and ‘}’).

index(sub[, start[, end]]) int

Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

Raises ValueError when the substring is not found.

isalnum()

Return True if the string is an alpha-numeric string, False otherwise.

A string is alpha-numeric if all characters in the string are alpha-numeric and there is at least one character in the string.

isalpha()

Return True if the string is an alphabetic string, False otherwise.

A string is alphabetic if all characters in the string are alphabetic and there is at least one character in the string.

isascii()

Return True if all characters in the string are ASCII, False otherwise.

ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too.

isdecimal()

Return True if the string is a decimal string, False otherwise.

A string is a decimal string if all characters in the string are decimal and there is at least one character in the string.

isdigit()

Return True if the string is a digit string, False otherwise.

A string is a digit string if all characters in the string are digits and there is at least one character in the string.

isidentifier()

Return True if the string is a valid Python identifier, False otherwise.

Call keyword.iskeyword(s) to test whether string s is a reserved identifier, such as “def” or “class”.

islower()

Return True if the string is a lowercase string, False otherwise.

A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.

isnumeric()

Return True if the string is a numeric string, False otherwise.

A string is numeric if all characters in the string are numeric and there is at least one character in the string.

isprintable()

Return True if the string is printable, False otherwise.

A string is printable if all of its characters are considered printable in repr() or if it is empty.

isspace()

Return True if the string is a whitespace string, False otherwise.

A string is whitespace if all characters in the string are whitespace and there is at least one character in the string.

istitle()

Return True if the string is a title-cased string, False otherwise.

In a title-cased string, upper- and title-case characters may only follow uncased characters and lowercase characters only cased ones.

isupper()

Return True if the string is an uppercase string, False otherwise.

A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.

join(iterable, /)

Concatenate any number of strings.

The string whose method is called is inserted in between each given string. The result is returned as a new string.

Example: ‘.’.join([‘ab’, ‘pq’, ‘rs’]) -> ‘ab.pq.rs’

ljust(width, fillchar=' ', /)

Return a left-justified string of length width.

Padding is done using the specified fill character (default is a space).

lower()

Return a copy of the string converted to lowercase.

lstrip(chars=None, /)

Return a copy of the string with leading whitespace removed.

If chars is given and not None, remove characters in chars instead.

static maketrans()

Return a translation table usable for str.translate().

If there is only one argument, it must be a dictionary mapping Unicode ordinals (integers) or characters to Unicode ordinals, strings or None. Character keys will be then converted to ordinals. If there are two arguments, they must be strings of equal length, and in the resulting dictionary, each character in x will be mapped to the character at the same position in y. If there is a third argument, it must be a string, whose characters will be mapped to None in the result.

partition(sep, /)

Partition the string into three parts using the given separator.

This will search for the separator in the string. If the separator is found, returns a 3-tuple containing the part before the separator, the separator itself, and the part after it.

If the separator is not found, returns a 3-tuple containing the original string and two empty strings.

removeprefix(prefix, /)

Return a str with the given prefix string removed if present.

If the string starts with the prefix string, return string[len(prefix):]. Otherwise, return a copy of the original string.

removesuffix(suffix, /)

Return a str with the given suffix string removed if present.

If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. Otherwise, return a copy of the original string.

replace(old, new, count=-1, /)

Return a copy with all occurrences of substring old replaced by new.

count

Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences.

If the optional argument count is given, only the first count occurrences are replaced.

rfind(sub[, start[, end]]) int

Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

Return -1 on failure.

rindex(sub[, start[, end]]) int

Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.

Raises ValueError when the substring is not found.

rjust(width, fillchar=' ', /)

Return a right-justified string of length width.

Padding is done using the specified fill character (default is a space).

rpartition(sep, /)

Partition the string into three parts using the given separator.

This will search for the separator in the string, starting at the end. If the separator is found, returns a 3-tuple containing the part before the separator, the separator itself, and the part after it.

If the separator is not found, returns a 3-tuple containing two empty strings and the original string.

rsplit(sep=None, maxsplit=-1)

Return a list of the substrings in the string, using sep as the separator string.

sep

The separator used to split the string.

When set to None (the default value), will split on any whitespace character (including n r t f and spaces) and will discard empty strings from the result.

maxsplit

Maximum number of splits. -1 (the default value) means no limit.

Splitting starts at the end of the string and works to the front.

rstrip(chars=None, /)

Return a copy of the string with trailing whitespace removed.

If chars is given and not None, remove characters in chars instead.

split(sep=None, maxsplit=-1)

Return a list of the substrings in the string, using sep as the separator string.

sep

The separator used to split the string.

When set to None (the default value), will split on any whitespace character (including n r t f and spaces) and will discard empty strings from the result.

maxsplit

Maximum number of splits. -1 (the default value) means no limit.

Splitting starts at the front of the string and works to the end.

Note, str.split() is mainly useful for data that has been intentionally delimited. With natural text that includes punctuation, consider using the regular expression module.

splitlines(keepends=False)

Return a list of the lines in the string, breaking at line boundaries.

Line breaks are not included in the resulting list unless keepends is given and true.

startswith(prefix[, start[, end]]) bool

Return True if S starts with the specified prefix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. prefix can also be a tuple of strings to try.

strip(chars=None, /)

Return a copy of the string with leading and trailing whitespace removed.

If chars is given and not None, remove characters in chars instead.

swapcase()

Convert uppercase characters to lowercase and lowercase characters to uppercase.

title()

Return a version of the string where each word is titlecased.

More specifically, words start with uppercased characters and all remaining cased characters have lower case.

translate(table, /)

Replace each character in the string using the given translation table.

table

Translation table, which must be a mapping of Unicode ordinals to Unicode ordinals, strings, or None.

The table must implement lookup/indexing via __getitem__, for instance a dictionary or list. If this operation raises LookupError, the character is left untouched. Characters mapped to None are deleted.

upper()

Return a copy of the string converted to uppercase.

zfill(width, /)

Pad a numeric string with zeros on the left, to fill a field of the given width.

The string is never truncated.

class madam.image.PillowContext(processor: PillowProcessor, image: Image, mime_type: str)[source]

Bases: ProcessingContext

Deferred in-memory state for a Pillow processing run.

Holds a live PIL.Image.Image and the target MIME type so that consecutive Pillow operators can be applied to the pixel data without intermediate encode/decode cycles. Call materialize() to produce the final encoded Asset.

Instances are created by PillowProcessor and passed to execute_run(). Custom operator implementations can inspect or mutate image and mime_type before the result is materialised.

Variables:
  • image (PIL.Image.Image) – The live Pillow image being transformed. Operators may replace this attribute with a new PIL.Image.Image object.

  • mime_type (str) – MIME type string that controls the output format when materialize() encodes the image. Changing this attribute is equivalent to inserting a convert() step.

Added in version 1.0.

__init__(processor: PillowProcessor, image: Image, mime_type: str) None[source]
materialize() Asset[source]

Encode and return the final Asset.

property processor: PillowProcessor

The Processor that owns this context.

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: 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 (Gravity or 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: 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.

gravity may be a Gravity member or the equivalent plain string (see Gravity for the full list of values).

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 (Gravity or 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

execute_run(steps, asset_or_context)[source]

Apply a group of consecutive Pillow operators in a single decode/encode cycle.

The input Asset (or incoming PillowContext from a prior run) is decoded once. Each step’s PIL image transform is applied in memory. The result is returned as a PillowContext; Pipeline encodes it only when a processor boundary or pipeline end is reached.

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: 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.

gravity may be a Gravity member or the equivalent plain string (see Gravity for the full list of values).

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 (Gravity or 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: 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.

gravity may be a Gravity member or the equivalent plain string (see Gravity for the full list of values).

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

  • width (int) – Target width in pixels

  • height (int) – Target height in pixels

  • mode (ResizeMode) – Resize behavior

  • gravity (Gravity or 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).

Added in version 0.24.

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.combine(assets: Iterable[Asset], mime_type: str, *, duration: int = 100, loop: int = 0) Asset[source]

Assembles a sequence of image assets into an animated GIF or WebP.

Parameters:
  • assets (Iterable[Asset]) – Iterable of image assets to use as frames; must be non-empty

  • mime_type (str) – Output format: 'image/gif' or 'image/webp'

  • duration (int) – Per-frame delay in milliseconds (default 100)

  • loop (int) – Number of animation loops; 0 means infinite (default 0)

Returns:

Animated image asset

Return type:

Asset

Raises:

Added in version 1.0.

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

Added in version 0.24.

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

Added in version 0.24.