HomeJavascriptImage Editor | HTML, CSS & Javascript

Image Editor | HTML, CSS & Javascript

Hey everyone. Welcome to today’s tutorial. In today’s tutorial, you will learn how to create an image editor app with download button. To build this app, we need HTML, CSS and Javascript.
 
This is an intermediate to expert-level javascript project. If you are looking for more such projects, you should check out this playlist here. This playlist consists of 100+ projects.
 
The difficulty level of this project varies from simple to quite complex ones. Hence it is suitable for all kinds of learners including beginners to experts.
 
We build an image editor that can rotate the image, flip the image and crop the image. The user can rotate the image to either right or left. We can flip the image horizontally or vertically. And lastly, we can crop the image to a fixed aspect ratio or freely.

Video Tutorial:

If you are interested to learn by watching a video tutorial, you can check out the video down below. Also, subscribe to my youtube channel where I post new tutorials every alternate day.

Project Folder Structure:

Before we start coding, we take a look at the project folder structure. We create a project folder called – ‘Image Editor With Download Button’. Inside this folder, we have three files -index.html, style.css and script.js.

HTML:

We begin with the HTML file. First, copy the code below and paste it into your HTML document.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Image Editor With Download</title>
    <!-- Google Font -->
    <link
      href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap"
      rel="stylesheet"
    />
    <!-- Cropper CDN -->
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.css"
    />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.12/cropper.min.js"></script>
    <!-- Stylesheet -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="wrapper">
      <div class="editor-container">
        <div class="image-container">
          <img id="image" />
        </div>
        <input type="file" id="file" accept="image/*" />
        <label for="file">Open A Photo</label>
        <div class="options-btn hide">
          <button id="rotate-left">
            <img src="rotate-left.png" />
          </button>
          <button id="rotate-right">
            <img src="rotate-right.png" />
          </button>
          <button id="scale-X-button">
            <img src="flip-hori.png" />
          </button>
          <button id="scale-Y-button">
            <img src="flip-ver.png" />
          </button>
          <button class="aspect-ratio-btns">16:9</button>
          <button class="aspect-ratio-btns">4:3</button>
          <button class="aspect-ratio-btns">1:1</button>
          <button class="aspect-ratio-btns">2:3</button>
          <button class="aspect-ratio-btns">Free</button>
        </div>
        <div class="action-btns">
          <button id="preview" class="hide">Preview</button>
          <a href="" id="download" class="hide">Download</a>
        </div>
      </div>
      <div class="preview-container">
        <img id="preview-image" />
      </div>
    </div>
    <!-- Script -->
    <script src="script.js"></script>
  </body>
</html>

CSS:

