html5 crop,Automatically Crop HTML5 canvas to contents

Let's say this is my canvas, with an evil-looking face drawn on it. I want to use toDataURL() to export my evil face as a PNG; however, the whole canvas is rasterised, including the 'whitespace' between the evil face and canvas edges.

+---------------+

| |

| |

| (.Y. ) |

| /_ |

| \____/ |

| |

| |

+---------------+

What is the best way to crop/trim/shrinkwrap my canvas to its contents, so my PNG is no larger than the face's 'bounding-box', like below? The best way seems to be scaling the canvas, but supposing the contents are dynamic...? I'm sure there should be a simple solution to this, but it's escaping me, with much Googling.

+------+

|(.Y. )|

| /_ |

|\____/|

+------+

Thanks!

function cropImageFromCanvas(ctx, canvas) {

var w = canvas.width,

h = canvas.height,

pix = {x:[], y:[]},

imageData = ctx.getImageData(0,0,canvas.width,canvas.height),

x, y, index;

for (y = 0; y < h; y++) {

for (x = 0; x < w; x++) {

index = (y * w + x) * 4;

if (imageData.data[index+3] > 0) {

pix.x.push(x);

pix.y.push(y);

}

}

}

pix.x.sort(function(a,b){return a-b});

pix.y.sort(function(a,b){return a-b});

var n = pix.x.length-1;

w = pix.x[n] - pix.x[0];

h = pix.y[n] - pix.y[0];

var cut = ctx.getImageData(pix.x[0], pix.y[0], w, h);

canvas.width = w;

canvas.height = h;

ctx.putImageData(cut, 0, 0);

var image = canvas.toDataURL();

var win=window.open(image, '_blank');

win.focus();

}

If I understood well you want to "trim" away all the surronding your image / drawing, and adjust the canvas to that size (like if you do a "trim" command in Photoshop).

Here is how I'll do it.

Run thru all the canvas pixels checking if their alpha component is > 0 (that means that something is drawn in that pixel). Alternativelly you could check for the r,g,b values, if your canvas background is fullfilled with a solid color, for instance.

Get te coordinates of the top most left pixel non-empty, and same for the bottom most right one. So you'll get the coordinates of an imaginay "rectangle" containing the canvas area that is not empty.

Store that region of pixeldata.

Resize your canvas to its new dimensions (the ones of the region we got at step 2.)

Paste the saved region back to the canvas.

Et, voilá :)

Accesing pixeldata is quite slow depending on the size of your canvas (if its huge it can take a while). There are some optimizations around to work with raw canvas pixeldata (I think there is an article about this topic at MDN), I suggest you to google about it.

I prepared a small sketch in jsFiddle that you can use as starting point for your code.

Hope I've helped you.

c:.

The top voted answer here, as well as the implementations i found online trim one extra pixel which was very apparent when trying to trim text out of canvas. I wrote my own that worked better for me:

var img = new Image;

img.onload = () => {

var canvas = document.getElementById('canvas');

canvas.width = img.width;

canvas.height = img.height;

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

ctx.drawImage(img, 0, 0);

document.getElementById('button').addEventListener('click', ()=>{

autoCropCanvas(canvas, ctx);

document.getElementById('button').remove();

});

};

img.src = 'data:image/png;base64,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';

function autoCropCanvas(canvas, ctx) {

var bounds = {

left: 0,

right: canvas.width,

top: 0,

bottom: canvas.height

};

var rows = [];

var cols = [];

var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

for (var x = 0; x < canvas.width; x++) {

cols[x] = cols[x] || false;

for (var y = 0; y < canvas.height; y++) {

rows[y] = rows[y] || false;

const p = y * (canvas.width * 4) + x * 4;

const [r, g, b, a] = [imageData.data[p], imageData.data[p + 1], imageData.data[p + 2], imageData.data[p + 3]];

var isEmptyPixel = Math.max(r, g, b, a) === 0;

if (!isEmptyPixel) {

cols[x] = true;

rows[y] = true;

}

}

}

for (var i = 0; i < rows.length; i++) {

if (rows[i]) {

bounds.top = i ? i - 1 : i;

break;

}

}

for (var i = rows.length; i--; ) {

if (rows[i]) {

bounds.bottom = i < canvas.height ? i + 1 : i;

break;

}

}

for (var i = 0; i < cols.length; i++) {

if (cols[i]) {

bounds.left = i ? i - 1 : i;

break;

}

}

for (var i = cols.length; i--; ) {

if (cols[i]) {

bounds.right = i < canvas.width ? i + 1 : i;

break;

}

}

var newWidth = bounds.right - bounds.left;

var newHeight = bounds.bottom - bounds.top;

var cut = ctx.getImageData(bounds.left, bounds.top, newWidth, newHeight);

canvas.width = newWidth;

canvas.height = newHeight;

ctx.putImageData(cut, 0, 0);

}

crop canvas

来源:https://stackoverflow.com/questions/11796554/automatically-crop-html5-canvas-to-contents

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值