Trabajar con imágenes en Node.js - GraphicsMagick e ImageMagick

En este artículo, daremos una introducción al uso de GraphicsMagick e ImageMagick para manipular imágenes en Node.js, así como ejemplos de varias funciones admitidas.

Introducción

Dado que las imágenes se han convertido en una parte integral de la web, la necesidad de procesamiento de imágenes se vuelve siempre presente. Existen varias bibliotecas y archivos binarios que se utilizan para el procesamiento de imágenes en Node.js, dos de los cuales son GraphicsMagick e ImageMagick.

ImageMagick es un software de procesamiento de imágenes de código abierto para crear, modificar y convertir imágenes. GraphicsMagick es una herramienta similar que originalmente era una bifurcación del proyecto ImageMagick que se ha convertido en un proyecto independiente propio con varias mejoras.

Algunas de las ventajas que GraphicsMagick tiene sobre ImageMagick incluyen más eficiencia, un tamaño más pequeño, menos vulnerabilidades de seguridad y, en general, es más estable que ImageMagick. Ambos están disponibles para su uso en Node.js como paquetes NPM: GráficosMagia e imagenmagia.

Instalación de GraphicsMagick e ImageMagick {#instalación degraphicsmagickandimagemagick}

Antes de instalar cualquiera de estos paquetes, debe descargar e instalar las herramientas de la interfaz de línea de comandos (CLI) en su sistema. También puede usar ImageMagick directamente desde GraphicsMagick.

Si planea usar el módulo GraphicsMagick, puede instalar imagenmagia o GráficosMagia Herramientas de CLI. Si, en cambio, desea utilizar ImageMagick, debe instalar la herramienta CLI imagenmagia.

Después de descargar e instalar la herramienta CLI requerida, puede verificar la versión de su instalación ejecutando los siguientes comandos en su terminal.

Para ImageMagick:

1
$ convert -version

Si se ha instalado correctamente, se imprimirán los detalles del software instalado en el terminal.

Para GraphicsMagick:

1
2
$ gm convert logo: logo.miff
$ gm convert logo.miff win:

Asimismo, si la instalación fue exitosa, se mostrará el logotipo de GraphicsMagick en una ventana.

A continuación, para agregar el módulo a su proyecto, usaremos npm.

Para ImageMagick:

1
$ npm install imagemagick

Para GraphicsMagick:

1
$ npm install gm

Procesamiento de imágenes en Node.js con GraphicsMagick

En este tutorial, aprenderemos a trabajar con imágenes en Node.js usando GraphicsMagick e ImageMagick. En esta sección, comenzaremos con GraphicsMagick.

Cree una carpeta llamada node-graphics-magick, cd en la carpeta, inicialice el proyecto Node con la configuración predeterminada e instale GraphicsMagick como se muestra a continuación:

1
2
3
4
$ mkdir node-graphics-magick
$ cd node-graphics-magick
$ npm init -y
$ npm install gm

A continuación, abra la carpeta con su editor de código favorito y cree un archivo index.js. Para usar el módulo en el proyecto, impórtelo usando require(). También agregaremos el módulo del sistema de archivos nativo (fs) para ayudarnos a interactuar con el sistema de archivos:

1
2
const fs = require('fs');
const gm = require('gm');

También desea agregar una imagen a su carpeta que se usará en este tutorial, la llamaremos sample_image.

Como se mencionó anteriormente, el módulo GraphicsMagick también le permite usar ImageMagick. Si desea utilizar esta opción, deberá importar la subclase:

1
const gm = require('gm').subClass({imageMagick: true});

Llamar al constructor gm

Hay tres formas de llamar al método constructor gm.

  1. Al pasar la ruta a la imagen como un argumento de cadena:
1
2
3
const gm = require('gm');

gm('sample_image');
  1. También puede pasar un ReadableStream o Buffer como primer argumento, con un nombre de archivo opcional para la inferencia de formato:
1
2
3
4
5
6
7
8
9
const gm = require('gm');

// ReadableStream
let readableImageFileStream = fs.createReadStream('sample_image1.jpeg');
gm(readableImageFileStream, sample_image);

// Buffer
let imageFileBuffer = fs.readFileSync('sample_image1.jpeg');
gm(imageFileBuffer);
  1. Otra opción es pasar dos números enteros para “ancho” y “alto” con un color de fondo opcional para crear una nueva imagen sobre la marcha:
1
2
3
const gm = require('gm');

gm(300, 300, "#00ff55aa");

Obtener información de la imagen

GraphicsMagick proporciona varios captadores para recuperar información sobre imágenes. Uno es el método identify(). Devuelve todos los datos de imagen disponibles:

1
2
3
4
5
6
7
8
9
const gm = require('gm');

gm("sample_image.jpg").identify(function(err, value) {
    console.log(value);

    if(err) {
        console.log(err);
    }
});

Después de incluir el módulo gm, llamamos al constructor gm() y luego llamamos a la función identify() pasando una función que toma dos argumentos: err para obtener cualquier error que ocurra y value que contiene la información de la imagen.

Estamos imprimiendo el valor en nuestra consola y verificando si hay un error. Si se produjo un error, se registrará en la consola. Puede usar ese bloque para detectar errores y mostrar mensajes apropiados en situaciones de la vida real.

Tenga en cuenta que el valor podría ser indefinido.

Ejecutar este código devolverá un objeto con todos los datos de imagen disponibles para la imagen. Así es como se ve la salida para una imagen que usamos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  Format: 'JPEG (Joint Photographic Experts Group JFIF format)',
  format: 'JPEG',
  Geometry: '213x133',
  size: { width: 213, height: 133 },
  Class: 'DirectClass',
  Type: 'true color',
  Depth: '8 bits-per-pixel component',
  ...
  Signature: 'ae5b5e492457ac667e9a4cb1e7b78b7e6459fbf342ea741857ee4e9e1092ad73',
  Tainted: 'False',
  path: 'sample_image.jpg'
}

