0

I am working on a photo editor and I want to download the edited image after the user makes the necessary changes on the original one. So the filter value depends on the user and is not constant

The changes are working fine but when I click download I get the original one instead of the modified one. Does anyone have any ideas on how I can proceed further? (P.S. I searched all over Stack Overflow and tried to implement every solution in my code but nothing's working)

const canvas = document.getElementById("img");
const ctx = canvas.getContext("2d");

let img = new Image();
let fileName = "";

const downloadBtn = document.getElementById("download-btn");
const uploadFile = document.getElementById("upload-file");
const revertBtn = document.getElementById("revert-btn");

// Upload File
uploadFile.addEventListener("change", () => {
  // Get File
  const file = document.getElementById("upload-file").files[0];
  // Init FileReader API
  const reader = new FileReader();

  // Check for file
  if (file) {
    // Set file name
    fileName = file.name;
    // Read data as URL
    reader.readAsDataURL(file);
  }

  // Add image to canvas
  reader.addEventListener(
    "load",
    () => {
      // Create image
      img = new Image();
      // Set image src
      img.src = reader.result;
      // On image load add to canvas
      img.onload = function() {
        canvas.width = img.width;
        canvas.height = img.height;
        ctx.drawImage(img, 0, 0, img.width, img.height);
        canvas.removeAttribute("data-caman-id");
      };
    },
    false
  );
});
// Download Event
downloadBtn.addEventListener("click", () => {
  // Get ext
  const fileExtension = fileName.slice(-4);

  // Init new filename
  let newFilename;

  // Check image type
  if (fileExtension === ".jpg" || fileExtension === ".png") {
    // new filename
    newFilename = fileName.substring(0, fileName.length - 4) + "-edited.jpg";
  }

  // Call download
  download(canvas, newFilename);
});

// Download
function download(canvas, filename) {
  // Init event
  let e;
  // Create link
  const link = document.createElement("a");

  // Set props
  link.download = filename;
  link.href = canvas.toDataURL("image/jpeg", 0.8);
  // New mouse event
  e = new MouseEvent("click");
  // Dispatch event
  link.dispatchEvent(e);
}
const options = {
  sepia: 0,
  rotation: 0,
  scale: 1,

};

function setSepia(e) {
  options.sepia = e.value;
  document.getElementById('Amount').innerHTML = "(" + e.value + ")";
  redraw();
}
let rotation = 0;

function RotateImg() {
  rotation += 90;
  if (rotation == 360) {
    rotation = 0;
  }
  options.rotation = rotation;
  redraw();
}

let scale = 1

function flipping() {
  scale -= 2
  if (scale <= -2) {
    scale = 1;
  }
  options.scale = scale;
  redraw();
}

let invertVal = 0

function invert() {
  invertVal += 100
  if (invertVal > 100) {
    invertVal = 0
  }
  options.invertVal = invertVal;
  redraw();
}

function redraw() {
  document.getElementById("img").style["webkitFilter"] = "sepia(" + options.sepia + ") 
  grayscale(" + options.grayscale + ") brightness(" + options.brightness + ") contrast(" + 
    options.contrast + ") opacity(" + options.opacity + ") invert(" + options.invertVal + ")"; document.querySelector("img").style.transform = `rotate(${options.rotation}deg) 
scaleX(${options.scale})`;
  }
<!-- class="custom-file-label" -->
<p><input type="file" id="upload-file">upload</input>
</p>
<p><label for="upload-file">Upload Image</label></p>
<p><canvas id="img"></canvas></p>

<button id="download-btn" class="btn btn-primary btn-block">Download</button>
<div class="sidenav">
  <label for="filter-select">FILTER AND ADJUST</label>
  <div class="slider">
    <p style="color: aliceblue;">Sepia</p>
    <input id="sepia" type="range" oninput="setSepia(this);" value="0" step="0.1" min="0" max="1"><span id="Amount" style="color: white;"> (0)</span><br /><br>


  </div>
  <label onclick="RotateImg()">ROTATE</label>
  <label onclick="flipping()">FLIP</label>
</div>
Antonino
  • 3,178
  • 3
  • 24
  • 39
kavya
  • 1

1 Answers1

1

I tried to run your code without success but I got the idea of what you'd like to do so I started building an image editor that should address many of your doubts

I'll leave here some considerations before:

  • I started on the backbone of this nice editor sample
  • I'm keeping the original file in <img> and I'm putting the edited image in a <canvas>
  • the previewFiles() method is used to set the two images and the most comes from this page
  • as you were correctly doing and as suggested by this question, you will need <canvas> to be able to save the image with CSS filters applied
  • I will apply the multiple filters as shown by this great example
  • and then we will download the edited image [actually <canvas>] following this other great example

NOTE: when I tried to run the example in the StackOverflow editor [this one below] I couldn't really download the image but it works if you run the same code in JSFiddle
NOTE: I tested it on Chrome but I would check more in depth with regards to browser compatibility, if this can be an issue

// checking activity on filters values
// calling the apply_filter method as soon as a slider is moved or set into a position
$(document).ready(function() {
  $(".range").change(apply_filter).mousemove(apply_filter);
});


// global variable
const original_image = document.getElementById('original_image_preview');


// setting canva size and return its context to drawing functions
function initializeCanva() {
  // creating the additional canva to show the filters action
  const canvas = document.getElementById('edited_image_canva');
  const ctx = canvas.getContext('2d');

  // assigning it the same size of the original image preview
  canvas.width = original_image.width;
  canvas.height = original_image.height;

  return ctx;
}

// loading and previewing the files
function previewFiles() {

  const preview = document.querySelector('img');
  const file = document.querySelector('input[type=file]').files[0];
  const reader = new FileReader();

  // the load event is fired only when a file has been read successfully, unlike loadend - because we need a success to get started
  reader.addEventListener("load", function() {
    // returning the file content
    preview.src = reader.result;

    // creating the canva to reflect the edits immediately after the original image has been loaded
    const ctx = initializeCanva();

    // drawing the original image on the canva
    ctx.drawImage(original_image, 0, 0, original_image.width, original_image.height);
  }, false);

  // reading the contents of the specified [image] file
  // when the read operation is successfully finished, the load event is triggered - at that time, the result attribute contains the data as a data: URL representing the file's data as a base64 encoded string
  if (file) {
    reader.readAsDataURL(file);
  }

}

// called everytime a slider is hovered or moved around
// atm needed also to show the canva after the original image has been loaded
function apply_filter() {

  // getting the filter values from the sliders elements
  var grayscale_val = $("#grayscale").val();
  //console.log(grayscale_val + "%");
  var blur_val = $("#blur").val();
  var exposure_val = $("#exposure").val();
  var sepia_val = $("#sepia").val();
  var opacity_val = $("#opacity").val();

  // getting the context where to apply the changes
  const ctx = initializeCanva();

  // creating the filter from sliders values
  ctx.filter = 'grayscale(' + grayscale_val + '%) blur(' + blur_val + 'px) brightness(' + exposure_val + '%) sepia(' + sepia_val + '%) opacity(' + opacity_val + '%)';
  // console.log(ctx.filter);

  // applying the filter on the original image
  ctx.drawImage(original_image, 0, 0, original_image.width, original_image.height);
}


// triggered by clicking on the download button
function download() {
  //console.log("asking for download");

  // keeping the same image quality
  var data = edited_image_canva.toDataURL("image/png", 1);

  // create temporary link  
  var tmpLink = document.createElement('a');
  tmpLink.download = 'edited_image.png'; // set the name of the download file 
  tmpLink.href = data;

  // temporarily add link to body and initiate the download  
  document.body.appendChild(tmpLink);
  tmpLink.click();
  document.body.removeChild(tmpLink);
}
body {
  text-align: center;
  width: 100%;
  margin: 0 auto;
  padding: 0px;
  font-family: Helvetica, Sans-Serif;
  background-color: #E6E6E6;
}

#wrapper {
  text-align: center;
  margin: 0 auto;
  padding: 0px;
  width: 995px;
}

#edit_controls {
  background-color: #A4A4A4;
  float: left;
  width: 500px;
  margin-left: 248px;
}

