Javascript recortar y previsualizar imagen

4 minutos

Previsualizar imagen

No siempre vamos a necesitar adjuntar una imagen en su totalidad, sería deseable facilitar la tarea al usuario antes de que pueda publicarla o subirla a la plataforma. Con algún mágico editor interactivo, capaz de visualizar la previa del recorte. Existen muchos plugins o extensiones que pueden ayudar a salir del paso pero nada a la altura de tu propio código Javascript Vanilla.

A continuación te mostraré como editar una imagen que se termina de adjuntar con el objetivo de transformar el recorte en puro Base64 (representación en texto de un archivo), ideal para guardar o mostrar en cualquier parte de tu HTML.

Demo

–> Pulsa para ver la DEMO interactiva <–

HTML

Dividimos la aplicación en 4 partes: el input donde introduciremos la imagen, la zona donde seleccionaremos el recorte que deseamos, canvas lugar para valorar el recorte y la generación de la imagen en base64.

<!-- Para el editor usaremos croppr.js, importamos sus CDNs -->
<script src="https://cdn.jsdelivr.net/gh/jamesssooi/Croppr.js@2.3.0/dist/croppr.min.js"></script>
<link href="https://cdn.jsdelivr.net/gh/jamesssooi/Croppr.js@2.3.0/dist/croppr.min.css" rel="stylesheet"/>

<h1>1 Introduce tu imagen</h1>
<!-- Input file donde se adjunta la imagen -->
<input type="file" id="image">

<h1>2 Recorta</h1>
<!-- Editor donde se recortará la imagen con la ayuda de croppr.js -->
<div id="editor"></div>

<h1>3 Previsualiza el resultado</h1>
<!-- Previa del recorte -->
<canvas id="preview"></canvas>

<h1>4 Resultado en Base64</h1>
<!-- Muestra de la imagen recortada en Base64 -->
<code id="base64"></code>

Javascript

Ahora vamos al corazón de la aplicación, el Javascript.

// Esperamos a que todo el HTML esté cargado antes de ejecutar Javascrip
document.addEventListener('DOMContentLoaded', () => {

    // Input File
    const inputImage = document.querySelector('#image');
    // Nodo donde estará el editor
    const editor = document.querySelector('#editor');
    // El canvas donde se mostrará la previa
    const miCanvas = document.querySelector('#preview');
    // Contexto del canvas
    const contexto = miCanvas.getContext('2d');
    // Ruta de la imagen seleccionada
    let urlImage = undefined;
    // Evento disparado cuando se adjunte una imagen
    inputImage.addEventListener('change', abrirEditor, false);

    /**
    * Método que abre el editor con la imagen seleccionada
    */
    function abrirEditor(e) {
        // Obtiene la imagen
        urlImage = URL.createObjectURL(e.target.files[0]);

        // Borra editor en caso que existiera una imagen previa
        editor.innerHTML = '';
        let cropprImg = document.createElement('img');
        cropprImg.setAttribute('id', 'croppr');
        editor.appendChild(cropprImg);

        // Limpia la previa en caso que existiera algún elemento previo
        contexto.clearRect(0, 0, miCanvas.width, miCanvas.height);

        // Envia la imagen al editor para su recorte
        document.querySelector('#croppr').setAttribute('src', urlImage);

        // Crea el editor
        new Croppr('#croppr', {
            aspectRatio: 1,
            startSize: [70, 70],
            onCropEnd: recortarImagen
        })
    }

    /**
    * Método que recorta la imagen con las coordenadas proporcionadas con croppr.js
    */
    function recortarImagen(data) {
        // Variables
        const inicioX = data.x;
        const inicioY = data.y;
        const nuevoAncho = data.width;
        const nuevaAltura = data.height;
        const zoom = 1;
        let imagenEn64 = '';
        // La imprimo
        miCanvas.width = nuevoAncho;
        miCanvas.height = nuevaAltura;
        // La declaro
        let miNuevaImagenTemp = new Image();
        // Cuando la imagen se carge se procederá al recorte
        miNuevaImagenTemp.onload = function() {
            // Se recorta
            contexto.drawImage(miNuevaImagenTemp, inicioX, inicioY, nuevoAncho * zoom, nuevaAltura * zoom, 0, 0, nuevoAncho, nuevaAltura);
            // Se transforma a base64
            imagenEn64 = miCanvas.toDataURL("image/jpeg");
            // Mostramos el código generado
            document.querySelector('#base64').textContent = imagenEn64;
            document.querySelector('#base64HTML').textContent = '<img src="' + imagenEn64.slice(0, 40) + '...">';

        }
        // Proporciona la imagen cruda, sin editarla por ahora
        miNuevaImagenTemp.src = urlImage;
    }
});

