В некоторых ситуациях, когда вы работаете с Canvas, используя фреймворк или нет, вы не сможете предоставить фиксированный размер холста, поскольку он может автоматически генерироваться библиотекой, и теперь ваша ответственность заключается в том, что с ним делать. Проблема этого подхода заключается в том, что иногда эти холсты будут содержать огромные поля вокруг содержимого, в основном пустые пространства, которые, вероятно, никому не нужны на изображении, поскольку это значительно увеличивает размер (визуальный и размер файла).
Если вы хотите быстро и легко решить эту проблему, выполните следующие действия. 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.
пример
В этом примере мы покажем вам, как обрезать крупье, который будет нарисован внутри холста 400x400, с помощью следующего кода:
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();
Предыдущий код сгенерирует крупье на холсте, если он будет экспортирован, результат изображения png будет следующим:
Как вы можете видеть, мы хотим иметь только stickman, но наш холст больше, чем нарисованный путь, поэтому есть много места, которое мы можем просто выбросить с помощью функции trimCanvas, просто выполнив:
// Crop and obtain the new canvas
var trimmedCanvas = trimCanvas(canvas);
// data:image/png;base64,iVBORw0KGgoAAAANSUhE..........XTklIOUbk4AAAAAElFTkSuQmCC
console.log(trimmedCanvas.toDataURL());
Если вы показываете предварительный просмотр сгенерированной строки base64, которая содержит изображение, вывод будет теперь только нашим крупье как trimCanvas
Функция убрала пустые пиксели, которые окружают оригинальный холст:
Удачного кодирования!