Cómo convertir una cadena de texto SVG o un nodo SVG en una imagen (PNG o JPEG) en el navegador con JavaScript

Cómo convertir una cadena de texto SVG o un nodo SVG en una imagen (PNG o JPEG) en el navegador con JavaScript

Hay muchas operaciones que se pueden realizar en el lado del cliente, por lo que puede ahorrar algo de dinero en la potencia de procesamiento del servidor. Una de las tareas que necesitaba resolver esta semana era encontrar la forma más sencilla de convertir una cadena SVG a un formato de imagen que cualquier usuario pueda entender, ya sea PNG o JPEG.

En este artículo, compartiré con ustedes el método que utilicé para crear una imagen a partir de cualquier cadena SVG o nodo Dom SVG en el navegador con Vanilla JavaScript.

1. Crear la función SVGToImage

La función que te ayudará a convertir tu SVG en una imagen es la siguiente:

/**
 * Función simple que convierte una cadena SVG simple o un nodo DOM SVG en una imagen con dimensiones personalizadas.
 * 
 * @param {Object} settings El objeto de configuración para sobreescribir la configuración predeterminada.
 * @see https://ourcodeworld.com/articles/read/1456/how-to-convert-a-plain-svg-string-or-svg-node-to-an-image-png-or-jpeg-in-the-browser-with-javascript
 * @returns {Promise}
 */
function SVGToImage(settings){
    let _settings = {
        svg: null,
        // Por lo general, todos los SVG tienen transparencia, por lo que PNG es el camino a seguir por defecto
        mimetype: "image/png",
        quality: 0.92,
        width: "auto",
        height: "auto",
        outputFormat: "base64"
    };

    // Anular la configuración predeterminada
    for (let key in settings) { _settings[key] = settings[key]; }

    return new Promise(function(resolve, reject){
        let svgNode;

        // Cree un nodo SVG si se ha proporcionado una cadena simple
        if(typeof(_settings.svg) == "string"){
            // Cree un nodo no visible para representar la cadena SVG
            let SVGContainer = document.createElement("div");
            SVGContainer.style.display = "none";
            SVGContainer.innerHTML = _settings.svg;
            svgNode = SVGContainer.firstElementChild;
        }else{
            svgNode = _settings.svg;
        }

        let canvas = document.createElement('canvas');
        let context = canvas.getContext('2d'); 

        let svgXml = new XMLSerializer().serializeToString(svgNode);
        let svgBase64 = "data:image/svg+xml;base64," + btoa(svgXml);

        const image = new Image();

        image.onload = function(){
            let finalWidth, finalHeight;

            // Calcule el ancho si se establece en automático y se especifica la altura (para preservar la relación de aspecto)
            if(_settings.width === "auto" && _settings.height !== "auto"){
                finalWidth = (this.width / this.height) * _settings.height;
            // Usar ancho original de la imagen
            }else if(_settings.width === "auto"){
                finalWidth = this.naturalWidth;
            // Usar ancho personalizado
            }else{
                finalWidth = _settings.width;
            }

            // Calcule la altura si se establece en automático y se especifica el ancho (para preservar la relación de aspecto)
            if(_settings.height === "auto" && _settings.width !== "auto"){
                finalHeight = (this.height / this.width) * _settings.width;
            // Usar altura original de la imagen
            }else if(_settings.height === "auto"){
                finalHeight = this.naturalHeight;
            // Usar altura personalizada
            }else{
                finalHeight = _settings.height;
            }

            // Definir el tamaño intrínseco del lienzo
            canvas.width = finalWidth;
            canvas.height = finalHeight;

            // Renderizar imagen en el lienzo
            context.drawImage(this, 0, 0, finalWidth, finalHeight);

            if(_settings.outputFormat == "blob"){
                // Completar y devolver la imagen de Blob
                canvas.toBlob(function(blob){
                    resolve(blob);
                }, _settings.mimetype, _settings.quality);
            }else{
                // Completar y devolver la imagen Base64
                resolve(canvas.toDataURL(_settings.mimetype, _settings.quality));
            }
        };

        // Cargue el SVG en Base64 a la imagen
        image.src = svgBase64;
    });
}

