eli chen
eli chen

Reputation: 878

canvas drawImage img source vs canvas source

I'm using drawImage function with the same image but i got diffrent results when the source is img element vs when the source is canvas(with the same size as original image).

this is the code

  async function draw(src) {

        const mainCanvas = document.getElementById("cnv");
        const ctx = mainCanvas.getContext("2d");
        let img = document.getElementById("img");

        let w = img.width;
        let h = img.height;
        if (src == "cnv") {
         
          const newCnv =      document.createElement("canvas");
          newCnv.width = w;
          newCnv.height = h;

          const newCtx = newCnv.getContext("2d");
          //just to be sure we dont touch the original image data
          newCtx.imageSmoothingEnabled = false;
          // i tested it with all function overloads and still the same
          newCtx.drawImage(img, 0, 0, w, h, 0, 0, w, h);
          img = newCnv;

        }

        let destW = 850;
        const pxr = window.devicePixelRatio;
        let destH = (destW * h) / w;
        mainCanvas.style.width = destW + "px";
        mainCanvas.style.height = destH + "px";

        destW *= pxr;
        destH *= pxr;

        mainCanvas.width = destW;
        mainCanvas.height = destH;

        ctx.imageSmoothingQuality = "high";

        ctx.drawImage(img, 0, 0, destW, destH);
      }
<img
      id="img"
      style="display: none"
      src="https://work.otzar.org/example.png"
    />
<button onclick="draw('img')">drawImage from img</button>
<button onclick="draw('cnv')">drawImage from canvas</button>
<br />
<canvas id="cnv"> </canvas>

i know when you use drawImage its does some work like for example downscale when the dest size is lower. but here the newCnv is the same as the original image so i dont understand why js need to do somestuff othar than just put the pixels data in the canvas.

Upvotes: 1

Views: 543

Answers (1)

Kaiido
Kaiido

Reputation: 136638

The culprit is imageSmothingQuality = "high", I already faced it before, even with ImageBitmaps.
Different sources will get different results with their algo, even two JPEG <img> will have very different quality depending on the compression of the image.

You did well opening that issue.

Note that in my tests then I had the best looking results with imageSmothingQuality = "medium", which also doesn't suffer from this bug.

async function draw(src) {

  const mainCanvas = document.getElementById("cnv");
  const ctx = mainCanvas.getContext("2d");
  let img = document.getElementById("img");

  let w = img.width;
  let h = img.height;
  if (src == "cnv") {

    const newCnv =      document.createElement("canvas");
    newCnv.width = w;
    newCnv.height = h;

    const newCtx = newCnv.getContext("2d");
    //just to be sure we dont touch the original image data
    newCtx.imageSmoothingEnabled = false;
    // i tested it with all function overloads and still the same
    newCtx.drawImage(img, 0, 0, w, h, 0, 0, w, h);
    img = newCnv;

  }

  let destW = 850;
  const pxr = window.devicePixelRatio;
  let destH = (destW * h) / w;
  mainCanvas.style.width = destW + "px";
  mainCanvas.style.height = destH + "px";

  destW *= pxr;
  destH *= pxr;

  mainCanvas.width = destW;
  mainCanvas.height = destH;

  ctx.imageSmoothingQuality = "medium";

  ctx.drawImage(img, 0, 0, destW, destH);
}
<img
      id="img"
      style="display: none"
      src="https://work.otzar.org/example.png"
    />
<button onclick="draw('img')">drawImage from img</button>
<button onclick="draw('cnv')">drawImage from canvas</button>
<br />
<canvas id="cnv"> </canvas>

Upvotes: 1

Related Questions