madam.image module
- class madam.image.FlipOrientation(value)[source]
Bases:
EnumRepresents an axis for image flip operations.
- HORIZONTAL = 0
Horizontal axis
- VERTICAL = 1
Vertical axis
- class madam.image.Gravity(value)[source]
Bases:
StrEnumNamed anchor positions for operators that place or crop images.
Because
Gravityis aStrEnum, 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:
ProcessingContextDeferred in-memory state for a Pillow processing run.
Holds a live
PIL.Image.Imageand the target MIME type so that consecutive Pillow operators can be applied to the pixel data without intermediate encode/decode cycles. Callmaterialize()to produce the final encodedAsset.Instances are created by
PillowProcessorand passed toexecute_run(). Custom operator implementations can inspect or mutateimageandmime_typebefore 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.Imageobject.mime_type (str) – MIME type string that controls the output format when
materialize()encodes the image. Changing this attribute is equivalent to inserting aconvert()step.
Added in version 1.0.
- __init__(processor: PillowProcessor, image: Image, mime_type: str) None[source]
- property processor: PillowProcessor
The
Processorthat owns this context.
- class madam.image.PillowProcessor(config: Mapping[str, Any] | None = None)[source]
Bases:
ProcessorRepresents 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.0produces a black image. A factor of1.0returns an image identical to the input. Values above1.0increase brightness; values between0.0and1.0decrease it.
- adjust_contrast(asset: Asset, factor: float) Asset[source]
Creates a new asset whose essence has adjusted contrast.
A factor of
0.0produces a solid gray image (the mean color of the original). A factor of1.0returns an image identical to the input. Values above1.0increase contrast; values between0.0and1.0decrease it.
- adjust_saturation(asset: Asset, factor: float) Asset[source]
Creates a new asset whose essence has adjusted color saturation.
A factor of
0.0produces a greyscale image. A factor of1.0returns an image identical to the input. Values above1.0increase saturation; values between0.0and1.0decrease it.
- adjust_sharpness(asset: Asset, factor: float) Asset[source]
Creates a new asset whose essence has adjusted sharpness.
A factor of
0.0produces a blurred (smoothed) image. A factor of1.0returns an image identical to the input. Values above1.0sharpen the image; values between0.0and1.0blur it.
- 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_assetcontrols the alpha of the output: white (255) is fully opaque and black (0) is fully transparent.mask_assetmust have the same dimensions as the base image. The output is always an RGBA PNG image.
- 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.
- blur(asset: Asset, radius: float = 2) Asset[source]
Creates a new asset whose essence is blurred using a Gaussian kernel.
Higher
radiusvalues produce stronger blur. Aradiusof0leaves the image unchanged.
- 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:
- 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_assetis placed over the base image at the position determined by(x, y)orgravity. When bothx/yandgravityare specified,gravityis ignored and(x, y)is used directly.opacityscales 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
xandyare both0; 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:
- 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:
- Returns:
New asset with converted essence
- Return type:
- 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
xandyare bothNone(the default), the crop window is positioned usinggravity. When either coordinate is supplied explicitly, both must be provided andgravityis ignored.gravity may be a
Gravitymember or the equivalent plain string (seeGravityfor 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
Noneto derive fromgravityy (int or None) – Vertical offset of the cropping area from the top edge, or
Noneto derive fromgravitygravity (Gravity or str) – Anchor position used when
xandyare not specified
- Returns:
New asset with cropped essence
- Return type:
- 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:
- 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 incomingPillowContextfrom a prior run) is decoded once. Each step’s PIL image transform is applied in memory. The result is returned as aPillowContext;Pipelineencodes 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_countfrom the asset metadata to know how many frames are available.- Parameters:
- Returns:
Static image asset for the requested frame
- Return type:
- 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.
- 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:
- 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
qualityscale, 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
ssimulacra2optional 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 withcolor. The position on the canvas is determined bygravity.gravity may be a
Gravitymember or the equivalent plain string (seeGravityfor 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:
- Raises:
OperatorError – If the canvas is smaller than the source image
- read(file: IO) Asset[source]
Returns an
Assetobject 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:
- 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
FILLmode the image is scaled up until it covers the target dimensions, then cropped to the exact target size. Thegravityparameter controls which part of the scaled image is kept; it has no effect inEXACTorFITmode.gravity may be a
Gravitymember or the equivalent plain string (seeGravityfor the full list of values).
- rotate(asset: Asset, angle: float, expand: bool = False) Asset[source]
Creates an asset whose essence is rotated by the specified angle in degrees.
- Parameters:
- Returns:
New asset with rotated essence
- Return type:
- round_corners(asset: Asset, radius: int) Asset[source]
Creates a new asset whose essence has rounded corners.
The corners are cut to the specified
radiususing a smooth circular mask. Pixels outside the rounded rectangle become fully transparent. The output is always an RGBA PNG image.
- 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.
- 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
percentvalues produce stronger sharpening;thresholdcontrols which pixel differences are sharpened.
- 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
opacityof0.0leaves the image unchanged;1.0fills it entirely withcolor. The output is always an RGB image in the same format as the input.
- transpose(asset: Asset) Asset[source]
Creates a new image asset whose essence is the transpose of the specified asset’s essence.
- 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.
strengthcontrols how much darkening is applied at the corners:0.0leaves the image unchanged;1.0makes the corners completely black.
- class madam.image.ResizeMode(value)[source]
Bases:
EnumRepresents 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:
- Returns:
Animated image asset
- Return type:
- Raises:
ValueError – If assets is empty
UnsupportedFormatError – If mime_type is not
'image/gif'or'image/webp'OperatorError – If Pillow cannot decode an asset
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
paddingadded on all sides. A system font is used whenfont_pathisNone.- Parameters:
text (str) – Text string to render
font_path (str or None) – Path to a TrueType or OpenType font file, or
Noneto use the default Pillow fontfont_size (int) – Font size in points (ignored when
font_pathisNonebecause the default font has a fixed size)color (tuple[int, int, int]) – Text color as an
(red, green, blue)tuplebackground (tuple[int, int, int, int]) – Canvas background color as an
(r, g, b, alpha)tuple; defaults to fully transparentpadding (int) – Uniform padding in pixels added around the text
- Returns:
RGBA PNG Asset containing the rendered text
- Return type:
Added in version 0.24.