alakazam/image
A Gleam library for image manipulation powered by ImageMagick.
Provides a composable, type-safe API for resizing, cropping, filtering, and
converting images through ImageMagick command-line tools. Build image
processing pipelines using Gleam’s pipe operator (|>) and execute them
with a single shell command.
Quick Start
import alakazam/image
pub fn main() {
// Basic resize
image.from_file("input.jpg")
|> image.resize_contain(800, 600)
|> image.to_file("output.jpg")
}
This generates and executes:
magick input.jpg -resize 800x600 output.jpg
Pipeline Operations
Chain multiple transformations that are lazily evaluated when written:
image.from_file("photo.jpg")
|> image.resize_cover(1920, 1080, image.Center)
|> image.sharpen(0.5)
|> image.strip() // Remove metadata
|> image.to_file("hero-banner.jpg")
Color Reduction
Create stylistic effects by reducing the color palette:
// Retro 8-color look with smooth dithering
image.from_file("photo.jpg")
|> image.dither()
|> image.colors(8)
|> image.to_file("retro.png")
// Visible color banding (poster effect)
image.from_file("photo.jpg")
|> image.dither()
|> image.posterize(4) // 4 levels per channel = 64 colors
|> image.to_file("posterized.png")
Debugging
Preview the generated ImageMagick command without executing:
let command =
image.from_file("input.png")
|> image.resize_contain(100, 100)
|> image.to_command("output.png")
// command == "magick input.png -resize 100x100 output.png"
Prerequisites
ImageMagick must be installed and the magick command available in PATH:
# macOS
brew install imagemagick
# Ubuntu/Debian
apt-get install imagemagick
See ImageMagick’s documentation for details on available options and advanced usage.
Security
Processing images with ImageMagick is potentially unsafe. Make sure you read the documentation and understand the security implications before using this library.
There are more information in the README.
Types
Represents an image colorspace.
Used both as input to colorspace/2 and as output in ImageInfo returned
by identify/1. The Unknown variant acts as an escape hatch for
colorspaces not enumerated here (e.g. HSL, Lab, YUV).
pub type Colorspace {
Srgb
Gray
Rgb
Cmyk
YCbCr
Unknown(String)
}
Constructors
-
SrgbStandard RGB with gamma correction (the most common colorspace for web and screen images).
-
GrayGrayscale. See
colorspace/2for the difference betweenGrayandmonochrome/1. -
RgbLinear RGB, without gamma correction.
-
CmykCyan/Magenta/Yellow/Key (Black). Used in print workflows.
-
YCbCrLuma + chroma channels. Used in video and some image compression formats.
-
Unknown(String)A colorspace not covered by the variants above. The string value is passed directly to ImageMagick (e.g.
Unknown("HSL")).
Ordered dithering patterns for use with ordered_dither/2.
Ordered dithering approximates tones by arranging black and white pixels in a fixed spatial pattern rather than random noise. Each family has different visual characteristics:
- Threshold / Checks — simple on/off patterns with no spatial spreading
- Ordered (
o2x2–o8x8) — smooth Bayer matrix patterns; larger matrices produce finer gradients at the cost of more visible structure - Halftone Angled (
h4x4a–h8x8a) — angled halftone dots, similar to traditional print halftoning - Halftone Orthogonal (
h4x4o–h16x16o) — axis-aligned halftone dots - Circles Black/White (
c5x5b–c7x7w) — circular dot patterns on black or white backgrounds
pub type DitherPattern {
Threshold
Checks
Ordered2x2
Ordered3x3
Ordered4x4
Ordered8x8
Halftone4x4Angled
Halftone6x6Angled
Halftone8x8Angled
Halftone4x4Orthogonal
Halftone6x6Orthogonal
Halftone8x8Orthogonal
Halftone16x16Orthogonal
Circles5x5Black
Circles6x6Black
Circles7x7Black
Circles5x5White
Circles6x6White
Circles7x7White
}
Constructors
-
ThresholdFlat threshold: pixels above 50% become white, below become black. No spatial spreading.
-
ChecksCheckerboard pattern at the 50% threshold boundary.
-
Ordered2x22×2 Bayer ordered matrix.
-
Ordered3x33×3 ordered matrix.
-
Ordered4x44×4 Bayer ordered matrix. Good general-purpose choice.
-
Ordered8x88×8 Bayer ordered matrix. Finer gradients, more visible grid structure.
-
Halftone4x4Angled4×4 angled halftone dots.
-
Halftone6x6Angled6×6 angled halftone dots.
-
Halftone8x8Angled8×8 angled halftone dots. Closest to traditional print halftoning.
-
Halftone4x4Orthogonal4×4 orthogonal (axis-aligned) halftone dots.
-
Halftone6x6Orthogonal6×6 orthogonal halftone dots.
-
Halftone8x8Orthogonal8×8 orthogonal halftone dots.
-
Halftone16x16Orthogonal16×16 orthogonal halftone dots. Finest tonal gradients in this family.
-
Circles5x5Black5×5 circular dots on a black background.
-
Circles6x6Black6×6 circular dots on a black background.
-
Circles7x7Black7×7 circular dots on a black background.
-
Circles5x5White5×5 circular dots on a white background.
-
Circles6x6White6×6 circular dots on a white background.
-
Circles7x7White7×7 circular dots on a white background.
Errors that can be returned by fallible operations in this library.
pub type Error {
CannotParseFormat(String)
CannotParseWidth
CannotParseHeight
CannotParseDepth
CannotParseFileSize
CannotIdentify(String)
CommandFailed(exit_code: Int, stderr: String)
CannotWriteTempFile
CannotCreateTempFile
}
Constructors
-
CannotParseFormat(String)The image format string returned by ImageMagick could not be mapped to a known
Formatvariant. The raw string is included for debugging. -
CannotParseWidthThe width value in ImageMagick’s identify output could not be parsed as an integer.
-
CannotParseHeightThe height value in ImageMagick’s identify output could not be parsed as an integer.
-
CannotParseDepthThe bit depth value in ImageMagick’s identify output could not be parsed as an integer.
-
CannotParseFileSizeThe file size value in ImageMagick’s identify output could not be parsed as an integer.
-
CannotIdentify(String)ImageMagick’s identify output could not be interpreted. The raw output string is included for debugging.
-
CommandFailed(exit_code: Int, stderr: String)The ImageMagick command exited with a non-zero status. Includes the exit code and stderr output.
-
CannotWriteTempFileA temporary file was created successfully but writing the image data to it failed. Used by
from_bits/1. -
CannotCreateTempFileThe temporary file itself could not be created. Used by
from_bits/1.
Resampling filters control the algorithm used when resizing images. Different filters are better suited for different types of images.
pub type Filter {
Lanczos
Bicubic
Nearest
Mitchell
Triangle
Catrom
}
Constructors
-
LanczosHigh quality, sharp results with minimal artifacts. Best for photographs and general-purpose resizing.
-
BicubicGood balance of quality and processing speed. A solid general-purpose choice when speed matters.
-
NearestFast, pixelated results without interpolation. Best for pixel art, icons, and images with hard edges.
-
MitchellSmooth results, particularly good for enlarging images. Produces softer results than Lanczos when upscaling.
-
TriangleSimple linear interpolation, fast but lower quality. Good for simple downscaling when performance is critical.
-
CatromSharp edges and good detail preservation. Excellent for text, line art, and images with sharp boundaries.
Controls whether a Width or Height resize is applied conditionally
based on the current image size.
pub type FitMode {
Any
OnlyIfLarger
OnlyIfSmaller
}
Constructors
-
AnyAlways resize, regardless of whether the image is larger or smaller than the target. This is the default behaviour.
-
OnlyIfLargerOnly resize if the image is larger than the target dimensions. Smaller images are left untouched. Maps to the
>geometry flag. -
OnlyIfSmallerOnly resize if the image is smaller than the target dimensions. Larger images are left untouched. Maps to the
<geometry flag.
Output image format, used with to_bits/2 and inferred from the file
extension by to_file/2.
pub type Format {
Png
Bmp
Jpeg
Webp
Pbm
Pgm
Keep
}
Constructors
-
PngPortable Network Graphics. Lossless, supports transparency.
-
BmpWindows Bitmap. Uncompressed, widely compatible.
-
JpegJPEG. Lossy compression, no transparency. Best for photographs.
-
WebpWebP. Modern format with excellent compression and transparency support.
-
PbmPortable Bitmap. 1-bit black and white, plain-text or binary encoding.
-
PgmPortable Graymap. 8-bit grayscale, plain-text or binary encoding.
-
KeepPreserve the original format. When used with
to_bits/2, ImageMagick writes to stdout without re-encoding, keeping the original format and compression intact.
Controls the anchor point for crop and extent operations.
When cropping or padding, gravity determines which part of the image is
kept or where the canvas is anchored. For example, Center crops from
the middle, while NorthWest anchors to the top-left corner.
Set gravity with gravity/2 before a crop or extent/3 call, or pass
it directly to resize_cover/4.
pub type Gravity {
NorthWest
North
NorthEast
West
Center
East
SouthWest
South
SouthEast
}
Constructors
-
NorthWestTop-left corner.
-
NorthTop edge, horizontally centered.
-
NorthEastTop-right corner.
-
WestLeft edge, vertically centered.
-
CenterCenter of the image (default).
-
EastRight edge, vertically centered.
-
SouthWestBottom-left corner.
-
SouthBottom edge, horizontally centered.
-
SouthEastBottom-right corner.
Metadata about an image, returned by identify/1.
pub type ImageInfo {
ImageInfo(
format: Format,
width: Int,
height: Int,
colorspace: Colorspace,
depth: Int,
has_alpha: Bool,
file_size: Int,
)
}
Constructors
-
ImageInfo( format: Format, width: Int, height: Int, colorspace: Colorspace, depth: Int, has_alpha: Bool, file_size: Int, )Arguments
- format
-
The image format (e.g.
Png,Jpeg). - width
-
Image width in pixels.
- height
-
Image height in pixels.
- colorspace
-
The colorspace of the image data (e.g.
Srgb,Gray). - depth
-
Bit depth per channel (e.g. 8 for standard images, 16 for HDR).
- has_alpha
-
Whether the image has an alpha (transparency) channel.
- file_size
-
File size in bytes.
Controls how an image is resized. Each variant maps to a specific ImageMagick geometry flag.
pub type Resize {
Fit(Int, Int)
Fill(Int, Int)
Exact(Int, Int)
Width(Int, FitMode)
Height(Int, FitMode)
Percent(Float)
ResizeArea(Int)
}
Constructors
-
Fit(Int, Int)Fits the image within the given dimensions, preserving aspect ratio. The result will be equal to or smaller than the specified size. Maps to
-resize widthxheight. -
Fill(Int, Int)Resizes the image to fill the given dimensions, preserving aspect ratio. The result will be equal to or larger than the specified size, so some pixels may extend beyond the canvas (use with
extentto crop the overflow). Maps to-resize widthxheight^. -
Exact(Int, Int)Resizes to exactly the given dimensions, ignoring aspect ratio. The image may be distorted. Maps to
-resize widthxheight!. -
Width(Int, FitMode)Resizes to the given width, adjusting height to preserve aspect ratio. The
FitModecontrols whether the resize is applied conditionally. Maps to-resize width,-resize width>, or-resize width<. -
Height(Int, FitMode)Resizes to the given height, adjusting width to preserve aspect ratio. The
FitModecontrols whether the resize is applied conditionally. Maps to-resize xheight,-resize xheight>, or-resize xheight<. -
Percent(Float)Resizes by a percentage of the original dimensions. Maps to
-resize float%. -
ResizeArea(Int)Resizes so the total pixel area is at most the given number of pixels. Useful for limiting memory usage regardless of image dimensions. Maps to
-resize int@.
Values
pub fn alpha_to_image(image: Image) -> Image
Extracts the alpha channel as a grayscale image.
Uses ImageMagick -alpha extract option.
pub fn auto_level(image: Image) -> Image
Automatically adjusts the image’s color levels.
Uses ImageMagick -auto-level option.
pub fn auto_orient(image: Image) -> Image
Automatically adjusts the image orientation based on EXIF data.
Uses ImageMagick -auto-orient option.
pub fn background(image: Image, color: colour.Colour) -> Image
Sets the background color for operations like extent that may create empty areas.
Uses ImageMagick -background option.
pub fn blur(image: Image, radius: Float) -> Image
Applies a Gaussian blur to the image.
Uses ImageMagick -blur radius option.
pub fn brightness_contrast(
image: Image,
brightness: Int,
contrast: Int,
) -> Image
Adjusts the brightness and contrast of the image. Both values are percentages where 0 means no change. Positive brightness brightens, negative darkens. Positive contrast increases contrast, negative decreases.
Uses ImageMagick -brightness-contrast option.
pub fn colors(image: Image, num_colors: Int) -> Image
Reduces the number of colors in the image to at most the specified number.
This uses quantization to select the best colors to represent the image.
Combine with dither/1 for smoother gradients when reducing to few colors.
image.from_file("photo.jpg")
|> image.dither()
|> image.colors(8)
|> image.to_file("output.png")
Uses ImageMagick -colors option.
pub fn colorspace(image: Image, kind: Colorspace) -> Image
Sets the colorspace of the image.
When converting to grayscale, prefer Gray over monochrome/1. Gray
preserves the full 256-level tonal range, producing smooth gradients and
intermediate gray values. monochrome/1 reduces the image to pure black
and white only (1-bit), using dithering to approximate tones.
Uses ImageMagick -colorspace option.
pub fn contrast_stretch(
image: Image,
black_percent: Float,
white_percent: Float,
) -> Image
Enhances the contrast of the image by stretching the range of intensity values.
The black_percent and white_percent parameters specify the percentage of
pixels to stretch at the dark and light ends of the histogram respectively.
Uses ImageMagick -contrast-stretch option.
pub fn crop(
image: Image,
x: Int,
y: Int,
width: Int,
height: Int,
) -> Image
Crops the image to the specified rectangle. The x and y coordinates specify the top-left corner of the crop area. Width and height specify the dimensions of the crop.
Uses ImageMagick -crop widthxheight+x+y option.
pub fn dither(image: Image) -> Image
Enables error-diffusion dithering for subsequent color reduction operations.
Error-diffusion dithering (Floyd-Steinberg) produces smoother gradients than ordered dithering when reducing colors. It propagates quantization errors to neighboring pixels rather than using a fixed pattern.
Commonly used with colors/2 to reduce the palette while preserving
smooth transitions:
image.from_file("photo.jpg")
|> image.dither()
|> image.colors(8)
|> image.to_file("output.png")
Uses ImageMagick -dither FloydSteinberg option.
pub fn extent(image: Image, width: Int, height: Int) -> Image
Crops or pads the image to the exact specified dimensions.
Uses ImageMagick -extent widthxheight option.
pub fn filter(image: Image, filter: Filter) -> Image
Sets the resampling filter for all subsequent resize operations.
This controls the algorithm used when resizing images. Different filters are better suited for different types of images:
- Lanczos (default) - High quality, sharp results. Best for photographs.
- Bicubic - Good balance of quality and speed.
- Nearest - Fast, pixelated results. Best for pixel art and icons.
- Mitchell - Good for enlarging, produces smoother results than Lanczos.
- Triangle - Simple linear interpolation. Faster but lower quality.
- Catrom - Sharp edges, good for text and line art.
The filter setting applies to all subsequent resize, resize_contain,
resize_fill, resize_cover, and thumbnail operations in the pipeline.
Example
from_file("pixel_art.png")
|> filter(Nearest) // Preserve sharp edges
|> resize_contain(100, 100)
|> to_file("resized.png")
pub fn flip(image: Image) -> Image
Flips the image vertically (top becomes bottom).
Uses ImageMagick -flip option.
pub fn flop(image: Image) -> Image
Flops the image horizontally (left becomes right).
Uses ImageMagick -flop option.
pub fn from_bits(bits: BitArray) -> Image
Creates an image from a BitArray containing image data. During execution this
file will be written to a temporary location and read from there by ImageMagick.
The temporary file is written everytime the pipeline is triggered and is automatically
cleaned up after execution. This is just a convenience method, prefer to use from_file
when possible.
ImageMagick will automatically detect the image format from the binary data (PNG, JPEG, BMP, etc.).
Example
let bits = read_image_from_database()
from_bits(bits)
|> resize_contain(100, 100)
|> to_file("resized.png")
pub fn gamma(image: Image, value: Float) -> Image
Applies gamma correction to the image. Values greater than 1.0 brighten the image (reduce gamma). Values less than 1.0 darken the image (increase gamma).
Uses ImageMagick -gamma option.
pub fn gravity(image: Image, gravity: Gravity) -> Image
Sets the gravity (position) for crop and extent operations.
Uses ImageMagick -gravity option.
pub fn identify(path: String) -> Result(ImageInfo, Error)
Identifies image properties (format, dimensions, colorspace, etc.).
Uses ImageMagick identify command.
pub fn monochrome(image: Image) -> Image
Converts the image to monochrome (pure black and white, 1-bit).
Unlike colorspace(image, Gray), this produces only pure black and pure
white pixels — no intermediate grays. ImageMagick applies dithering to
approximate tones using patterns of black and white dots.
Use this when you need a hard black-and-white result (e.g. PBM output,
printed bitmaps). Use colorspace(image, Gray) instead when you want to
preserve the full 256-level grayscale tonal range.
Uses ImageMagick -monochrome option.
pub fn negate(image: Image) -> Image
Negates the colors in the image (color inversion).
Uses ImageMagick -negate option.
pub fn normalize(image: Image) -> Image
Normalizes the image (enhances contrast by stretching the intensity range).
Uses ImageMagick -normalize option.
pub fn ordered_dither(image: Image, kind: DitherPattern) -> Image
Applies an ordered dithering pattern to the image.
Uses ImageMagick -ordered-dither option.
pub fn policy() -> Result(String, Error)
Lists the current ImageMagick security policy configuration.
This is useful for debugging security-related issues, such as when an image format is blocked by the security policy. The output shows which coders (image formats) and resources are allowed or denied.
Example
case image.policy() {
Ok(policy_info) -> io.println(policy_info)
Error(e) -> io.println("Failed to get policy: " <> string.inspect(e))
}
Uses ImageMagick -list policy command.
pub fn posterize(image: Image, levels: Int) -> Image
Reduces the image to a fixed number of color levels.
The levels argument specifies how many levels per channel to use. For
example, posterize(image, 4) produces at most 4^3 = 64 colors.
Use dither/1 before this function to enable error-diffusion dithering
for smoother transitions between color levels.
Example
// Retro 4-color look with dithering
image.from_file("photo.jpg")
|> image.dither()
|> image.posterize(2)
|> image.to_file("output.png")
Uses ImageMagick -posterize option.
pub fn quality(image: Image, percent: Int) -> Image
Sets the JPEG/WebP compression quality (1-100). Higher values produce better quality but larger file sizes. Lower values produce smaller files but with more compression artifacts.
Uses ImageMagick -quality option.
pub fn raw(image: Image, key: String, value: String) -> Image
This is an escape hatch to add options that are unsupported by this library
Example
image.from_file("input.png")
|> image.raw("-brightness-contrast", "0x30") // Increase contrast by 30%
|> image.to_file("output.jpg")
For simple flags like -flop just leave the second argument as an empty string.
pub fn resize(image: Image, kind: Resize) -> Image
Resizes the image using the specified resize mode.
Uses ImageMagick -resize option.
pub fn resize_contain(
image: Image,
width: Int,
height: Int,
) -> Image
Resizes the image to fit within the specified dimensions while preserving aspect ratio. The image will be equal to or smaller than the given width and height.
Uses ImageMagick -resize widthxheight option.
pub fn resize_cover(
image: Image,
width: Int,
height: Int,
gravity_val: Gravity,
) -> Image
Resizes the image to fill the specified dimensions, cropping overflow. The image will be resized to cover the entire area, and the cropping position is determined by the gravity parameter.
Uses ImageMagick -resize widthxheight^ and -extent options.
pub fn resize_fill(
image: Image,
width: Int,
height: Int,
) -> Image
Resizes the image to exactly the specified dimensions, ignoring aspect ratio. The image may be distorted.
Uses ImageMagick -resize widthxheight! option.
pub fn rotate(image: Image, degrees: Float) -> Image
Rotates the image by the specified angle in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise. The image canvas is automatically expanded to fit the rotated image.
Uses ImageMagick -rotate option.
pub fn sepia(image: Image, threshold: Float) -> Image
Applies a sepia tone effect to the image. The threshold is a percentage (0-100) that controls the intensity of the effect. Higher values produce a stronger sepia effect.
Uses ImageMagick -sepia-tone option.
pub fn sharpen(image: Image, radius: Float) -> Image
Sharpens the image using an unsharp mask.
Uses ImageMagick -sharpen radius option.
pub fn strip(image: Image) -> Image
Strips all metadata (EXIF, ICC profiles, comments) from the image.
Uses ImageMagick -strip option.
pub fn thumbnail(image: Image, width: Int, height: Int) -> Image
Creates a thumbnail of the image.
This is more efficient than using resize as it automatically strips
metadata (EXIF, ICC profiles, comments) before resizing, resulting in
smaller memory usage and faster processing - especially useful for
creating preview images from large source files.
The image will be resized to fit within the specified dimensions while preserving its aspect ratio. The resulting thumbnail dimensions will be equal to or smaller than the specified width and height.
Example
from_file("large_photo.jpg")
|> thumbnail(150, 150)
|> to_file("preview.jpg")
pub fn to_bits(
image: Image,
format: Format,
) -> Result(BitArray, Error)
Outputs the image as a BitArray in the specified format.
Uses ImageMagick output to stdout.
pub fn to_command(image: Image, output_path: String) -> String
Returns the ImageMagick command that would be executed for this image pipeline.
This is useful for debugging or logging purposes. The returned string includes the “magick” command prefix and can be copy-pasted directly into a terminal.
Example
let command =
from_file("input.png")
|> resize_contain(100, 100)
|> to_command("output.png")
// command == "magick input.png -resize 100x100 output.png"