Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save only a certain part of an HTML canvas

Is it possible to save or export only a certain part of the canvas rather than the whole canvas?

http://i.stack.imgur.com/hmvYh.jpg

At the moment, when I save the file I get the composition plus the transparent background (light blue in example above) of the entire canvas element I have on the site. What I would like to get is only the gray region (which could be made up of several images and text elements).

like image 821
mindo Avatar asked Aug 27 '15 18:08

mindo


2 Answers

Yes you can. Here is the JSFiddle.

First, you need to take a clipping of the image in your canvas. This is pretty simple. I made another canvas (a hidden one) and used the context.drawImage

var hidden_ctx = hidden_canvas.getContext('2d');

hidden_ctx.drawImage(
    MainCanvas,
    startClippingX,
    startClippingY,
    clippingWidth,
    clippingHeight,
    pasteX,
    pasteY,
    pasteWidth,
    pasteHeight
);

Now, we need the Data URL from this canvas so we can download the contents. For this, we will use the canvas.toDataURL method.

var data_url = hidden_canv.toDataURL("image/png");

Now, all we need to do is make a download link (an a element with an href attribute of our data_url) and we're done!

like image 151
WebWanderer Avatar answered Nov 08 '22 02:11

WebWanderer


Suppose you have a canvas called oldCanvas and you want to save a rectangular area of width w and height h with its upper left corner at x, y.

Start by making a new canvas element of width w and height h:

var newCanvas = document.createElement('canvas');
newCanvas.width = w;
newCanvas.height = h;

Now copy the rectangular area to the new canvas:

var newContext = newCanvas.getContext('2d');
newContext.drawImage(oldCanvas, x, y, w, h, 0, 0, w, h);

Finally, save the new canvas using toDataUrl() or whatever method you were using previously to save a whole canvas.

For example, you can make an image out of the new canvas:

var newImage = document.createElement('img');
newImage.src = newCanvas.toDataURL();

Then append the new image to the web page:

document.body.appendChild(newImage);

Or maybe you have a container div that you want to append it to.

In any case, once the image is in the document, you can right-click on it and save it as usual.

I've implemented this approach in the following snippet. When you run it, a canvas will be randomly painted. Click and drag on the canvas to select a region that you want to download. A new, downloadable image appears at right.

// Returns a random RGB string (RGBA if alpha is true).
function randomColor(alpha) {
  var rgb = [
    Math.floor(Math.random() * 255),
    Math.floor(Math.random() * 255),
    Math.floor(Math.random() * 255)
  ];
  if (alpha) {
    rgb.push(Math.random());
  }
  return 'rgb' + (alpha ? 'a' : '') + '(' + rgb.join(', ') + ')';
}

// Makes a random picture for use in the demonstration.
function makeCanvas() {
  var canvas = document.getElementById('oldCanvas'),
      context = canvas.getContext('2d'),
      width = canvas.width = 400,
      height = canvas.height = 500;
  context.fillStyle = randomColor();
  context.fillRect(0, 0, width, height);
  for (var i = 0; i < 200; ++i) {
    var x = Math.floor(Math.random() * width),
        y = Math.floor(Math.random() * height),
        w = Math.floor(Math.random() * width/5),
        h = Math.floor(Math.random() * height/5);
    context.fillStyle = randomColor(true);
    if (Math.floor(Math.random() * 2) === 0) {
      context.fillRect(x - w / 2, y - h / 2, w, h);
    } else {
      context.beginPath();
      context.arc(x, y, w, 0, 2 * Math.PI);
      context.closePath();
      context.fill();
    }
  }
  return canvas;
};

window.onload = function () {
  var oldCanvas = makeCanvas(),
      oldContext = oldCanvas.getContext('2d'),
      targetImage = document.getElementById('targetImage'),
      downloadContainer = document.getElementById('downloadContainer'),
      selectCanvas = document.getElementById('selectCanvas'),
      selectContext = selectCanvas.getContext('2d'),
      width = selectCanvas.width = oldCanvas.width,
      height = selectCanvas.height = oldCanvas.height;
  selectContext.fillStyle = '#000';
  downloadContainer.style.left = width + 25 + 'px';
  var clipCanvas = document.createElement('canvas'),
      clipContext = clipCanvas.getContext('2d');
  downloadContainer.appendChild(clipCanvas);
  selectCanvas.onmousedown = function (event) {
    var x0 = Math.max(0, Math.min(event.clientX, width)),
        y0 = Math.max(0, Math.min(event.clientY, height));
    targetImage.style.display = 'none';
    function update(event) {
      var x = Math.max(0, Math.min(event.clientX, width)),
          y = Math.max(0, Math.min(event.clientY, height)),
          dx = x - x0, w = Math.abs(dx),
          dy = y - y0, h = Math.abs(dy);
      selectContext.clearRect(0, 0, width, height);
      selectContext.fillRect(x0, y0, dx, dy);
      clipCanvas.width = w;
      clipCanvas.height = h;
      if (w*h == 0) {
        downloadContainer.style.visibility = 'hidden';
      } else {
        downloadContainer.style.visibility = 'visible';
        clipContext.drawImage(oldCanvas,
          x0 + Math.min(0, dx), y0 + Math.min(0, dy), w, h,
          0, 0, w, h);
        downloadContainer.style.visibility = (w*h == 0 ? 'hidden' : 'visible');
        downloadContainer.style.top = Math.min(y0, y) + 'px';
      }
    };
    update(event);
    selectCanvas.onmousemove = update;
    document.onmouseup = function (event) {
      selectCanvas.onmousemove = undefined;
      document.onmouseup = undefined;
      targetImage.src = clipCanvas.toDataURL();
      targetImage.style.display = 'block';
    };
  };
};
body, div, canvas, img {
  margin: 0;
  padding: 0;
}
#targetImage {
  display: none;
  position: absolute;
  left: 0;
  top: 0;
}
canvas {
  display: block;
}
#oldCanvas, #selectCanvas, #downloadContainer {
  position: fixed;
}
#downloadContainer {
  visibility: hidden;
}
#downloadContainer .label {
  position: absolute;
  width: 500px;
  bottom: -20px;
  font-family: sans-serif;
  font-size: 17px;
  color: #444;
}
#selectCanvas {
  opacity: 0.5;
  cursor: default;
}
<canvas id="oldCanvas"></canvas>

<canvas id="selectCanvas"></canvas>

<div id="downloadContainer">
  <div class="label"> right-click above to download this image </div>
  <img id="targetImage">
</div>
like image 33
Michael Laszlo Avatar answered Nov 08 '22 00:11

Michael Laszlo