在某些情况下, 当你使用Canvas或不使用Canvas时, 你将无法为画布提供固定的大小, 因为它可能是库自动生成的, 现在由你自行负责。这种方法的问题在于, 有时这些画布将在内容周围包含巨大的空白, 基本上是空白空间, 没人会在图像中希望这样做, 因为这会大大增加大小(视觉和文件大小)。
如果你想快速, 轻松地解决此问题, Remy Sharp编写的以下trimCanvas函数将帮助你解决许多开发人员在使用Canvas时可能需要的有问题的功能:
// MIT http://rem.mit-license.org
function trimCanvas(c) {
var ctx = c.getContext('2d'), copy = document.createElement('canvas').getContext('2d'), pixels = ctx.getImageData(0, 0, c.width, c.height), l = pixels.data.length, i, bound = {
top: null, left: null, right: null, bottom: null
}, x, y;
// Iterate over every pixel to find the highest
// and where it ends on every axis ()
for (i = 0; i < l; i += 4) {
if (pixels.data[i + 3] !== 0) {
x = (i / 4) % c.width;
y = ~~((i / 4) / c.width);
if (bound.top === null) {
bound.top = y;
}
if (bound.left === null) {
bound.left = x;
} else if (x < bound.left) {
bound.left = x;
}
if (bound.right === null) {
bound.right = x;
} else if (bound.right < x) {
bound.right = x;
}
if (bound.bottom === null) {
bound.bottom = y;
} else if (bound.bottom < y) {
bound.bottom = y;
}
}
}
// Calculate the height and width of the content
var trimHeight = bound.bottom - bound.top, trimWidth = bound.right - bound.left, trimmed = ctx.getImageData(bound.left, bound.top, trimWidth, trimHeight);
copy.canvas.width = trimWidth;
copy.canvas.height = trimHeight;
copy.putImageData(trimmed, 0, 0);
// Return trimmed canvas
return copy.canvas;
}
该函数的逻辑虽然不容易编写, 但很容易理解。该函数希望将画布对象作为第一个参数, 而不是上下文, 因为脚本需要复制画布才能创建具有其内容的新画布对象, 但不覆盖原始内容。然后, 所有像素都存储在一个数组中, 该数组将使用for循环进行迭代, 以在图像中找到最高边界点以对其进行修剪(基本上是使用存储画布数据的坐标来构建一个对象)。存储点(顶部, 左侧, 底部和右侧)后, 它们将用于剪切画布的原始数据并将新内容附加到创建的副本中。该副本由函数返回, 这意味着将返回另一个Canvas实例。
例子
在此示例中, 我们将向你展示如何使用以下代码修剪将在400×400画布内绘制的火柴人:
<canvas id="stickman" width="400" height="400"></canvas>
<script>
var canvas = document.getElementById("stickman");
context = canvas.getContext("2d"); // get Canvas Context object
context.beginPath();
context.fillStyle = "bisque"; // #ffe4c4
context.arc(200, 50, 30, 0, Math.PI * 2, true); // draw circle for head
// (x, y) center, radius, start angle, end angle, anticlockwise
context.fill();
context.beginPath();
context.strokeStyle = "red"; // color
context.lineWidth = 3;
context.arc(200, 50, 20, 0, Math.PI, false); // draw semicircle for smiling
context.stroke();
// eyes
context.beginPath();
context.fillStyle = "green"; // color
context.arc(190, 45, 3, 0, Math.PI * 2, true); // draw left eye
context.fill();
context.arc(210, 45, 3, 0, Math.PI * 2, true); // draw right eye
context.fill();
// body
context.beginPath();
context.moveTo(200, 80);
context.lineTo(200, 180);
context.strokeStyle = "navy";
context.stroke();
// arms
context.beginPath();
context.strokeStyle = "#0000ff"; // blue
context.moveTo(200, 80);
context.lineTo(150, 130);
context.moveTo(200, 80);
context.lineTo(250, 130);
context.stroke();
// legs
context.beginPath();
context.strokeStyle = "orange";
context.moveTo(200, 180);
context.lineTo(150, 280);
context.moveTo(200, 180);
context.lineTo(250, 280);
context.stroke();
</script>
先前的代码将在画布上生成一个火柴人, 如果将其导出, 则png图像的结果如下:
如你所见, 我们只想拥有火柴人, 但是我们的画布比绘制的路径大, 因此, 通过执行以下操作, 可以简单地使用trimCanvas函数丢弃很多空间:
// Crop and obtain the new canvas
var trimmedCanvas = trimCanvas(canvas);
// data:image/png;base64, iVBORw0KGgoAAAANSUhE..........XTklIOUbk4AAAAAElFTkSuQmCC
console.log(trimmedCanvas.toDataURL());
如果显示包含图像的生成的base64字符串的预览, 则输出现在将只是我们的火柴人, 因为trimCanvas函数删除了围绕原始画布的空白像素:
编码愉快!
评论前必须登录!
注册