0

I am trying to optimize some code that uses the canvas.drawImage() call. This is a pretty expensive call when called several hundreds or thousands of times. Found out about the canvas.toBlob(callback) method but I want to know if there is a way to get only a section of the canvas.

drawimage() gives much more fine grain control over which sections should be draw.

canvas.drawImage(canvas, sx, sy, sw, sh, dx, dy, dw, dh);

Any suggestions / thoughts are welcomed!

JerryFox
  • 615
  • 2
  • 13
  • 25

1 Answers1

1

The canvas.toBlob method is currently only supported by Firefox browser.
For it to work on other browsers, you can use this code to convert a base64 dataURI to a blob object.

Now, to get only a portion of the canvas through these methods, you'll have to create a new canvas, set its dimensions to the cropped ones and draw the part you want on it :

var img = new Image();
img.crossOrigin = 'anonymous';
img.src = "http://i.imgur.com/fHyEMsl.jpg";

var resultImg = new Image();
var resultSize = document.createElement('span');
document.body.appendChild(resultImg);
document.body.appendChild(resultSize);

var cropped = {x: 0, y: 0, width: 130, height: 130};

var canvas = document.createElement('canvas');
document.body.appendChild(canvas);

img.onload = function() {
  canvas.width = this.width;
  canvas.height = this.height;
  canvas.getContext('2d').drawImage(this, 0, 0);
  setInterval(cropCanvas, 1000);
}

function cropCanvas() {
  URL.revokeObjectURL(resultImg.src);
  var newCanvas = document.createElement('canvas');
  newCanvas.width = cropped.width;
  newCanvas.height = cropped.height;
  newCanvas.getContext('2d').drawImage(canvas, -cropped.x, -cropped.y);
  if (newCanvas.toBlob) { // Firefox
    newCanvas.toBlob(function(blob) {
      resultImg.src = URL.createObjectURL(blob);
      resultSize.innerHTML = blob.size + ' bytes';
    }, 'image/jpeg');
  } else { // all other browsers
    var blob = dataURItoBlob(newCanvas.toDataURL('image/jpeg'));
    resultImg.src = URL.createObjectURL(blob);
    resultSize.innerHTML = blob.size + ' bytes';
  }
  //move our crop
  if (cropped.x < img.width - 130)
    cropped.x += 130;
  else {
    if (cropped.y < img.height - 130) {
      cropped.y += 130;
      cropped.x = 0;
    } else {
      cropped.x = 0;
      cropped.y = 0;
    }
  }
}

// taken from https://stackoverflow.com/questions/4998908/convert-data-uri-to-file-then-append-to-formdata/5100158#5100158
function dataURItoBlob(dataURI) {
  var byteString;
  if (dataURI.split(',')[0].indexOf('base64') >= 0)
    byteString = atob(dataURI.split(',')[1]);
  else
    byteString = unescape(dataURI.split(',')[1]);

  var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

  var ia = new Uint8Array(byteString.length);
  for (var i = 0; i < byteString.length; i++) {
    ia[i] = byteString.charCodeAt(i);
  }

  return new Blob([ia], {
    type: mimeString
  });
}
Community
  • 1
  • 1
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • 1
    the issue is that I am trying to convert a piece of the canvas to a blob type to then convert to a data uri. Ideally I want to avoid the drawimage method of this canvas altogether – JerryFox Sep 18 '15 at 18:04
  • 1
    If you don't need the blob, don't convret it to blob but directly to a dataURL. The `toDataURL` method has no cropping property, **you have to draw it on another canvas** in order to make the crop. Ps, if you are concerned about performances, you've to know that `toDataURL` or `toBlob` are something like [5000 times slower than drawimage](http://stackoverflow.com/a/6003174/3702797) – Kaiido Sep 19 '15 at 01:51
  • hmm that unfortunately then. Will need to find some other workaround. – JerryFox Sep 24 '15 at 23:12
  • 1
    Why? That's the way to do it. Simply avoid converting to blob in the above example, you'll have you cropped dataURL – Kaiido Sep 24 '15 at 23:17
  • I meant to the way to improve performance on what I am working on – JerryFox Sep 24 '15 at 23:19
  • 1
    But whatever you're working on, this post does answer this question. It's the only way to crop a toBlob/toDataURL. – Kaiido Sep 24 '15 at 23:22