Proporciona información sobre el “tamaño”, la “resolución”, el “tamaño del archivo” y la “profundidad” del color de la imagen, entre otros. Si desea obtener algunos de estos detalles individualmente, hay una función separada para obtenerlos, como: tamaño(), formato(), profundidad(), orientación(), res() , etc.

Todos tienen la misma sintaxis que la función identificar(). Por ejemplo, si quisiéramos recuperar el tamaño de una imagen, usaríamos:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("sample_image.png").size(function(err, value) {
    console.log(value);
    if(err) {
        console.log(err);
    }
});

Cambiar el tamaño de las imágenes

También es común cambiar el tamaño de las imágenes. La sintaxis de las funciones resize() es:

1
resize(width, [, height [, options]])

Donde los parámetros altura y opciones son opcionales. El parámetro opciones puede ser %, @, !, < o >. Cubriremos cada uno de estos.

El “ancho” y la “altura” especificados son los valores máximos permitidos para ambas propiedades.

Sin especificar ninguna opción, GraphicsMagick mantendrá la relación de aspecto de la imagen original. Si se dan tanto ancho como alto, la imagen se redimensionará hasta que alcance el valor máximo para uno u otro.

Sin embargo, puede obligar al módulo a cambiar el tamaño al ancho y alto dados usando la opción !.

También usamos la función write() para guardar la salida en un nuevo archivo.

