alakazam

Package VersionHex Docs

A fluent, type-safe image processing library for Gleam, powered by ImageMagick.

How It Works

alakazam is a thin, composable wrapper around the ImageMagick magick command-line tool. Rather than binding to a native C library, it builds a pipeline of operations in Gleam and compiles them into a single magick command that is executed when the image is written.

import alakazam/image

pub fn main() {
  image.from_file("photo.jpg")
  |> image.resize_contain(800, 600)
  |> image.sharpen(0.5)
  |> image.to_file("output.jpg")
  // Executes: magick photo.jpg -resize 800x600 -sharpen 0.5 output.jpg
}

You can inspect the generated command at any point using to_command/2, which returns the full command string without executing it — useful for debugging or logging.

Why a CLI wrapper?

No native bindings. There is no FFI layer, no platform-specific compilation, and no memory safety concerns at the binding boundary. The library is pure Gleam; only the magick binary is native.

Battle-tested engine. ImageMagick has over 30 years of development behind it. Format quirks, ICC profiles, EXIF handling, and hundreds of other edge cases are handled by a mature, widely-deployed tool rather than a new binding.

Transparent and debuggable. Because the library produces a plain shell command, you can inspect exactly what will run with to_command/2 and paste it directly into a terminal to reproduce or investigate any result.

Full feature access. The raw/3 escape hatch lets you pass any ImageMagick option the library does not explicitly wrap, so you are never blocked by a missing API.

Tradeoffs

Each pipeline execution spawns an OS process. This is well-suited for batch processing, image pipelines, and server-side generation, but is not appropriate for tight loops that process many small images per second. For those workloads, consider batching operations or pre-generating assets.

ImageMagick must also be installed on every host that runs your application. See the Prerequisites section for installation instructions.

Prerequisites

ImageMagick must be installed and the magick command must be available in your PATH.

# macOS
brew install imagemagick

# Ubuntu/Debian
apt-get install imagemagick

# Verify installation
magick -version

Installation

gleam add alakazam

Quick Start

// Basic resize and save
image.from_file("photo.jpg")
|> image.resize_contain(800, 600)
|> image.to_file("resized.jpg")
}

Usage Examples

Resizing Images

// Fit within dimensions (preserves aspect ratio)
image.from_file("large.png")
|> image.resize_contain(300, 200)
|> image.to_file("fitted.png")

// Fill exact dimensions (may stretch)
image.from_file("photo.jpg")
|> image.resize_fill(800, 600)
|> image.to_file("filled.jpg")

// Cover/crop to fill (CSS object-fit: cover behavior)
image.from_file("banner.jpg")
|> image.resize_cover(1920, 1080, image.Center)
|> image.to_file("cover.jpg")

// Reduce colors with dithering for retro/pixel art look
image.from_file("photo.jpg")
|> image.dither()
|> image.colors(8)
|> image.to_file("retro.png")

Creating Thumbnails

Thumbnails are optimized for creating preview images - they automatically strip metadata and use less memory:

image.from_file("high_res_photo.jpg")
|> image.thumbnail(150, 150)
|> image.to_file("thumb.jpg")

Controlling Resampling Quality

Choose the right filter for your image type:

// For pixel art - preserve sharp edges
image.from_file("pixel_art.png")
|> image.filter(image.Nearest)
|> image.resize_contain(200, 200)
|> image.to_file("scaled.png")

// For photos - high quality (default)
image.from_file("photo.jpg")
|> image.filter(image.Lanczos)
|> image.thumbnail(100, 100)
|> image.to_file("thumb.jpg")

Available filters:

Chaining Operations

Combine multiple transformations in a single pipeline:

image.from_file("input.jpg")
|> image.resize_contain(800, 600)
|> image.sharpen(0.5)
|> image.strip()  // Remove metadata for smaller files
|> image.to_file("optimized.jpg")

Getting Image Information

import alakazam/image

pub fn main() {
  case image.identify("photo.jpg") {
    Ok(info) -> {
      io.println("Format: " <> format_to_string(info.format))
      io.println("Dimensions: " <> int.to_string(info.width) <> "x" <> int.to_string(info.height))
      io.println("Colorspace: " <> colorspace_to_string(info.colorspace))
      io.println("Bit depth: " <> int.to_string(info.depth))
      io.println("File size: " <> int.to_string(info.file_size) <> " bytes")
      io.println("Has alpha: " <> bool.to_string(info.has_alpha))
    }
    Error(e) -> io.println("Failed to identify image")
  }
}

Format Conversion

// Convert PNG to JPEG
image.from_file("image.png")
|> image.to_file("image.jpg")

// Get image as bytes in specific format
image.from_file("photo.jpg")
|> image.to_bits(image.Png)

Working with Binary Data

// Load image from BitArray (e.g., from database or API)
let image_bits = read_image_from_database()
image.from_bits(image_bits)
|> image.resize_contain(100, 100)
|> image.to_file("resized.png")

// Round-trip: File -> BitArray -> File
image.from_file("photo.jpg")
|> image.to_bits(image.Png)
|> image.from_bits
|> image.to_file("converted.png")

Color Reduction

Reduce the color palette for stylistic effects or smaller file sizes. Both operations work well with dither() to smooth gradients.

colors(n) - Reduces to n total colors using intelligent quantization. ImageMagick analyzes the image and picks the best colors to represent it.

// 8-color image with dithering for smooth gradients
image.from_file("photo.jpg")
|> image.dither()
|> image.colors(8)
|> image.to_file("8color.png")

posterize(n) - Reduces to n levels per color channel (R, G, B). Creates total colors with uniform steps, producing visible color banding (posterization effect).

// 4 levels per channel = 4³ = 64 total colors (retro poster look)
image.from_file("photo.jpg")
|> image.dither()
|> image.posterize(4)
|> image.to_file("posterized.png")

// Extreme posterization: 2 levels per channel = only 8 colors total
image.from_file("photo.jpg")
|> image.dither()
|> image.posterize(2)
|> image.to_file("8color-poster.png")

When to use:

Available Operations

Loading & Saving

Resizing

Quality Control

Effects

Transformations

Cropping

Colors & Color Space

Metadata

Utilities

Supported Formats

Use Keep format to maintain the original format when converting.

Development

gleam run   # Run the project
gleam test  # Run the tests
gleam format --check src test  # Check formatting

Documentation

Further documentation can be found at https://hexdocs.pm/alakazam.

License

This project is licensed under the Apache License 2.0.