Easy Image Editor: Tutorial and Documentation
100daysofMiva Day 5.
Today, I went through the implementation and functionality of a simple yet powerful image editor built with HTML, CSS, and JavaScript. The editor allows users to apply basic filters, rotate, and flip an image. It also supports loading an image from the user's device and saving the edited image.
1. HTML Structure
The HTML structure is divided into several key sections: the filter options, rotation and flip options, an image preview area, and control buttons.
<div class="container disable">
<h2>Easy Image Editor</h2>
<div class="wrapper">
<div class="editor-panel">
<!-- Filters Section -->
<div class="filter">
<label class="title">Filters</label>
<div class="options">
<button id="brightness" class="active">Brightness</button>
<button id="saturation">Saturation</button>
<button id="inversion">Inversion</button>
<button id="grayscale">Grayscale</button>
</div>
<!-- Slider for Filter Adjustments -->
<div class="slider">
<div class="filter-info">
<p class="name">Brighteness</p>
<p class="value">100%</p>
</div>
<input type="range" value="100" min="0" max="200">
</div>
</div>
<!-- Rotate & Flip Section -->
<div class="rotate">
<label class="title">Rotate & Flip</label>
<div class="options">
<button id="left"><i class="fa-solid fa-rotate-left"></i></button>
<button id="right"><i class="fa-solid fa-rotate-right"></i></button>
<button id="horizontal"><i class='bx bx-reflect-vertical'></i></button>
<button id="vertical"><i class='bx bx-reflect-horizontal'></i></button>
</div>
</div>
</div>
<!-- Image Preview Section -->
<div class="preview-img">
<img src="image-placeholder.svg" alt="preview-img">
</div>
</div>
<!-- Controls Section -->
<div class="controls">
<button class="reset-filter">Reset Filters</button>
<div class="row">
<input type="file" class="file-input" accept="image/*" hidden>
<button class="choose-img">Choose Image</button>
<button class="save-img">Save Image</button>
</div>
</div>
</div>
- Container & Wrapper: Wraps the entire image editor.
- Filter Section: Includes buttons for selecting filters like brightness, saturation, inversion, and grayscale.
- Rotate & Flip Section: Provides options to rotate and flip the image.
- Preview Image Section: Displays the image that the user is editing.
- Controls Section: Contains buttons to reset filters, choose an image, and save the edited image.
2. JavaScript Functionality
The JavaScript code handles the logic behind loading an image, applying filters, rotating and flipping the image, and saving the edited image.
Variables and DOM Elements
const fileInput = document.querySelector(".file-input"),
filterOptions = document.querySelectorAll(".filter button"),
filterName = document.querySelector(".filter-info .name"),
filterValue = document.querySelector(".filter-info .value"),
filterSlider = document.querySelector(".slider input"),
rotateOptions = document.querySelectorAll(".rotate button"),
previewImg = document.querySelector(".preview-img img"),
resetFilterBtn = document.querySelector(".reset-filter"),
chooseImgBtn = document.querySelector(".choose-img"),
saveImgBtn = document.querySelector(".save-img");
let brightness = "100", saturation = "100", inversion = "0", grayscale = "0";
let rotate = 0, flipHorizontal = 1, flipVertical = 1;
- Variables: Stores default values for filters and rotation/flip states.
- DOM Elements: Selects various elements in the DOM for interaction (e.g., buttons, sliders, image preview).
Loading the Image
const loadImage = () => {
let file = fileInput.files[0];
if(!file) return;
previewImg.src = URL.createObjectURL(file);
previewImg.addEventListener("load", () => {
resetFilterBtn.click(); // Reset filters when a new image is loaded
document.querySelector(".container").classList.remove("disable");
});
}
- loadImage: Loads the selected image from the user's device and displays it in the preview area.
Applying Filters
const applyFilter = () => {
previewImg.style.transform = `rotate(${rotate}deg) scale(${flipHorizontal}, ${flipVertical})`;
previewImg.style.filter = `brightness(${brightness}%) saturate(${saturation}%) invert(${inversion}%) grayscale(${grayscale}%)`;
}
- applyFilter: Applies the selected filters and transformations (rotate, flip) to the image preview.
Handling Filter Selection and Updates
filterOptions.forEach(option => {
option.addEventListener("click", () => {
document.querySelector(".active").classList.remove("active");
option.classList.add("active");
filterName.innerText = option.innerText;
if(option.id === "brightness") {
filterSlider.max = "200";
filterSlider.value = brightness;
filterValue.innerText = `${brightness}%`;
} else if(option.id === "saturation") {
filterSlider.max = "200";
filterSlider.value = saturation;
filterValue.innerText = `${saturation}%`
} else if(option.id === "inversion") {
filterSlider.max = "100";
filterSlider.value = inversion;
filterValue.innerText = `${inversion}%`;
} else {
filterSlider.max = "100";
filterSlider.value = grayscale;
filterValue.innerText = `${grayscale}%`;
}
});
});
const updateFilter = () => {
filterValue.innerText = `${filterSlider.value}%`;
const selectedFilter = document.querySelector(".filter .active");
if(selectedFilter.id === "brightness") {
brightness = filterSlider.value;
} else if(selectedFilter.id === "saturation") {
saturation = filterSlider.value;
} else if(selectedFilter.id === "inversion") {
inversion = filterSlider.value;
} else {
grayscale = filterSlider.value;
}
applyFilter();
}
- Event Listeners: These are attached to the filter buttons and slider. They update the filter values and reapply them to the image preview.
Rotating and Flipping the Image
rotateOptions.forEach(option => {
option.addEventListener("click", () => {
if(option.id === "left") {
rotate -= 90;
} else if(option.id === "right") {
rotate += 90;
} else if(option.id === "horizontal") {
flipHorizontal = flipHorizontal === 1 ? -1 : 1;
} else {
flipVertical = flipVertical === 1 ? -1 : 1;
}
applyFilter();
});
});
- rotateOptions: These buttons rotate the image by 90 degrees or flip it horizontally/vertically.
Resetting Filters
const resetFilter = () => {
brightness = "100"; saturation = "100"; inversion = "0"; grayscale = "0";
rotate = 0; flipHorizontal = 1; flipVertical = 1;
filterOptions[0].click();
applyFilter();
}
- resetFilter: Resets all filters and transformations to their default values.
Saving the Edited Image
const saveImage = () => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
canvas.width = previewImg.naturalWidth;
canvas.height = previewImg.naturalHeight;
ctx.filter = `brightness(${brightness}%) saturate(${saturation}%) invert(${inversion}%) grayscale(${grayscale}%)`;
ctx.translate(canvas.width / 2, canvas.height / 2);
if(rotate !== 0) {
ctx.rotate(rotate * Math.PI / 180);
}
ctx.scale(flipHorizontal, flipVertical);
ctx.drawImage(previewImg, -canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height);
const link = document.createElement("a");
link.download = "image.jpg";
link.href = canvas.toDataURL();
link.click();
}
- saveImage: Creates a canvas element, applies the transformations and filters, and then saves the edited image as a file.
Event Listeners
filterSlider.addEventListener("input", updateFilter);
resetFilterBtn.addEventListener("click", resetFilter);
saveImgBtn.addEventListener("click", saveImage);
fileInput.addEventListener("change", loadImage);
chooseImgBtn.addEventListener("click", () => fileInput.click());
- Event Listeners: Handle user interactions, such as choosing an image, adjusting filters, and saving the edited image.
3. Usage
- Choose an Image: Click the "Choose Image" button to load an image from your device.
- Apply Filters: Select a filter and adjust its value using
the slider.
- Rotate & Flip: Use the rotate and flip buttons to modify the image orientation.
- Reset Filters: Click "Reset Filters" to revert all settings to default.
- Save Image: Once you're satisfied with the edits, click "Save Image" to download the modified image.
4. Conclusion
This simple image editor provides essential tools to modify and enhance images. The structure is designed to be easy to understand and extendable, allowing for the addition of more features like additional filters or advanced editing tools. Thanks for reading. Unto the next…
Check it out here
https://app.marvelly.com.ng/100daysofMiva/day-5/
Source code
https://github.com/Marvellye/100daysofMiva/tree/main/Projects/Day_5-Image-Editor
Top comments (3)
Wow
Awesome!
Amazing work!
Keep going and complete your #100daysofMiva Journey!