#edit_controls li {
  list-style-type: none;
  display: inline-block;
  padding: 0px;
  margin: 10px;
  color: white;
}

#images_div img {
  width: 80%;
  padding: 20px;
}

#images_div canvas {
  border: 3px solid #d3d3d3;
}

button {
  margin: 20px;
}
<html>

<head>
  <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>

<body>
  <div id="wrapper">

    <!-- filters area -->
    <div id="edit_controls">
      <li>GrayScale<br><input id="grayscale" class="range" type="range" min="0" max="100" value="0"></li>
      <li>Blur<br><input id="blur" class="range" type="range" min="0" max="10" value="0"></li>
      <li>Exposure<br><input id="exposure" class="range" type="range" min="0" max="200" value="100"></li>
      <li>Sepia<br><input id="sepia" class="range" type="range" min="0" max="100" value="0"></li>
      <li>Opacity<br><input id="opacity" class="range" type="range" min="0" max="100" value="100"></li>
    </div>

    <!-- images area -->
    <div id="images_div">
      <!-- accepting only image files -->
      <input type="file" accept="image/*" onchange="previewFiles()" style="margin-top: 20px"><br>
      <img src="" id="original_image_preview" alt="Waiting for the image to edit...">
      <br />Edited Image<br /><br />
      <canvas id="edited_image_canva">
          Your browser does not support the HTML5 canvas tag
        </canvas>
      <br />
      <button onclick="download()">Download</button>
    </div>

  </div>
</body>

</html>
Dharman
  • 30,962
  • 25
  • 85
  • 135
Antonino
  • 3,178
  • 3
  • 24
  • 39