HDR Intensity Slider
Relevant source files
The following files were used as context for generating this wiki page:The HDR Intensity Slider is a core feature of the HDRify application, allowing users to adjust the brightness multiplication factor applied to an uploaded image in real-time. This provides an instant preview of the HDR effect, enabling users to fine-tune the output before downloading. The slider's range is configured from 0.5x to 3.0x, offering a wide spectrum of intensity adjustments.
Sources: README.md:10, static/index.html:56
Frontend Implementation
The slider's user interface and client-side logic are handled entirely with vanilla HTML, CSS, and JavaScript.
Sources: README.md:46
HTML Structure
The slider is defined in index.html as an <input type="range"> element. It is part of a larger <section class="controls"> that becomes visible only after an image has been uploaded. A <span> element with the ID hdrValue is used to display the current numerical value of the slider.
<section class="controls" id="controls" style="display: none;" role="group" aria-label="HDR controls">
<label for="hdrSlider">
HDR: <span id="hdrValue" aria-live="polite">1.5</span>
<input type="range" id="hdrSlider" min="0.5" max="3.0" step="0.1" value="1.5" aria-label="HDR intensity level">
</label>
...
</section>
Sources: static/index.html:52-58
The slider's configuration is defined by its HTML attributes:
| Attribute | Value | Description |
|---|---|---|
id | hdrSlider | Unique identifier for the slider element. |
min | 0.5 | The minimum allowed intensity value. |
max | 3.0 | The maximum allowed intensity value. |
step | 0.1 | The increment value for each step of the slider. |
value | 1.5 | The default initial intensity value. |
Sources: static/index.html:56
CSS Styling
The visual appearance of the slider, its track, and its thumb are defined in static/style.css. The styles provide a custom look that matches the application's theme, with specific rules for the WebKit and Mozilla rendering engines. Hover effects are included to provide visual feedback to the user.
#hdrSlider {
width: 200px;
height: 4px;
background: #e5e7eb;
outline: none;
-webkit-appearance: none;
cursor: pointer;
transition: all 0.2s ease;
}
#hdrSlider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: #6b7280;
cursor: pointer;
transition: all 0.2s ease;
}
Sources: static/style.css:143-164
JavaScript Logic
The client-side behavior is managed by the HDRify class in static/script.js.
Event Handling
An input event listener is attached to the slider. When the user drags the slider, this event fires continuously.
- The UI display (
#hdrValue) is updated immediately with the new value. - The download button's
downloadattribute is updated to reflect the new HDR value in the filename. - A debounce mechanism using
setTimeoutwith a 250ms delay is employed. This prevents the application from sending an API request for every single micro-movement of the slider. A new processing request is only sent after the user has stopped moving the slider for 250ms.
this.hdrSlider.addEventListener('input', (e) => {
const value = parseFloat(e.target.value);
this.updateHdrValue(value);
// ... update download filename ...
clearTimeout(this.processingTimeout);
this.processingTimeout = setTimeout(() => {
if (this.currentImageData) {
this.processImage(value);
}
}, 250);
});
Sources: static/script.js:90-108
The following diagram illustrates the frontend event handling flow.
Sources: static/script.js:90-108
Image Caching
To provide an "instant preview", the frontend maintains a client-side cache (this.imageCache) for processed images. The cache is a Map where the key is the HDR value (e.g., "1.8") and the value is the base64-encoded image data.
When processImage is called, it first checks if the result for the current hdrValue exists in the cache. If it does, the cached image is rendered immediately without an API call. If not, an API request is made, and the new result is stored in the cache for future use. This cache is cleared whenever a new image is uploaded.
Sources: static/script.js:8, static/script.js:180-197, static/script.js:220-222
Backend Processing
The backend is a Rust application using the warp web server framework. It exposes a single endpoint to handle image processing.
Sources: src/main.rs, Cargo.toml
API Endpoint
The slider's value is sent to the backend as part of a POST request to the /upload endpoint.
- Endpoint:
POST /upload - Content-Type:
application/x-www-form-urlencoded
The request body contains the base64 image data and the HDR value from the slider.
| Parameter | Type | Description |
|---|---|---|
image | String | The base64-encoded source image data. |
hdr_value | String | The intensity value from the slider (e.g., "1.5"). |
Sources: static/script.js:260-263, src/main.rs:18-22, src/main.rs:198-201
ImageMagick Integration
In the handle_upload function, the backend receives the form data, parses the hdr_value into an f32, and constructs an ImageMagick command. The hdr_value is passed directly to the -evaluate Multiply argument, which is the core of the HDR enhancement.
// in handle_upload function
let hdr_value: f32 = form
.get("hdr_value")
.and_then(|v| v.parse().ok())
.unwrap_or(1.5);
// ...
let output = Command::new("magick")
.arg(input_file.path())
// ... other args
.arg("-evaluate")
.arg("Multiply")
.arg(hdr_value.to_string()) // The slider value is used here
// ... other args
.arg(output_file.path())
.output();
Sources: src/main.rs:19-22, src/main.rs:96-108
End-to-End Data Flow
The following sequence diagram shows the complete interaction from the user moving the slider to the image being updated on the screen.
This diagram illustrates the debouncing, caching, and API communication that create the real-time preview experience.
Sources: static/script.js:90-108, static/script.js:180-252, src/main.rs:17-138