更好的修剪功能。
虽然给出的答案有效,但它包含一个潜在的危险缺陷,创建一个新的画布而不是裁剪现有的画布,并且(链接区域搜索)效率有些低。
如果您对画布有其他引用,则创建第二个画布可能会出现问题,这很常见,因为通常有两个对画布的引用,例如canvas 和ctx.canvas。闭包可能会使移除引用变得困难,如果闭包结束某个事件,您可能永远无法移除参考。
缺陷是画布不包含像素。允许将画布设置为零大小(canvas.width = 0; canvas.height = 0; 不会引发错误),但某些函数不能接受零作为参数并会引发错误(例如,ctx.getImageData(0,0,ctx.canvas.width,ctx.canvas.height); 是常见做法,但如果画布会引发错误没有大小)。由于这与调整大小没有直接关联,因此可以忽略此潜在的崩溃并进入生产代码。
链接搜索会检查每次搜索的所有像素,在找到边缘时包含简单的break 会改进搜索,但平均而言搜索速度仍然更快。同时在两个方向上搜索,顶部和底部然后左右将减少迭代次数。而不是为每个像素测试计算每个像素的地址,您可以通过逐步执行索引来提高性能。例如data[idx++] 比data[x + y * w] 快很多
更强大的解决方案。
以下函数将使用两遍搜索从画布上裁剪透明边缘,同时考虑到第一遍的结果以减少第二遍的搜索区域。
如果没有像素,它不会裁剪画布,但会返回false,以便采取行动。如果画布包含像素,它将返回true。
在原地裁剪画布时,无需更改对画布的任何引用。
// ctx is the 2d context of the canvas to be trimmed
// This function will return false if the canvas contains no or no non transparent pixels.
// Returns true if the canvas contains non transparent pixels
function trimCanvas(ctx) { // removes transparent edges
var x, y, w, h, top, left, right, bottom, data, idx1, idx2, found, imgData;
w = ctx.canvas.width;
h = ctx.canvas.height;
if (!w && !h) { return false }
imgData = ctx.getImageData(0, 0, w, h);
data = new Uint32Array(imgData.data.buffer);
idx1 = 0;
idx2 = w * h - 1;
found = false;
// search from top and bottom to find first rows containing a non transparent pixel.
for (y = 0; y < h && !found; y += 1) {
for (x = 0; x < w; x += 1) {
if (data[idx1++] && !top) {
top = y + 1;
if (bottom) { // top and bottom found then stop the search
found = true;
break;
}
}
if (data[idx2--] && !bottom) {
bottom = h - y - 1;
if (top) { // top and bottom found then stop the search
found = true;
break;
}
}
}
if (y > h - y && !top && !bottom) { return false } // image is completely blank so do nothing
}
top -= 1; // correct top
found = false;
// search from left and right to find first column containing a non transparent pixel.
for (x = 0; x < w && !found; x += 1) {
idx1 = top * w + x;
idx2 = top * w + (w - x - 1);
for (y = top; y <= bottom; y += 1) {
if (data[idx1] && !left) {
left = x + 1;
if (right) { // if left and right found then stop the search
found = true;
break;
}
}
if (data[idx2] && !right) {
right = w - x - 1;
if (left) { // if left and right found then stop the search
found = true;
break;
}
}
idx1 += w;
idx2 += w;
}
}
left -= 1; // correct left
if(w === right - left + 1 && h === bottom - top + 1) { return true } // no need to crop if no change in size
w = right - left + 1;
h = bottom - top + 1;
ctx.canvas.width = w;
ctx.canvas.height = h;
ctx.putImageData(imgData, -left, -top);
return true;
}