Resultado final

Todo unido y organizado quedaría con la siguiente silueta.

<html>
    <head>
        <script src="https://cdn.jsdelivr.net/gh/jamesssooi/Croppr.js@2.3.0/dist/croppr.min.js"></script>
        <link href="https://cdn.jsdelivr.net/gh/jamesssooi/Croppr.js@2.3.0/dist/croppr.min.css" rel="stylesheet"/>
        <title>Recorta tu imagen y transforma a base64</title>
        <script>
         document.addEventListener('DOMContentLoaded', () => {

             // Input File
             const inputImage = document.querySelector('#image');
             // Nodo donde estará el editor
             const editor = document.querySelector('#editor');
             // El canvas donde se mostrará la previa
             const miCanvas = document.querySelector('#preview');
             // Contexto del canvas
             const contexto = miCanvas.getContext('2d');
             // Ruta de la imagen seleccionada
             let urlImage = undefined;
             // Evento disparado cuando se adjunte una imagen
             inputImage.addEventListener('change', abrirEditor, false);

             /**
              * Método que abre el editor con la imagen seleccionada
              */
             function abrirEditor(e) {
                 // Obtiene la imagen
                 urlImage = URL.createObjectURL(e.target.files[0]);

                 // Borra editor en caso que existiera una imagen previa
                 editor.innerHTML = '';
                 let cropprImg = document.createElement('img');
                 cropprImg.setAttribute('id', 'croppr');
                 editor.appendChild(cropprImg);

                 // Limpia la previa en caso que existiera algún elemento previo
                 contexto.clearRect(0, 0, miCanvas.width, miCanvas.height);

                 // Envia la imagen al editor para su recorte
                 document.querySelector('#croppr').setAttribute('src', urlImage);

                 // Crea el editor
                 new Croppr('#croppr', {
                     aspectRatio: 1,
                     startSize: [70, 70],
                     onCropEnd: recortarImagen
                 })
             }

             /**
              * Método que recorta la imagen con las coordenadas proporcionadas con croppr.js
              */
             function recortarImagen(data) {
                 // Variables
                 const inicioX = data.x;
                 const inicioY = data.y;
                 const nuevoAncho = data.width;
                 const nuevaAltura = data.height;
                 const zoom = 1;
                 let imagenEn64 = '';
                 // La imprimo
                 miCanvas.width = nuevoAncho;
                 miCanvas.height = nuevaAltura;
                 // La declaro
                 let miNuevaImagenTemp = new Image();
                 // Cuando la imagen se carge se procederá al recorte
                 miNuevaImagenTemp.onload = function() {
                     // Se recorta
                     contexto.drawImage(miNuevaImagenTemp, inicioX, inicioY, nuevoAncho * zoom, nuevaAltura * zoom, 0, 0, nuevoAncho, nuevaAltura);
                     // Se transforma a base64
                     imagenEn64 = miCanvas.toDataURL("image/jpeg");
                     // Mostramos el código generado
                     document.querySelector('#base64').textContent = imagenEn64;
                 }
                 // Proporciona la imagen cruda, sin editarla por ahora
                 miNuevaImagenTemp.src = urlImage;
             }
         });
        </script>
    </head>
    <body>
        <h2>1 Introduce tu imagen</h2>
        <!-- Input file donde se adjunta la imagen -->
        <input type="file" id="image">

        <h2>2 Recorta</h2>
        <!-- Editor donde se recortará la imagen con la ayuda de croppr.js -->
        <div id="editor"></div>

        <h2>3 Previsualiza el resultado</h2>
        <!-- Previa del recorte -->
        <canvas id="preview"></canvas>

        <h2>4 Resultado en Base64</h2>
        <!-- Muestra de la imagen recortada en Base64 -->
        <code id="base64"></code>
    </body>
</html>

¿Alguna propuesta de mejora? Deja un comentario.

Tal vez también te interese...