Image Class
Pure-Rust image manipulation for resizing, cropping, transforms, filters, and format conversion. No system dependencies required.
Tip. If your image lives on a model declared with uploader(...), you don't have to write a transform pipeline by hand — the auto-routed GET /<resource>/:id/<field> endpoint accepts query params (w, h, thumb, square, crop, fit=cover|contain, flipx, flipy, rot=90/180/270, blur, bright, contrast, hue, gray, invert, fmt, q) and runs them through the Image class for you.
See Image transforms via URL.
Supported Formats
All methods return a new Image instance, enabling fluent chaining.
Loading Images
Image.new(path)
Loads an image from a file path. The format is detected automatically.
Parameters
path : String - Path to the image fileReturns
Image instance
img = Image.new("photo.jpg")
println(img.width) # 1920
println(img.height) # 1080
Image.from_buffer(base64_string)
Loads an image from a base64-encoded string. Useful for processing images from HTTP requests, S3, or databases.
Parameters
base64_string : String - Base64-encoded image dataReturns
Image instance
img = Image.from_buffer(base64_data)
println(img.width)
Properties
img.width / img.height
Returns the image dimensions in pixels.
Returns
Int
img = Image.new("photo.jpg")
println("Size: " + str(img.width) + "x" + str(img.height))
Resizing
img.resize(width, height)
Resizes the image to the specified dimensions using high-quality Lanczos3 filtering.
Parameters
width : Int - Target width in pixelsheight : Int - Target height in pixelsReturns
New Image instance
resized = Image.new("photo.jpg").resize(800, 600)
resized.to_file("photo_resized.jpg")
img.thumbnail(max_size)
Creates a thumbnail that fits within a square of the given size, preserving the original aspect ratio.
Parameters
max_size : Int - Maximum width or height in pixelsReturns
New Image instance
thumb = Image.new("photo.jpg").thumbnail(200)
thumb.to_file("thumb.jpg")
img.crop(x, y, width, height)
Crops a rectangular region from the image. Coordinates must be non-negative.
Parameters
x : Int - Left offset (>= 0)y : Int - Top offset (>= 0)width : Int - Crop widthheight : Int - Crop heightReturns
New Image instance
cropped = Image.new("photo.jpg").crop(100, 50, 400, 300)
cropped.to_file("cropped.jpg")
Transforms
img.grayscale()
Convert to grayscale.
img.invert
Invert all colors.
img.flip_horizontal()
Flip horizontally (mirror).
img.flip_vertical()
Flip vertically.
img.rotate90()
Rotate 90° clockwise.
img.rotate180()
Rotate 180°.
img.rotate270()
Rotate 270° clockwise (90° counter-clockwise).
All transform methods return a new Image and can be chained:
img = Image.new("photo.jpg")
.grayscale()
.flip_horizontal()
.rotate90()
img.to_file("transformed.jpg")
Adjustments
img.blur(sigma)
Applies a Gaussian blur. Higher sigma = more blur.
Parameters
sigma : Float or Int - Blur intensityblurred = Image.new("photo.jpg").blur(3.5)
img.brightness(value)
Adjusts image brightness. Positive values brighten, negative values darken.
Parameters
value : Int - Brightness adjustmentimg.contrast(value)
Adjusts image contrast. Positive increases contrast, negative decreases.
Parameters
value : Float or Int - Contrast adjustmentimg.hue_rotate(degrees)
Rotates the hue of all pixels by the given number of degrees.
Parameters
degrees : Int - Hue rotation in degreesadjusted = Image.new("photo.jpg")
.brightness(20)
.contrast(1.5)
.hue_rotate(90)
adjusted.to_file("adjusted.jpg")
Output Settings
img.quality(n)
Sets the output quality for JPEG encoding. Default is 85.
Parameters
n : Int - Quality from 1 (smallest) to 100 (best)img.format(fmt)
Sets the output format explicitly.
Parameters
fmt : String - One of: "jpeg", "png", "gif", "bmp", "ico", "tiff", "webp"# Convert PNG to JPEG at 70% quality
img = Image.new("photo.png")
.format("jpeg")
.quality(70)
img.to_file("photo.jpg")
Saving & Exporting
img.to_file(path)
Saves the image to a file. Format is determined by: .format() setting, then file extension, then PNG fallback.
Parameters
path : String - Output file pathReturns
Boolean - true on success
Image.new("photo.jpg").thumbnail(200).to_file("thumb.jpg")
img.to_buffer()
Encodes the image to a base64 string. Useful for storing in databases, HTTP responses, or passing to S3.
Returns
String - Base64-encoded image data
img = Image.new("photo.jpg").thumbnail(100)
base64_data = img.to_buffer()
# Store in S3
S3.put_object("my-bucket", "thumb.jpg", base64_data, {
"content_type": "image/jpeg"
})
Parallel Processing
Image transforms are CPU-bound. To process several images concurrently, build a plan with Image.plan(path), chain the same transform methods you would on a regular image, and pass an array of plans to Image.process_all(...). Each plan runs on its own thread; the call returns when every plan finishes.
A plan is lazy — methods just record operations. Nothing decodes, transforms, or writes until you call plan.run() (one plan, current thread) or Image.process_all([...]) (many plans, in parallel).
Image.plan(path)
Creates a new lazy plan that will read its source from path when executed.
Parameters
path : String - Path to the image file (read at execution time)Returns
ImagePlan instance
Plan instance methods
A plan supports the same transform methods as Image:
resize(w, h), thumbnail(size), crop(x, y, w, h), grayscale(), flip_horizontal(), flip_vertical(), rotate90(), rotate180(), rotate270(), blur(sigma), brightness(n), contrast(n), invert(), hue_rotate(degrees), format(fmt), quality(n).
Each call returns a new ImagePlan instance with the operation appended.
Plan-only methods
save_to(path)— terminal; the plan will save topathwhen executed.run()— executes the plan synchronously on the current thread. Returnstrueifsave_towas set, otherwise anImageinstance.src()— returns the source path.ops_count()— returns the number of recorded operations.
Image.process_all(plans)
Runs an array of plans in parallel (one OS thread per plan) and returns an array of results in the same order.
Parameters
plans : Array<ImagePlan> - Plans to execute concurrentlyReturns
Array, where each entry is:
trueif the plan hadsave_to(path)and the file was written- An
Imageinstance if the plan had nosave_to - A hash
{"error": "..."}if that plan failed (other plans still complete)
# Generate three thumbnail variants in parallel
results = Image.process_all([
Image.plan("uploads/raw.jpg").thumbnail(800).save_to("public/large.jpg"),
Image.plan("uploads/raw.jpg").thumbnail(400).save_to("public/medium.jpg"),
Image.plan("uploads/raw.jpg").thumbnail(100).save_to("public/small.jpg"),
])
# results == [true, true, true] on success
Process many files
let plans = files.map(fn(f) {
Image.plan(f).resize(1200, 900).quality(80).save_to("processed/" + basename(f))
})
let results = Image.process_all(plans)
# Inspect failures
for r in results
println("error: " + r.error) if r.error != null
end
Collect transformed images without saving
let images = Image.process_all([
Image.plan("a.jpg").grayscale(),
Image.plan("b.jpg").rotate90().resize(200, 200),
])
println(images[0].width)
let buf = images[1].to_buffer()
Image.new(...) is fully synchronous and runs on one thread. Use Image.plan(...) + Image.process_all([...]) only when you have multiple images and want them to run concurrently.
Complete Examples
Thumbnail generation in a controller
fn upload
file = req.files["avatar"]
# `file["data"]` is a base64-encoded string. Image.from_buffer expects
# base64, so pass it through directly. Use `file["size"]` for the raw
# byte count instead of `file["data"].length`.
img = Image.from_buffer(file["data"])
# Create multiple sizes
large = img.resize(800, 800)
medium = img.thumbnail(400)
small = img.thumbnail(100)
large.to_file("public/uploads/avatar_large.jpg")
medium.to_file("public/uploads/avatar_medium.jpg")
small.to_file("public/uploads/avatar_small.jpg")
return { "status": 200, "body": "Upload complete" }
end
Image processing pipeline
img = Image.new("raw_photo.jpg")
.resize(1200, 900)
.brightness(10)
.contrast(1.2)
.quality(85)
img.to_file("processed.jpg")
# Also create a grayscale thumbnail
img.grayscale().thumbnail(200).to_file("thumb_gray.jpg")
Format conversion with S3
# Convert all PNGs to WebP
files = S3.list_objects("images", "photos/")
for file in files
if file.ends_with(".png")
data = S3.get_object("images", file)
img = Image.from_buffer(data)
.format("webp")
.quality(80)
new_key = file.replace(".png", ".webp")
S3.put_object("images", new_key, img.to_buffer(), {
"content_type": "image/webp"
})
end
end