Next, we style the app with CSS. For this copy, the code provided to you below and paste it into your stylesheet.

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}
.wrapper {
  width: 90%;
  position: absolute;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.editor-container,
.preview-container {
  display: block;
  position: relative;
  width: 100%;
  background-color: #ffffff;
  padding: 2em 1em;
  box-shadow: 0 1.25em 4em rgba(8, 6, 75, 0.15);
  border-radius: 0.5em;
}
.editor-container {
  margin: 0 0.6em 0 0;
}
.preview-container {
  display: grid;
  place-items: center;
}
input[type="file"] {
  display: none;
}
label {
  display: block;
  background-color: #025bee;
  color: #ffffff;
  width: 12em;
  font-size: 1.1em;
  text-align: center;
  padding: 1em 0;
  border-radius: 0.3em;
  margin: auto;
  cursor: pointer;
}
.image-container {
  margin-bottom: 1em;
}
img {
  max-width: 100%;
}
button,
a {
  border: none;
  outline: none;
  place-items: center;
  cursor: pointer;
}
.options-btn {
  margin-top: 1em;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.options-btn button {
  background-color: #dceafe;
  color: #025bee;
  border-radius: 0.3em;
  font-size: 0.8em;
  height: 3.2em;
  width: 3.2em;
}
.options-btn button img {
  width: 1.1em;
}
.action-btns {
  display: flex;
  align-items: center;
  justify-content: space-around;
  margin-top: 1em;
}
#preview,
#download {
  background-color: #025bee;
  font-size: 1em;
  padding: 0.8em 1em;
  color: #ffffff;
  border-radius: 0.3em;
  text-decoration: none;
}
.hide {
  display: none;
}
@media screen and (max-width: 1200px) {
  .wrapper {
    flex-direction: column;
    position: absolute;
    transform: translateX(-50%);
    left: 50%;
    top: 1em;
  }
  img {
    display: block;
    width: 60%;
    margin: 0 auto;
  }
  .editor-container {
    margin: 0 0 0.6em 0;
  }
}

Javascript:

Finally, we add functionality to this app using javascript. Once more, copy the code below and paste it into your script file. We do this in the following steps:

Create Initial References.
Function On Winload Load
Function To Upload & Read Image File.
Add Functionality To Change The Aspect Ratio.
Add Functionality To The Rotate The Image
Function To Preview The Edited Image
Add Functionality To Flip The Image
Function To Download The Edited Image

let fileInput = document.getElementById("file");
let image = document.getElementById("image");
let downloadButton = document.getElementById("download");
let aspectRatioBtns = document.querySelectorAll(".aspect-ratio-btns");
const rotateRightButton = document.getElementById("rotate-right");
const rotateLeftButton = document.getElementById("rotate-left");
const scaleXButton = document.getElementById("scale-X-button");
const scaleYButton = document.getElementById("scale-Y-button");
const previewButton = document.getElementById("preview");
const previewImage = document.getElementById("preview-image");
const options = document.querySelector(".options-btn");
let cropper = "";
let fileName = "";
let scaleXClick = false,
  scaleYClick = false;
let rotateRightValue = -45,
  rotateLeftValue = 45;

//Function on window load
window.onload = () => {
  downloadButton.classList.add("hide");
  options.classList.add("hide");
  previewButton.classList.add("hide");
};

fileInput.onchange = () => {
  //The FileReader object helps tp read contents of file stored on computer
  let reader = new FileReader();
  //readAsDataURL read the content of input file
  reader.readAsDataURL(fileInput.files[0]);
  reader.onload = () => {
    //onload is triggered after file reading operation is successfully completed
    //set src attribute of image to the result/input file
    image.setAttribute("src", reader.result);
    //set filename for setting downloaded file name later
    //initialize cropper
    if (cropper) {
      cropper.destroy();
    }
    cropper = new Cropper(image);
    options.classList.remove("hide");
    previewButton.classList.remove("hide");
  };
  fileName = fileInput.files[0].name.split(".")[0];
};

//Change Aspect Ratio
aspectRatioBtns.forEach((element) => {
  element.addEventListener("click", () => {
    if (element.innerText == "Free") {
      cropper.setAspectRatio(NaN);
    } else {
      cropper.setAspectRatio(eval(element.innerText.replace(":", "/")));
    }
  });
});

//Function for rotate buttons
rotateRightButton.addEventListener("click", () => {
  cropper.rotate(rotateRightValue);
});

rotateLeftButton.addEventListener("click", () => {
  cropper.rotate(rotateLeftValue);
});

//Flip Vertically and flip horizontally
scaleXButton.addEventListener("click", () => {
  if (scaleXClick) {
    cropper.scaleX(1);
    scaleXClick = false;
  } else {
    cropper.scaleX(-1);
    scaleXClick = true;
  }
});

scaleYButton.addEventListener("click", () => {
  if (scaleYClick) {
    cropper.scaleY(1);
    scaleYClick = false;
  } else {
    cropper.scaleY(-1);
    scaleYClick = true;
  }
});

//Function to preview output image
previewButton.addEventListener("click", () => {
  downloadButton.classList.remove("hide");
  let imgSrc = cropper.getCroppedCanvas({}).toDataURL();
  previewImage.src = imgSrc;
});

//Function to download the edited image
downloadButton.addEventListener("click", (e) => {
  //get cropped result
  let imgSrc = cropper.getCroppedCanvas({}).toDataURL();
  //Download name
  downloadButton.download = `cropped_${fileName}.png`;
  downloadButton.setAttribute("href", imgSrc);
});

That’s it for this tutorial. If you face any issues while creating this code, you can download the source code by clicking on the ‘Download Code’ button below. Also, if you have had any queries, suggestions or feedback you can comment below.
Happy Coding!

Previous articleMCQ – 9/10/22
Next articleMCQ – 11/10/22
RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

five × five =

Most Popular