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.