0

I have a page where users can put on themselves images some filters like hue-rotate, blur, invert, saturate and sepia. After, they can dowload it by pressing Save picture button. The problem is picture downloads but without any filters on it. I use canvas and adding filter with CanvasRenderingContext2D.filter. When i check with console.log() my ctx.filter there are filters that i accepted on it. I tried to redraw file with drawImage() function when Save picture button is pressed, it downloads with filters, but here is another problem, current img that User put on page become with filters even when filters reset. I mean picture seems like user have downloaded on page picture with filters already on it. Any suggestions? Below code and picture of page:

window.addEventListener("DOMContentLoaded", () => {
  const filters = document.querySelectorAll(".filters input"),
    btnReset = document.querySelector(".btn.btn-reset"),
    btns = document.querySelectorAll(".btn-container .btn"),
    btnContainer = document.querySelector(".btn-container"),
    btnLoadPicture = document.querySelector(".btn.btn-load #btnInput");
  const canvas = document.querySelector("canvas"),
    ctx = canvas.getContext("2d"),
    saveBtn = document.querySelector(".btn.btn-save");
  const img = new Image();

  // filter change

  function handleUpdate() {
    const suffix = this.dataset.sizing || "";
    document.documentElement.style.setProperty(
      `--${this.name}`,
      this.value + suffix
    );
    this.nextElementSibling.value = this.value;
    filterDownload();
  }
  function filterDownload() {
    let hold = "";
    for (let i = 0; i < filters.length; i++) {
      hold =
        hold +
        filters[i].name +
        "(" +
        filters[i].value +
        filters[i].dataset.sizing +
        ")";
    }
    ctx.filter = hold;
    console.log(ctx);
  }
  
  // load button function

  canvas.dataMaxWidth = canvas.width;
  canvas.dataMaxHeight = canvas.height;
  btnLoadPicture.addEventListener(
    "change",
    (e) => {
      const reader = new FileReader();
      const file = e.target.files[0];

      img.onload = function () {
        let scaled = getScaledDim(
          img,
          ctx.canvas.dataMaxWidth,
          ctx.canvas.dataMaxHeight
        );
        ctx.canvas.width = scaled.width;
        ctx.canvas.height = scaled.height;
        ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
      };
      reader.onloadend = function () {
        img.src = reader.result;
      };
      reader.readAsDataURL(file);
      e.target.value = "";
      hideButton();
      highlightButton(2);
    },
    false
  );
  function getScaledDim(img, maxWidth, maxHeight) {
    let scaled = {
      ratio: img.width / img.height,
      width: img.width,
      height: img.height,
    };
    if (scaled.width > maxWidth) {
      scaled.width = maxWidth;
      scaled.height = scaled.width / scaled.ratio;
    }
    if (scaled.height > maxHeight) {
      scaled.height = maxHeight;
      scaled.width = scaled.height / scaled.ratio;
    }
    return scaled;
  }

  // canvas

  let i = 0;
  function setImage() {
    img.setAttribute("crossOrigin", "anonymous");
    const index = i % images.length;
    let currentTime = new Date();
    if (currentTime.getHours() == 6 || currentTime.getHours() < 12) {
      const imageSrc = imageBaseMorning + images[index];
      img.src = imageSrc;
      i++;
    } else if (currentTime.getHours() == 12 || currentTime.getHours() < 18) {
      const imageSrc = imageBaseDay + images[index];
      img.src = imageSrc;
      i++;
    } else if (currentTime.getHours() == 18 || currentTime.getHours() < 24) {
      const imageSrc = imageBaseEvening + images[index];
      img.src = imageSrc;
      i++;
    } else if (currentTime.getHours() == 0 || currentTime.getHours() < 6) {
      const imageSrc = imageBaseNight + images[index];
      img.src = imageSrc;
      i++;
    }

    img.onload = () => {
      canvas.width = img.width;
      canvas.height = img.height;
      ctx.drawImage(img, 0, 0);
    };
  }
  setImage();

  // Save picture function
  saveBtn.addEventListener("click", saveButton);

  function saveButton() {
    const link = document.createElement("a");
    link.download = "download.png";
    link.href = canvas.toDataURL();
    link.style.display = "none";
    link.click();
    link.remove();

  }
});

HTML:

<main class="main">
  <div class="filters">
    <label>
      Blur:
      <input
        name="blur"
        data-sizing="px"
        type="range"
        min="0"
        max="10"
        value="0"
        id="blur"
      />
      <output name="result" for="blur">0</output>
    </label>

    <label>
      Invert:
      <input
        name="invert"
        data-sizing="%"
        type="range"
        min="0"
        max="100"
        value="0"
        id="invert"
      />
      <output name="result">0</output>
    </label>

    <label>
      Sepia:
      <input
        name="sepia"
        data-sizing="%"
        type="range"
        min="0"
        max="100"
        value="0"
        id="sepia"
      />
      <output name="result">0</output>
    </label>

    <label>
      Saturate:
      <input
        name="saturate"
        data-sizing="%"
        type="range"
        min="0"
        max="200"
        value="100"
        id="saturate"
      />
      <output name="result">100</output>
    </label>

    <label>
      Hue rotate:
      <input
        name="hue-rotate"
        data-sizing="deg"
        type="range"
        min="0"
        max="360"
        value="0"
        id="hue"
      />
      <output name="result">0</output>
    </label>
  </div>
  <div class="editor">
    <div class="btn-container">
      <button class="btn btn-reset">Reset</button>
      <button class="btn btn-next btn-active">Next picture</button>
      <label class="btn btn-load" for="btnInput">
        Load picture
        <input
          class="btn-load--input"
          id="btnInput"
          name="upload"
          type="file"
          placeholder="Load picture"
        />
      </label>
      <button class="btn btn-save">Save picture</button>
    </div>
    <canvas width="1600" height="900"></canvas>
  </div>
</main>

enter image description here

Ruslan
  • 57
  • 5
  • 1
    Maybe this will answer your question [how-to-clear-the-canvas-for-redrawing](https://stackoverflow.com/questions/2142535/how-to-clear-the-canvas-for-redrawing). I guess you need to reset your context before adding a new picture. – wayneOS Jul 22 '21 at 09:20
  • Thanks, you helped me. I added second canvas element and copy from main element, and after i used your method that u sent me. And when i press save button second canvas copy my main canvas, accept all filters, and delete it with clearRect method, so i can download diffrent files again and again – Ruslan Jul 22 '21 at 12:25
  • Your code is quite unclear, could you try to remove everything that is not needed, for instance, remove all the controls and all the conditionals everywhere, use only constant variables and a single image. From a quick look it seems you never redraw on the context after you set the filter, is that right? Setting the filter property only won't change the content of the canvas, it will only be applied for the next drawing. – Kaiido Jul 22 '21 at 13:00
  • a faster way to load/paint images is with `createImageBitmap(blob)` the 2nd way is with `img.src = URL.createObjectURL(file)` the worst way is with fileReader.readAsDataURL – Endless Jul 25 '21 at 10:42

0 Answers0