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

  • Srgb

    Standard RGB with gamma correction (the most common colorspace for web and screen images).

  • Gray

    Grayscale. See colorspace/2 for the difference between Gray and monochrome/1.

  • Rgb

    Linear RGB, without gamma correction.

  • Cmyk

    Cyan/Magenta/Yellow/Key (Black). Used in print workflows.

  • YCbCr

    Luma + 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 (o2x2o8x8) — smooth Bayer matrix patterns; larger matrices produce finer gradients at the cost of more visible structure
  • Halftone Angled (h4x4ah8x8a) — angled halftone dots, similar to traditional print halftoning
  • Halftone Orthogonal (h4x4oh16x16o) — axis-aligned halftone dots
  • Circles Black/White (c5x5bc7x7w) — 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

  • Threshold

    Flat threshold: pixels above 50% become white, below become black. No spatial spreading.

  • Checks

    Checkerboard pattern at the 50% threshold boundary.

  • Ordered2x2

    2×2 Bayer ordered matrix.

  • Ordered3x3

    3×3 ordered matrix.

  • Ordered4x4

    4×4 Bayer ordered matrix. Good general-purpose choice.

  • Ordered8x8

    8×8 Bayer ordered matrix. Finer gradients, more visible grid structure.

  • Halftone4x4Angled

    4×4 angled halftone dots.

  • Halftone6x6Angled

    6×6 angled halftone dots.

  • Halftone8x8Angled

    8×8 angled halftone dots. Closest to traditional print halftoning.

  • Halftone4x4Orthogonal

    4×4 orthogonal (axis-aligned) halftone dots.

  • Halftone6x6Orthogonal

    6×6 orthogonal halftone dots.

  • Halftone8x8Orthogonal

    8×8 orthogonal halftone dots.

  • Halftone16x16Orthogonal

    16×16 orthogonal halftone dots. Finest tonal gradients in this family.

  • Circles5x5Black

    5×5 circular dots on a black background.

  • Circles6x6Black

    6×6 circular dots on a black background.

  • Circles7x7Black

    7×7 circular dots on a black background.

  • Circles5x5White

    5×5 circular dots on a white background.

  • Circles6x6White

    6×6 circular dots on a white background.

  • Circles7x7White

    7×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 Format variant. The raw string is included for debugging.

  • CannotParseWidth

    The width value in ImageMagick’s identify output could not be parsed as an integer.

  • CannotParseHeight

    The height value in ImageMagick’s identify output could not be parsed as an integer.

  • CannotParseDepth

    The bit depth value in ImageMagick’s identify output could not be parsed as an integer.

  • CannotParseFileSize

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

  • CannotWriteTempFile

    A temporary file was created successfully but writing the image data to it failed. Used by from_bits/1.

  • CannotCreateTempFile

    The 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

  • Lanczos

    High quality, sharp results with minimal artifacts. Best for photographs and general-purpose resizing.

  • Bicubic

    Good balance of quality and processing speed. A solid general-purpose choice when speed matters.

  • Nearest

    Fast, pixelated results without interpolation. Best for pixel art, icons, and images with hard edges.

  • Mitchell

    Smooth results, particularly good for enlarging images. Produces softer results than Lanczos when upscaling.

  • Triangle

    Simple linear interpolation, fast but lower quality. Good for simple downscaling when performance is critical.

  • Catrom

    Sharp 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

  • Any

    Always resize, regardless of whether the image is larger or smaller than the target. This is the default behaviour.

  • OnlyIfLarger

    Only resize if the image is larger than the target dimensions. Smaller images are left untouched. Maps to the > geometry flag.

  • OnlyIfSmaller

    Only 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

  • Png

    Portable Network Graphics. Lossless, supports transparency.

  • Bmp

    Windows Bitmap. Uncompressed, widely compatible.

  • Jpeg

    JPEG. Lossy compression, no transparency. Best for photographs.

  • Webp

    WebP. Modern format with excellent compression and transparency support.

  • Pbm

    Portable Bitmap. 1-bit black and white, plain-text or binary encoding.

  • Pgm

    Portable Graymap. 8-bit grayscale, plain-text or binary encoding.

  • Keep

    Preserve 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

  • NorthWest

    Top-left corner.

  • North

    Top edge, horizontally centered.

  • NorthEast

    Top-right corner.

  • West

    Left edge, vertically centered.

  • Center

    Center of the image (default).

  • East

    Right edge, vertically centered.

  • SouthWest

    Bottom-left corner.

  • South

    Bottom edge, horizontally centered.

  • SouthEast

    Bottom-right corner.

pub opaque type Image

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 extent to 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 FitMode controls 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 FitMode controls 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 from_file(path: String) -> Image

Creates an image from a file path.

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"
pub fn to_file(
  image: Image,
  path: String,
) -> Result(String, Error)

Writes the image to a file.

Uses ImageMagick magick command.

Search Document