Skip welcome & menu and move to editor
Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
  <meta name="description" content="Image resize on client with supersampling">
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <canvas id="c" width="100" height="300"></canvas>
  
  <br>
  <input type="file" id="f" multiple>
  <button id="run">run</button>
  <button id="save">save</button>
  
  <div id="log"></div>
  
</body>
</html>
 
body {
  font-family: sans-serif;
  line-height: 1.4;
}
 
// noprotect
function supersampleFast(xsizeIn, ysizeIn, data, xsizeOut, ysizeOut, dataOut) {
  var xres = xsizeOut / xsizeIn;
  var yres = ysizeOut / ysizeIn;
  xsizeIn = xsizeIn|0;
  xsizeOut = xsizeOut|0;
  var buf = new Int32Array(xsizeOut * 4);
  var pxx = new Int32Array(xsizeIn);
  var pcountx = new Int32Array(xsizeOut);
  for (var x = 0; x < xsizeIn; x++) {
    var dstx = (x * xres + xres / 2)|0;
    pxx[x] = dstx * 4;
    pcountx[dstx] += 1;
  }
  var lastyy = 0;
  var county = 0;
  var lowY = 0;
  for (var i = 0; i < data.length; i++) {
    var dataIn = data[i];
    var nextY = Math.floor(dataIn.length / xsizeIn / 4);
    for (y = 0; y < nextY; y++) {
      var yy = ((y + lowY) * yres + yres / 2)|0;
      if (yy > lastyy) {
        var dstIndex = lastyy * xsizeOut * 4;
        var xcc = 0;
        for (var x = 0; x < xsizeOut; x++) {
          var count = (county * pcountx[x])|0;
          dataOut[dstIndex + xcc + 0] = (buf[xcc + 0] + (count >> 1)) / count;
          dataOut[dstIndex + xcc + 1] = (buf[xcc + 1] + (count >> 1)) / count;
          dataOut[dstIndex + xcc + 2] = (buf[xcc + 2] + (count >> 1)) / count;
          dataOut[dstIndex + xcc + 3] = (buf[xcc + 3] + (count >> 1)) / count;
          xcc += 4;
        }
        var buf = new Int32Array(xsizeOut * 4);
        county = 0;
      }
      lastyy = yy;
      county += 1;
      var srcIndex = y * xsizeIn * 4;
      for (var x = 0; x < xsizeIn; x++) {
        var xx = pxx[x];
        buf[xx + 0] += dataIn[srcIndex + 0];
        buf[xx + 1] += dataIn[srcIndex + 1];
        buf[xx + 2] += dataIn[srcIndex + 2];
        buf[xx + 3] += dataIn[srcIndex + 3];
        srcIndex += 4;
      }
    }
    lowY += nextY;
  }
  var dstIndex = lastyy * xsizeOut * 4;
  var xcc = 0;
  for (var x = 0; x < xsizeOut; x++) {
    var count = (county * pcountx[x])|0;
    dataOut[dstIndex + xcc + 0] = (buf[xcc + 0] + (count >> 1)) / count;
    dataOut[dstIndex + xcc + 1] = (buf[xcc + 1] + (count >> 1)) / count;
    dataOut[dstIndex + xcc + 2] = (buf[xcc + 2] + (count >> 1)) / count;
    dataOut[dstIndex + xcc + 3] = (buf[xcc + 3] + (count >> 1)) / count;
    xcc += 4;
  }
  return dataOut;
}
function supersampleImage(i, ctxOut, callback) {
  var start = new Date();
  function consume(img) {
    var drawTime = 0;
    var getDataTime = 0;
    var width = img.width;
    var chunkHeight = Math.ceil(2 * 1024 * 1024 / width)|0;
    var c = document.createElement('canvas');
    c.width = width;
    c.height = chunkHeight;
    var ctxIn = c.getContext('2d');
    var data = [];
    for (var i = 0; i < img.height; i += chunkHeight) {
      chunkHeight = Math.min(chunkHeight, img.height - i);
      var start = new Date();
      ctxIn.drawImage(img, 0, i, width, chunkHeight, 0, 0, width, chunkHeight);
      var drawTime1 = (new Date() - start);
      start = new Date();
      data.push(ctxIn.getImageData(0, 0, width, chunkHeight).data);
      var getDataTime1 = (new Date() - start);
      drawTime += drawTime1;
      getDataTime += getDataTime1;
      log('&nbsp; &nbsp; draw, get: ' + drawTime1 + ' ' + getDataTime1);
    }
    log('Draw to canvas: ' + drawTime);
    log('Get image data: ' + getDataTime);
    return data;
  }
  var data = consume(i);
  for (var j = 0; j < 1; j++) {
    var imageDataOut = ctxOut.createImageData(ctxOut.canvas.width,
                                              ctxOut.canvas.height);
    start = new Date();
    dataOut = supersampleFast(
      i.width, i.height, data,
      ctxOut.canvas.width, ctxOut.canvas.height,
      imageDataOut.data
    );
    log('Resize: ' + (new Date() - start)); start = new Date();
    ctxOut.putImageData(imageDataOut, 0, 0);
    log('Put data back: ' + (new Date() - start)); 
  }
  start = new Date();
  ctxOut.canvas.toBlob(function(blob) {
    log('Get image blob: ' + ((new Date()) - start));
    callback(blob);
  }, 'image/jpeg');
}
if (!HTMLCanvasElement.prototype.toBlob) {
  Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
   value: function (callback, type, quality) {
      var dataURL = this.toDataURL(type, quality);
      var binStr = atob( dataURL.split(',')[1] ),
          len = binStr.length,
          arr = new Uint8Array(len);
      for (var i=0; i<len; i++ ) {
       arr[i] = binStr.charCodeAt(i);
      }
      callback( new Blob( [arr], {type: type || 'image/png'} ) );
    }
  });
}
var c = document.getElementById('c');
function log(string) {
  console.log(string);
  $('#log').append([string, '<br>']);
}
function run() {
  var fileUrl = (URL || webkitURL).createObjectURL($('#f').prop('files')[0]);      
  setTimeout(function() {
    var start = new Date();
    var img = new Image();
    img.onload = function() {
      log('Image load: ' + (new Date() - start));
      c.height = 300;
      c.width = 300 * img.width / img.height;
      supersampleImage(img, c.getContext('2d'), function(blob) {
        log('Total: ' + (new Date() - start));
        log('');
      });
    };
    img.src = fileUrl;
  }, 0);
}
$('#run').on('click', run);
$('#f').on('change', run);
$('#save').on('click', function() {
  window.open(c.toDataURL('image/png', 1));
});
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x
public
Bin info
hommpro
0viewers