javascript

Rotar imagen en navegador web con JavaScript y canvas

En este artículo te voy a enseñar a rotar una imagen con HTML y JavaScript a través de canvas, de manera que podrás girar una imagen los grados que tú quieras, es decir, rotarla 90, 180, 270 o cualquier cantidad.

Veremos cómo cargar una imagen, pintarla en un canvas, agregarle rotación y después hacer cosas como descargar esa imagen o enviarla al backend que puede ser con Node, C#, PHP, etcétera.

Cargando imagen en canvas

Lo primero que haremos será dibujar nuestra imagen en un elemento canvas en lugar de usar un elemento img directamente en el HTML.

Aquí es importante mencionar que debemos cargar la imagen desde el mismo origen donde ejecutamos el script, y si no lo hacemos entonces debemos especificar el crossOrigin de la imagen en anonymous  y agregar encabezados CORS en el servidor del otro origen.

const imagen = new Image();
imagen.src = "http://localhost/pusheen.png";
imagen.crossOrigin = "anonymous";
imagen.onload = () => {
    let medidaMayor = imagen.width;
    if (imagen.height > medidaMayor) {
        medidaMayor = imagen.height;
    }
    $canvas.width = medidaMayor;
    $canvas.height = medidaMayor;
    context.drawImage(imagen, 0, 0);
};

En el ejemplo de arriba estoy cargando una imagen de localhost, y como mi script se carga en ese mismo origen no hay problema.

El tamaño del canvas es definido como un cuadrado en donde cada lado medirá la mayor medida de la imagen. Es decir, si el ancho es mayor que el alto, el canvas medirá ancho*ancho, y si el alto es mayor entonces el canvas medirá alto*alto.

Finalmente dibujamos la imagen en el canvas, para ello invocamos a drawImage.

Rotar imagen con JavaScript

Hasta este punto tenemos la imagen dibujada en el canvas. Lo que sigue es trasladarnos al centro, rotar el canvas y volver a dibujar la imagen. Veamos la siguiente función:

const dibujarSegunGrados = (grados) => {
    context.clearRect(0, 0, $canvas.width, $canvas.height);
    context.save();
    context.translate($canvas.width / 2, $canvas.height / 2);
    context.rotate(grados * Math.PI / 180);
    context.drawImage(imagen, -imagen.width / 2, -imagen.width / 2);
    context.restore();
};

La función recibe los grados que se debe rotar la imagen con JS. Lo que hace es limpiar el canvas, guardar el contexto, trasladarse al centro, rotar, dibujar la imagen y restaurar el contexto. Ahora solo debemos pasarle la cantidad de grados y listo.

Nota: en este caso context es el contexto del canvas obtenido con getContext, y $canvas es el elemento canvas obtenido con querySelector. Son variables globales que se explican mejor en el código completo.

Ahora solo falta rotar la imagen a la derecha o a la izquierda. Definimos una variable de grados con valor inicial en 0 y la aumentamos o restamos según sea rotada al a izquierda o derecha, luego invocamos a dibujarSegunGrados:

$btnRotarDerecha.addEventListener("click", () => {
    grados += 90;
    dibujarSegunGrados(grados);
});

$btnRotarIzquierda.addEventListener("click", () => {
    grados -= 90;
    dibujarSegunGrados(grados);
});

Poniendo todo junto

El código completo con los botones y el canvas queda así:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button id="rotarDerecha">Derecha</button>
    <button id="rotarIzquierda">Izquierda</button>
    <button id="enviar">Enviar</button>
    <canvas id="canvas"></canvas>
</body>
<script>
    const $canvas = document.querySelector("#canvas");
    const $btnRotarDerecha = document.querySelector("#rotarDerecha");
    const $btnRotarIzquierda = document.querySelector("#rotarIzquierda");
    const $btnEnviar = document.querySelector("#enviar");
    const context = $canvas.getContext("2d");



    const enviar = async () => {
        const data = $canvas.toDataURL("image/png");
        const fd = new FormData();
        fd.append("imagen", data);
        const respuestaHttp = await fetch("http://localhost/recibir.php", {
            method: "POST",
            body: fd,
        });
        const nombreImagenSubida = await respuestaHttp.json();
        console.log({ nombreImagenSubida });
    }



    // https://parzibyte.me/blog
    let grados = 0;
    const imagen = new Image();
    imagen.src = "./captura_codigo.png";
    imagen.crossOrigin = "anonymous";
    imagen.onload = () => {
        let medidaMayor = imagen.width;
        if (imagen.height > medidaMayor) {
            medidaMayor = imagen.height;
        }
        $canvas.width = medidaMayor;
        $canvas.height = medidaMayor;
        context.drawImage(imagen, 0, 0);
    };
    $btnRotarDerecha.addEventListener("click", () => {
        grados += 90;
        dibujarSegunGrados(grados);
    });

    $btnRotarIzquierda.addEventListener("click", () => {
        grados -= 90;
        dibujarSegunGrados(grados);
    });
    $btnEnviar.addEventListener("click", async () => {
        await enviar();
    });

    const dibujarSegunGrados = (grados) => {
        context.clearRect(0, 0, $canvas.width, $canvas.height);
        context.save();
        context.translate($canvas.width / 2, $canvas.height / 2);
        context.rotate(grados * Math.PI / 180);
        context.drawImage(imagen, -imagen.width / 2, -imagen.width / 2);
        context.restore();
    };


</script>

</html>

Puedes probarlo en el siguiente enlace: https://parzibyte.github.io/ejemplos-javascript/rotar-imagen/

Bonus: enviar imagen rotada

Si has abierto la demostración de cómo rotar la imagen con JS y HTML te habrás dado cuenta de que hay un botón que sirve para Enviar la imagen a un servidor.

Obviamente no funciona en la demostración porque no hay backend, pero funcionará si descargas y configuras el código. En el ejemplo tenemos el siguiente código que usa fetch para invocar al servidor con PHP y enviar el canvas como lo expliqué en mi post:

Por cierto, también puedes descargar la imagen una vez rotada:

Como sea, el código que envía la imagen al backend es el siguiente. No importa si usas Node, C#, Python… al final la imagen estará codificada en base64 en un valor del formulario con la clave imagen:

const enviar = async () => {
    const data = $canvas.toDataURL("image/png");
    const fd = new FormData();
    fd.append("imagen", data);
    const respuestaHttp = await fetch("http://localhost/recibir.php", {
        method: "POST",
        body: fd,
    });
    const nombreImagenSubida = await respuestaHttp.json();
    console.log({ nombreImagenSubida });
}

(obviamente debes cambiar la ruta del backend de la línea 5)

Si la recibimos con PHP el código puede ser el siguiente:

<?php
$imagenCodificada = $_POST["imagen"];
$imagenCodificadaLimpia = str_replace("data:image/png;base64,", "", $imagenCodificada);
$imagenDecodificada = base64_decode($imagenCodificadaLimpia);
$nombreImagenGuardada = "imagen_" . uniqid() . ".png";
file_put_contents($nombreImagenGuardada, $imagenDecodificada);
echo json_encode($nombreImagenGuardada);

Y así es como podemos rotar la imagen en el cliente para luego almacenarla en el servidor. Hay varias combinaciones que puedes hacer con lo expuesto en este post, lo que resta es implementarlo.

Recuerda que cuando procesamos imágenes (por ejemplo, en este caso rotamos una imagen con HTML y JavaScript) es mejor dejar el trabajo pesado en el cliente, así no saturamos nuestro servidor.

Te dejo con más tutoriales de JavaScript en mi blog.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.