Aprende a recortar los márgenes transparentes que rodean un elemento en un lienzo html5.

Cómo eliminar los píxeles transparentes que rodean un Canvas en JavaScript

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 trimCanvasfunció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:

Trim Transparent Pixels around canvas example

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 trimCanvasfunción eliminó los píxeles vacíos que rodean el lienzo original:

Remove transparent pixels from canvas example

Que te diviertas ❤️!


Ingeniero de Software Senior en EPAM Anywhere. Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores