Search code examples
javascripthtmlcanvashtml5-canvas

How to draw more than one image in html5 canvas without losing resolution using naturalwidth and height of the two images?


I'm trying to draw two images on the same canvas, but the second image being loaded is "erasing" the first. The images are the same size and they complete each other.

HTML:

<canvas id="canvas style="width: 400px"/>
<img id="img1" src="myImage1" />
<img id="img2" src="myImage2" />

JS:

var canvas = document.getElementByID("canvas");
var ctx = canvas.getContext('2d');

var img1 = document.getElementByID("img1");
var img2 = document.getElementByID("img2");

img1.onload = function(){
 canvas.width = img1.naturalWidth;
 canvas.height = img1.naturalHeight;

 ctx.drawImage(img1, 0, 0);
}

img2.onload = function(){
 canvas.width = img2.naturalWidth;
 canvas.height = img2.naturalHeight;

 ctx.drawImage(img2, 0, 0);
}

Solution

  • Changing the size of the canvas clears the context.

    If you're sure the images align, all you have to do is make sure you only initialize once using the dimensions of whichever image loads first:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext('2d');
    
    var img1 = document.getElementById("img1");
    var img2 = document.getElementById("img2");
    
    var didInit = false;
    function init(img) {
      canvas.width = img.naturalWidth;
      canvas.height = img.naturalHeight;
      didInit = true;
    }
    
    img1.onload = function(){
     if (!didInit) init(img1);
     ctx.drawImage(img1, 0, 0);
    }
    
    img2.onload = function(){
     if (!didInit) init(img2);
     ctx.drawImage(img2, 0, 0);
    }
    canvas {
      display: block;
      border: 1px solid lime;
    }
    
    img {
      visibility: hidden;
    }
    <canvas id="canvas"></canvas>
    
    <img id="img1" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAImSURBVHgB7daxDcNADARBvqH+W343IG3MYKYEAgvemZk7bHKGNX4DfBIIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIhGdg5gyvHGafO2xxTSwIAtnFR19GIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBALhGba5wxb3D2JQBpHWtsxvAAAAAElFTkSuQmCC" alt="black" />
    
    <img id="img2" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAIrSURBVHgB7daxDcMwDABBOvD+KyuB6/hrFnegFpDwEK9hlfMMS5zPAK8EAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAuEemDnDP+c6LmeV6xm2sGJBEMgufvNlBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQ7t85wxbeYpkv/gALi57sGR8AAAAASUVORK5CYII=" alt="red" />

    Alternatively, you could wait for all images to be loaded, find the largest width and height dimension, set the canvas size and only then draw all the images to it.

    const canvas = document.getElementById("canvas");
    const ctx = canvas.getContext("2d");
    
    
    const loadedImages = [];
    const drawImagesToPage = () => {
      let maxW = 0;
      let maxH = 0;
      
      for (const img of loadedImages) {
        maxW = Math.max(maxW, img.naturalWidth);
        maxH = Math.max(maxH, img.naturalHeight);
      }
      
      canvas.width = maxW;
      canvas.height = maxH;
      
      for (const img of loadedImages) {
        ctx.drawImage(img, 0, 0);
      }
    }
    
    document
      .querySelectorAll("img")
      .forEach((img, idx, all) => {
        loadedImages.push(img);
        
        if (loadedImages.length === all.length) {
          drawImagesToPage();
        }
      });
    canvas {
      display: block;
      border: 1px solid lime;
    }
    
    img {
      visibility: hidden;
    }
    <canvas id="canvas"></canvas>
    
    <img id="img1" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAImSURBVHgB7daxDcNADARBvqH+W343IG3MYKYEAgvemZk7bHKGNX4DfBIIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIBIFAEAgEgUAQCASBQBAIhGdg5gyvHGafO2xxTSwIAtnFR19GIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBALhGba5wxb3D2JQBpHWtsxvAAAAAElFTkSuQmCC" alt="black" />
    
    <img id="img2" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAIrSURBVHgB7daxDcMwDABBOvD+KyuB6/hrFnegFpDwEK9hlfMMS5zPAK8EAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAuEemDnDP+c6LmeV6xm2sGJBEMgufvNlBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQBAJBIBAEAkEgEAQCQSAQ7t85wxbeYpkv/gALi57sGR8AAAAASUVORK5CYII=" alt="red" />