Cambiar el tamaño de una imagen a un “ancho” particular mientras se mantiene la relación de aspecto:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("sample_image.jpg")
    .resize(200)
    .write('resized_img_width_only.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });

También podemos cambiar el tamaño de una imagen hasta que su tamaño alcance el “ancho” o “alto” máximos manteniendo la relación de aspecto:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("sample_image.jpg")
    .resize(200, 200)
    .write('resized_img_widthandheight.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    })

O bien, podemos cambiar el tamaño de una imagen para que se ajuste al “ancho” y “alto” exactos, posiblemente cambiando la relación de aspecto original:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("sample_image.jpg")
    .resize(600, 200, '!')
    .write('resized_to_fit.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });

También podemos usar porcentajes en lugar de píxeles para cambiar el tamaño de las imágenes, es decir, podemos cambiar el tamaño de la imagen al 50% de su tamaño original:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("img.png")
    .resize(50, 50, "%")
    .write('resized_img_percentage.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });

Por supuesto, también puedes dar un porcentaje superior al 100% para agrandar la imagen.

Otra opción interesante que puedes usar es @, que cambia el tamaño de la imagen de tal manera que ocupa como máximo ancho*alto píxeles. Esto significa que si escribes algo como esto:

1
2
3
4
5
6
7
8
const gm = require('gm');

gm("sample_image.jpg")
    .resize(100, 100, "@")
    .write('resized_img_max_area_in_pixels.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });

La imagen se redimensionará para que se ajuste a un área de 10 000 píxeles (100 * 100 = 10 000 píxeles). Es decir, si multiplicamos el ancho por el alto de la imagen resultante, será un número menor o igual a 10.000.

Ahora tomaremos las opciones > y <:

  • La opción > cambia el tamaño de una imagen solo si el ancho y la altura de la imagen dada son mayores que el ancho y la altura dadas.
  • La opción < cambia el tamaño de una imagen solo si el ancho y el alto de la imagen dada son menores que el ancho y alto dados.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const gm = require('gm');

// Resize image if image width is greater than 100 and image height is greater than 100
gm("sample_image.jpg")
    .resize(100, 100, ">")
    .write('resized_img_greater_than_100x100.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });
    
// Resize image if image width is less than 100 and image height is less than 100
gm("sample_image.jpg")
    .resize(100, 100, "<")
    .write('resized_img_less_than_100x100.jpg', function (err) {
        if(err) console.log(err);
        console.log("Done!")
    });

Conversión de imágenes de un formato a otro {#conversión de imágenes de un formato a otro}

Otra cosa común que nos gustaría hacer con las imágenes es convertir una imagen de un formato a otro. Esto se puede hacer de una manera muy sencilla, simplemente cambiando la extensión del archivo a uno de los formatos admitidos:

1
2
3
4
5
6
7
const gm = require('gm');

gm("sample_image.jpg")
    .write('sample_image.png', function(err) {
        if(err) console.log(err);
        console.log("Jpg to png!")
    });

Recortar imágenes

Además de cambiar el tamaño de las imágenes, es posible que también desee recortar imágenes en su aplicación. GraphicsMagick tiene una función crop() y su sintaxis es:

1
gm("sample_image.png").crop(width, height, [x, y[, percentage]])

Donde los parámetros tienen el siguiente significado:

  • ancho y alto son las dimensiones a las que desea recortar la imagen. Estos se tratan como números de píxeles o porcentajes de la imagen original según el parámetro “porcentaje”.
  • x e y son parámetros opcionales y representan las coordenadas de la posición desde donde debe comenzar el recorte. El valor predeterminado es 0 para ambos, lo que significa que el recorte comienza desde la esquina superior izquierda de la imagen.
  • El parámetro ‘porcentaje’ también es opcional y se usa para especificar si los valores de ‘ancho’ y ‘alto’ dados representan porcentajes de las dimensiones o píxeles de la imagen. La opción porcentaje por defecto es falso.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
const gm = require('gm');

// Crop image to 100x100 at position 20, 20
gm("sample_image.jpg")
    .crop(100, 100, 20, 20)
    .write('resized_img_crop.jpg', function (err, value) {
        if(err) console.log(err);
        console.log(value);
    });
    

// Crop image to 50% if both width and height at position 10, 10 
gm("sample_image.jpg")
    .crop(50, 50, 10, 10, true)
    .write('resized_img_crop1.jpg', function (err, value) {
        if(err) console.log(err);
        console.log(value);
    });

Nuevamente, si verifica las dimensiones de la nueva imagen resized_img_crop1, puede ver que tiene la mitad del tamaño de la imagen original y está recortada en una posición particular en lugar de en la esquina superior izquierda.

La siguiente imagen muestra un ejemplo:
recortando imágenes con gm

Hemos echado un vistazo a cómo realizar la manipulación de imágenes usando GraphicsMagick. A continuación, veremos cómo hacerlo en ImageMagick.

Procesamiento de imágenes en Node.js con ImageMagick

El módulo ImageMagick no ha recibido mantenimiento durante algún tiempo y los desarrolladores incluso aconsejan usar el módulo GraphicsMagick en su lugar. Sin embargo, para este tutorial, también veremos brevemente algunas de las funciones principales de este módulo.

Cree una carpeta llamada node-image-magick siguiendo los pasos de la sección anterior, instale el módulo ImageMagick a través de npm y cree un archivo index.js.

En el archivo index.js, agregue el módulo usando require():

1
const im = require('image-magick');

Obtener información de la imagen

Para obtener información de la imagen, también hay un método identify() en el módulo image-magick. El primer argumento es la ruta a la imagen y el segundo es una función de devolución de llamada que tiene dos argumentos: err para manejar errores e info para recuperar la información de la imagen:

1
2
3
4
5
6
const im = require('image-magick');

im.identify('sample_image.jpg', function (err, info) {
    if(err) console.log(err);
    console.log(info);
});

Ejecutar este código para nuestra imagen imprime:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  format: 'JPEG',
  'mime type': 'image/jpeg',
  class: 'DirectClass',
  geometry: '213x133+0+0',
  units: 'Undefined',
  colorspace: 'sRGB',
  type: 'TrueColor',
  'base type': 'Undefined',
  endianess: 'Undefined',
  depth: 8,
  'channel depth': { red: '8-bit', green: '8-bit', blue: '8-bit' },
  ...
  width: 213,
  height: 133
}

Cambiar el tamaño de las imágenes

ImageMagick proporciona una función conveniente para cambiar el tamaño de las imágenes que toma un objeto con opciones para cambiar el tamaño de la imagen y una función de devolución de llamada. Cambiar el tamaño de las imágenes usando el módulo ImageMagick sigue la siguiente sintaxis:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const im = require('image-magick');

im.resize({
    srcPath: 'sample_image.jpg',
    dstPath: 'sample_image_resized.jpg',
    width:   256
  }, function(err, stdout, stderr){
       if (err) throw err;
       console.log('resized');
});

Recortar imágenes

ImageMagick también proporciona una función para recortar imágenes con la misma sintaxis que la función resize(). Echemos un vistazo a un ejemplo de uso simple:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
const im = require('image-magick');

im.crop({
    srcPath: 'sample_image.jpg',
    dstPath: 'sample_image_cropped.jpg',
    width: 800,
    height: 600,
    quality: 1,
    gravity: "North"
  }, function(err, stdout, stderr){
       if(err) console.log(err);
});

La documentación proporciona una lista de las opciones para cada una de las funciones anteriores.

Conclusión

En este artículo exploramos cómo trabajar con imágenes en Node.js usando los módulos ImageMagick y GraphicsMagick. GraphicsMagick es la mejor opción de los dos, dadas todas las ventajas que tiene sobre ImageMagick.

El módulo GraphicsMagick tiene una extensa documentación sobre más opciones para manipular imágenes. es.