Backend Overview
Relevant source files
The following files were used as context for generating this wiki page:The hdrify backend is a lightweight, single-purpose web service written in Rust. Its primary function is to receive an image, apply an HDR-like effect using the ImageMagick command-line tool, and return the processed image to the client. The backend is built using the warp web framework and runs on the tokio asynchronous runtime.
The architecture is straightforward: a web server listens for HTTP requests, serves the static frontend files (HTML, CSS, JS), and exposes a single API endpoint (/upload) for image processing. It does not use a database or any external services beyond the locally installed ImageMagick.
Sources: src/main.rs, README.md:29-32
Architecture and Dependencies
The backend is a monolithic Rust application. It leverages several key crates from the Rust ecosystem to handle web requests, asynchronous operations, and data serialization.
The following diagram illustrates the high-level components and their interaction.
This diagram shows the flow of an image processing request from the client through the backend components.
Sources: src/main.rs:18-132, static/script.js:255-281
Key Dependencies
The backend relies on the following core dependencies defined in Cargo.toml.
| Crate | Version | Description |
|---|---|---|
warp | 0.3 | A composable, asynchronous web server framework. |
tokio | 1.0 | An asynchronous runtime for writing network applications. |
serde | 1.0 | A framework for serializing and deserializing Rust data structures. |
base64 | 0.21 | Used for encoding and decoding image data sent over JSON. |
tempfile | 3.0 | Used to create temporary files for input and output of ImageMagick. |
Sources: Cargo.toml:5-14
Server Initialization and Routing
The server is started in the main function, which is annotated with #[tokio::main] to run within the Tokio async runtime. It sets up routes and starts listening on 0.0.0.0:3000.
Sources: src/main.rs:172-187
Routes
The server defines three main routing rules:
| Path | Method | Handler | Description |
|---|---|---|---|
/ | GET | warp::fs::file | Serves the main index.html file. |
/upload | POST | handle_upload | The core API endpoint for processing images. |
/* | GET | warp::fs::dir | Serves static assets (CSS, JS, images) from the static/ directory. |
All routes are configured with a CORS layer to allow requests from any origin.
Sources: src/main.rs:174-184
API Endpoint: POST /upload
This is the only API endpoint and the core of the backend's functionality. It accepts form-urlencoded data, processes an image, and returns a JSON response.
Sources: src/main.rs:18-132, static/script.js:261-267
Request Payload
The endpoint expects a POST request with a Content-Type of application/x-www-form-urlencoded. The body should contain the following fields:
| Parameter | Type | Description |
|---|---|---|
image | String | The base64-encoded image data (without the data:image/...;base64, prefix). |
hdr_value | f32 | The HDR intensity multiplier. Defaults to 1.5 if not provided or invalid. |
Sources: src/main.rs:19-24, static/script.js:257-259
Response Payload
The server responds with a JSON object defined by the ProcessResponse struct.
// src/main.rs:8-13
#[derive(Debug, Serialize)]
struct ProcessResponse {
success: bool,
message: String,
image_data: Option<String>, // base64 encoded HDR image
}
- On success:
successistrue,messagecontains a success string, andimage_dataholds the base64-encoded processed PNG image. - On failure:
successisfalse,messagecontains a detailed error, andimage_dataisnull.
Sources: src/main.rs:8-13
Processing Flow
The handle_upload function orchestrates the entire image processing logic. The sequence diagram below shows the interaction between the client, the warp server, and the ImageMagick process.
This diagram details the sequence of operations for a /upload request.
Sources: src/main.rs:18-132, static/script.js:255-281
Image Processing
The core image manipulation is delegated to the magick command-line tool. The backend constructs and executes a specific command pipeline to achieve the HDR effect.
Sources: src/main.rs:83-100, README.md:23-28
ImageMagick Command
The following command is executed, with hdr_value being the user-provided float.
magick <input_file> \
-define quantum:format=floating-point \
-colorspace RGB \
-auto-gamma \
-evaluate Multiply <hdr_value> \
-evaluate Pow 0.9 \
-colorspace sRGB \
-depth 16 \
-profile 2020_profile.icc \
<output_file>
| Argument | Purpose |
|---|---|
-define quantum:format=floating-point | Enables high-precision floating-point processing. |
-colorspace RGB | Converts the image to a linear RGB colorspace. |
-auto-gamma | Applies automatic gamma correction. |
-evaluate Multiply <hdr_value> | Multiplies pixel brightness by the user-defined HDR value. |
-evaluate Pow 0.9 | Applies a power curve adjustment. |
-colorspace sRGB | Converts the image back to the standard sRGB colorspace. |
-depth 16 | Sets the bit depth to 16 bits per channel. |
-profile 2020_profile.icc | Applies the Rec. 2020 color profile to enable HDR display. |
Sources: src/main.rs:84-99, README.md:23-28
Input Validation
Before processing, the backend performs several validation checks to ensure the input is safe and supported.
File Size
A hard limit is set for the uploaded file size to prevent excessive memory usage. The maximum allowed size is 10 MB.
// src/main.rs:55-56
const MAX_SIZE: usize = 10 * 1024 * 1024; // 10MB
if image_bytes.len() > MAX_SIZE { ... }
Sources: src/main.rs:55-65, static/index.html:27, static/script.js:159-167
Image Format
The backend does not rely on the Content-Type header but instead validates the file format by inspecting its "magic bytes". This provides a more reliable way to confirm the image type. Supported formats are JPEG, PNG, and WebP.
// src/main.rs:134-137
fn is_supported_image_format(bytes: &[u8]) -> bool {
if bytes.len() < 12 {
return false;
}
// ... magic byte checks ...
}
The function checks for the following byte patterns at the beginning of the file:
- JPEG:
FF D8 FF - PNG:
89 50 4E 47 0D 0A 1A 0A - WebP:
RIFFat bytes 0-3 andWEBPat bytes 8-11.