En algunas situaciones cuando trabaja con Canvas usando o no un framework, no podrá proporcionar un tamaño fijo al lienzo, ya que esto puede ser generado automáticamente por la biblioteca y ahora es su responsabilidad qué hacer con él. El problema de este enfoque es que a veces esos lienzos contendrán enormes márgenes alrededor del contenido, básicamente espacios vacíos que probablemente nadie quiera en la imagen, ya que esto aumenta el tamaño (visual y) considerablemente.
Si está dispuesto a resolver este problema de forma rápida y sencilla, la siguiente trimCanvas
función que ha sido escrita por Remy Sharp le ayudará a resolver esta característica problemática que muchos desarrolladores pueden necesitar algún día cuando trabajen con 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;
// Iterar sobre cada píxel para encontrar el más alto
// y donde termina en cada eje
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;
}
}
}
// Calcula la altura y el ancho del contenido.
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);
// Recortar lienzo y enviar nueva version
return copy.canvas;
}
La lógica de la función, aunque no es sencilla de escribir, se puede entender fácilmente. La función espera como primer argumento un objeto de canvas, no el contexto, ya que el script necesita hacer una copia del lienzo para crear el nuevo con su contenido pero sin sobrescribir el contenido del original. Luego, todos los píxeles se almacenan dentro de una matriz que se repetirá con un bucle for para encontrar los puntos de límite más altos en la imagen para recortarla (básicamente construye un objeto con las coordenadas donde se almacenan los datos de su lienzo). Una vez que se almacenan los puntos (superior, izquierda, inferior y derecha), se utilizan para cortar los datos originales del lienzo y agregar el nuevo contenido a la copia creada. Esta copia es devuelta por la función, lo que significa que se devuelve otra instancia de Canvas.
Ejemplo
En este ejemplo, le mostraremos cómo recortar un stickman que se dibujará dentro de un canvas de 400x400 con el siguiente código:
<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>
El código anterior generará un stickman en el lienzo, si este se exporta, el resultado de la imagen png sería el siguiente:
Como puede ver, solo queremos tener el stickman, pero nuestro lienzo es más grande que la ruta dibujada, por lo que hay mucho espacio que simplemente podemos tirar con la función trimCanvas simplemente haciendo:
// Recorta y obtén el nuevo canvas
var trimmedCanvas = trimCanvas(canvas);
// data:image/png;base64,iVBORw0KGgoAAAANSUhE..........XTklIOUbk4AAAAAElFTkSuQmCC
console.log(trimmedCanvas.toDataURL());
Si muestra una vista previa de la cadena base64 generada que contiene la imagen, la salida ahora será solo nuestro stickman ya que la trimCanvas
función eliminó los píxeles vacíos que rodean el lienzo original:
Que te diviertas ❤️!
Conviertete en un programador más sociable