Image to HTML / CSS conversion using pure JS Just for fun I wrote some JavaScript that "converts" an image into pure HTML / CSS. The user is able to select a local image. This image is loaded into an invisible canvas in order to extract pixeldata from the image. Using the pixeldata, a structure of 1x1 &lt;div/&gt; elements is created with each element having its background color set to its corresponding pixel color of the image.

The script works perfectly fine on small (width / height) images, but kills the browser on any large image file. I was wondering if there are some things I can do within my code to solve this issue?



document.addEventListener("DOMContentLoaded", function(event) {
 const file = document.getElementById('file');

 file.addEventListener('change', handleFile);

 function handleFile(e){
  // Create canvas
  let canvas = document.createElement('canvas');
  let ctx = canvas.getContext('2d');
  
  // Load image
  let img = new Image;
  img.src = URL.createObjectURL(e.target.files[0]);
  img.onload = function() {
   // Draw image to canvas
   ctx.drawImage(img, 0, 0, img.width, img.height);
   
   let container = document.createElement('div');
   container.id = 'container';
   container.style.Width = img.width;
   container.style.Height = img.height;

   let pixelData = ctx.getImageData(0, 0, img.width, img.height).data;
   let pixel = 0;

   // Loop through each row
   for(let x = 0; x &lt; img.height; x++){
    let row = document.createElement('div');
    row.className = 'row';

    // Loop through each column
    for(let y = 0; y &lt; img.width; y++){
     let col = document.createElement('div');
     col.className = 'col';

     col.style.cssText = 'background: rgba('+pixelData[pixel]+','+pixelData[pixel+1]+','+pixelData[pixel+2]+','+pixelData[pixel+3]+');';
     row.appendChild(col);
        pixel = pixel + 4;
    }
    container.appendChild(row);
   }

   document.getElementById('body').appendChild(container);

   URL.revokeObjectURL(img.src);
  }
 }
});
#container {
 margin-left: 50px;
 margin-top: 50px;
}
.row {
 overflow: auto;
}
.row {
 height: 1px;
}
.col {
 width: 1px;
 height: 1px;
 float:left;
}
&lt;body id='body'&gt;
 &lt;input type='file' id='file'/&gt;
&lt;/body&gt;
After working on this for a while with other developers on Stack Overflow chat, the best solution I came up with (so far) was to use an asynchronous loop and adding nodes to a Document Fragment instead of adding them directly to the DOM.

The result:



document.addEventListener("DOMContentLoaded", function(event) {
 const file = document.getElementById('file');

 file.addEventListener('change', handleFile);

 function handleFile(e){
  document.getElementById('container').innerHTML = '';
  
  // Load image
  let img = new Image;
  img.src = URL.createObjectURL(e.target.files[0]);
  img.onload = function() {
   // Create canvas
   let canvas = document.createElement('canvas');
   let ctx = canvas.getContext('2d');
   canvas.width = img.width;
   canvas.height = img.height;

   // Draw image to canvas
   ctx.drawImage(img, 0, 0, img.width, img.height);
   
   let container = document.getElementById('container');
   container.style.width = img.width+'px';
   container.style.height = img.height+'px';

   let pixelData = ctx.getImageData(0, 0, img.width, img.height).data;
   let pixel = 0;
   let processedPixels = 0;
   let total = img.height*img.width;

   (function _asyncLoop(){
    let row = document.createElement('div');
    let fragment = document.createDocumentFragment();
    row.className = 'row';

    let rowPixels = 0;

    do {
     let col = document.createElement('div');
     col.className = 'col';

     col.style.cssText = 'background: rgba('+pixelData[pixel]+','+pixelData[pixel+1]+','+pixelData[pixel+2]+','+pixelData[pixel+3]+');';
     fragment.appendChild(col);
     processedPixels++;
     rowPixels++;
     pixel = pixel + 4;
    } while(rowPixels &lt; img.width);

    row.appendChild(fragment);
    document.getElementById('container').appendChild(row);

    if( processedPixels &lt; total ) setTimeout( _asyncLoop, 100 );
   }());

   URL.revokeObjectURL(img.src);
  }
 }
});
#container {
 margin-left: 50px;
 margin-top: 50px;
}
.row {
 overflow: auto;
}
.row {
 height: 1px;
}
.col {
 width: 1px;
 height: 1px;
 float:left;
}
&lt;body&gt;
 &lt;p&gt;Select an image from your computer and allow Javascript to draw it in the DOM using only DIV elements!&lt;/p&gt;
 &lt;input type='file' id='file'/&gt;
 &lt;div id='container'&gt;&lt;/div&gt;
&lt;/body&gt;