SVGToImage recibe como primer argumento un objeto que admite las siguientes propiedades:

  • svg: un nodo DOM de SVG o una cadena simple con datos SVG. Esto se convertirá en una imagen.
  • mimetype: el tipo de mime de salida de la imagen, podría ser image/png image/jpegimage/webp en Chrome también funciona). Por defecto, usa el formato PNG, como es habitual, cada imagen SVG tiene transparencias.
  • width: el ancho de salida en píxeles de la imagen que se creará. De forma predeterminada, toma el ancho de la imagen SVG (automático). Si proporcionas una altura personalizada para la imagen y el ancho se establece en automático, el ancho se calculará automáticamente para preservar la relación de aspecto del SVG.
  • height: la altura de salida en píxeles de la imagen que se creará. De forma predeterminada, toma la altura de la imagen SVG (automático). Si proporcionas un ancho personalizado para la imagen y la altura se establece en automática, la altura se calculará automáticamente para preservar la relación de aspecto del SVG.
  • quality: Un número entre 0 y 1 que indica la calidad de imagen que se utilizará para formatos de imagen que utilizan compresión con pérdida como image/jpegimage/webp. Si este argumento es cualquier otro, se utiliza el valor predeterminado para la calidad de imagen. El valor predeterminado es 0,92.
  • outputFormat: el formato de exportación de la imagen, podría ser base64 para una DataURL o blob.

2. Crear una imagen a partir de una cadena de texto SVG plano

Por ejemplo, si deseas crear una imagen a partir de una cadena de texto SVG plana, puedes usar la función de esta manera:

SVGToImage({
    // 1. Proporcionar el SVG
    svg: `<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"> <path d="M1585 1215q-39 125-123 250-129 196-257 196-49 0-140-32-86-32-151-32-61 0-142 33-81 34-132 34-152 0-301-259-147-261-147-503 0-228 113-374 113-144 284-144 72 0 177 30 104 30 138 30 45 0 143-34 102-34 173-34 119 0 213 65 52 36 104 100-79 67-114 118-65 94-65 207 0 124 69 223t158 126zm-376-1173q0 61-29 136-30 75-93 138-54 54-108 72-37 11-104 17 3-149 78-257 74-107 250-148 1 3 2.5 11t2.5 11q0 4 .5 10t.5 10z"/> </svg>`,
    // 2. Proporcione el formato de la imagen de salida.
    mimetype: "image/png",
    // 3. Proporciona las dimensiones de la imagen si desea un tamaño específico.
    //  - si permanecen en automático, se usará el atributo de ancho y alto del svg
    //  - Puedes proporcionar una única dimensión y la otra se calculará automáticamente
    // width: "auto",
    // height: "auto",
    width: 500,
    height: 500,
    // 4. Especifica la calidad de la imagen
    quality: 1,
    // 5. Definir el formato de la salida (base64 o blob)
    outputFormat: "base64"
}).then(function(outputData){
    // Si usas base64 (genera un DataURL)
    //  data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0...
    // O con Blob (Blob)
    //  Blob {size: 14353, type: "image/png"}
    console.log(outputData);
}).catch(function(err){
    // Registrar cualquier error
    console.log(err);
});

3. Creación de una imagen a partir de un elemento SVG Dom

Si en lugar de una cadena simple, deseas convertir directamente un elemento DOM en tu documento, simplemente puedes seleccionarlo y proporcionarlo en la misma propiedad SVG:

<svg id="my-svg" width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
    <path d="M1585 1215q-39 125-123 250-129 196-257 196-49 0-140-32-86-32-151-32-61 0-142 33-81 34-132 34-152 0-301-259-147-261-147-503 0-228 113-374 113-144 284-144 72 0 177 30 104 30 138 30 45 0 143-34 102-34 173-34 119 0 213 65 52 36 104 100-79 67-114 118-65 94-65 207 0 124 69 223t158 126zm-376-1173q0 61-29 136-30 75-93 138-54 54-108 72-37 11-104 17 3-149 78-257 74-107 250-148 1 3 2.5 11t2.5 11q0 4 .5 10t.5 10z"/>
</svg>

<script>
    SVGToImage({
        // 1. Proporcione el elemento DOM de SVG
        svg: document.getElementById("my-svg"),
        // 2. Proporcione el elemento DOM de SVG
        mimetype: "image/png",
        // 3. Proporcione las dimensiones de la imagen si desea un tamaño específico.
        //  - si permanecen en automático, se usará el atributo de ancho y alto del svg
        //  - Puedes proporcionar una única dimensión y la otra se calculará automáticamente
        // width: "auto",
        // height: "auto",
        width: 500,
        height: 500,
        // 4. Especifica la calidad de la imagen
        quality: 1,
        // 5. Definir el formato de la salida (base64 o blob)
        outputFormat: "base64"
    }).then(function(outputData){
        // Si usas base64 (genera un DataURL)
        //  data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAAH0...
        // O con Blob (Blob)
        //  Blob {size: 14353, type: "image/png"}
        console.log(outputData);
    }).catch(function(err){
        // Registra cualquier error
        console.log(err);
    });
</script>

Prueba en linea

Puedes ver una vista previa en vivo de cómo funciona esta función en el siguiente Fiddle, solo proporciona tu propio SVG en el textarea y envía el formulario para agregar la versión PNG de la imagen en el documento:

Que te diviertas ❤️!

Esto podria interesarte

Conviertete en un programador más sociable