DEV Community

Cover image for Easy Image Editor: Tutorial and Documentation
Ezekiel Marvellous
Ezekiel Marvellous

Posted on

Easy Image Editor: Tutorial and Documentation

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>

Enter fullscreen mode Exit fullscreen mode
  • 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;

Enter fullscreen mode Exit fullscreen mode
  • 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");
    });
}

Enter fullscreen mode Exit fullscreen mode
  • 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}%)`;
}

Enter fullscreen mode Exit fullscreen mode
  • 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();
}

Enter fullscreen mode Exit fullscreen mode
  • 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();
    });
});

Enter fullscreen mode Exit fullscreen mode
  • 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();
}

Enter fullscreen mode Exit fullscreen mode
  • 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();
}

Enter fullscreen mode Exit fullscreen mode
  • 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());

Enter fullscreen mode Exit fullscreen mode
  • Event Listeners: Handle user interactions, such as choosing an image, adjusting filters, and saving the edited image.

3. Usage

  1. Choose an Image: Click the "Choose Image" button to load an image from your device.
  2. Apply Filters: Select a filter and adjust its value using

the slider.

  1. Rotate & Flip: Use the rotate and flip buttons to modify the image orientation.
  2. Reset Filters: Click "Reset Filters" to revert all settings to default.
  3. 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)

Collapse
 
mayowakalejaiye profile image
mayowa-kalejaiye

Wow

Collapse
 
tobidelly profile image
TD!

Awesome!

Collapse
 
be_rajeevkumar profile image
Rajeev Kumar

Amazing work!
Keep going and complete your #100daysofMiva Journey!