Node.js: cambio de tamaño de imagen sin ImageMagick

85

Estoy desarrollando una aplicación web en Node.js (+ express 4) donde los usuarios pueden configurar su imagen de perfil subiéndola al servidor. Ya limitamos el tipo de archivo mime y max, por lo que el usuario no puede cargar más de 200 KB de imágenes png o jpeg.

El problema es que nos gustaría cambiar el tamaño (en el servidor) de la resolución de la imagen cargada a 200x200 para mejorar la carga de la página y ahorrar espacio en el disco. Después de investigar un poco, todas las respuestas apuntaban al uso de cualquier módulo basado en ImageMagick o GraphicsMagick.

Sin embargo, tener que instalar ImageMagick / GraphicsMagick para hacer un simple cambio de tamaño de imagen me parece demasiado exagerado, entonces, ¿hay alguna otra solución que no sea esta para Node.js?

Editar: he cambiado la solución aceptada a aguda ya que la solución anterior (lwip) ya no se mantiene. ¡Gracias por todos tus comentarios!

zacr0
fuente
Hola. Tengo una pregunta. ¿Cómo disminuir el tamaño de la imagen por debajo de 200 KB? Por favor, explique el camino. Gracias.
C.Petrescu
Hola, vale la pena publicar esa pregunta como nueva si no encuentra ninguna relacionada que se haya publicado anteriormente. Para darle algo de luz, intente buscar métodos de compresión y cambio de tamaño en la API proporcionada para las herramientas que puede encontrar en esta pregunta.
zacr0

Respuestas:

92

Yo votaría por sharp :

sharp('input.jpg')
  .resize(200, 200)
  .toFile('ouput.jpg', function(err) {
    // output.jpg is a 200 pixels wide and 200 pixels high image
    // containing a scaled and cropped version of input.jpg
  });

Es rápido, normalmente 6 veces más rápido que los enlaces de nodo basados ​​en imagemagick más rápidos , y se ejecuta en muy poca memoria, quizás 10 veces menos . enlaces directos a la biblioteca de imágenes libvips directamente, no hay que pagar a un programa externo, y la biblioteca en sí es más rápida y eficiente que * magick en esta tarea. Admite elementos útiles como entrada y salida de flujo, búfer y sistema de archivos, gestión del color, transparencia, promesas, superposiciones, WebP, SVG y más.

A partir de 0,20 npm, npm descargará automáticamente los binarios completos precompilados en la mayoría de las plataformas, por lo que no hay necesidad de node-gyp. Solo ingrese:

npm install sharp

o:

yarn add sharp

Y te vas.

jcupitt
fuente
7
A partir de v0.12.0, sharpya no tiene dependencias de tiempo de ejecución externas para usuarios de Linux y Windows, ya que incluye una versión precompilada de libvips. Encontrará que las operaciones de cambio de tamaño son ~ 10 veces más rápidas que LWIP y con una fracción del uso de memoria.
Lovell Fuller
4
Sharp agregó soporte nativo para gif y svg con la versión 0.15 sharp.dimens.io/en/stable/changelog
jcupitt
1
Son cientos de archivos, pero npm los gestiona todos automáticamente, no es necesario que lo piense.
jcupitt
4
@CoDEmanX Quizás intente ejecutar npm install --global --production windows-build-toolsprimero. Ver también github.com/Microsoft/nodejs-guidelines/blob/master/…
Lovell Fuller
1
Creé un pequeño script que hace que sea fácil ver qué están haciendo las cosas y cómo se vería en el contenido como tarjetas de boostrap y fondo: cubrir para optimizar mejor los parámetros, tal vez sea de interés github.com/lcherone/sharp-test
Lawrence Cherone
71

Recientemente comencé a desarrollar un módulo de procesamiento de imágenes para NodeJS sin dependencias de tiempo de ejecución ( lea por qué ). Todavía está en las primeras etapas, pero ya se puede usar.

Lo que solicita se haría de la siguiente manera:

image.resize(200, 200, function(err, image){
    // encode resized image to jpeg and get a Buffer object
    image.toBuffer('jpg', function(err, buffer){
        // save buffer to disk / send over network / etc.
    });
});

Más información en el repositorio de Github del módulo .

EyalAr
fuente
7
Tu módulo es asombroso. Sin embargo, se necesita mucha memoria. He intentado obtener writeFile una 1.8Mbimagen y requiere 130 Mb de memoria. Después de eso, hago una prueba 4MB, 11000x6000cambiando el tamaño de una imagen a varias miniaturas (640,560,480, ..., 160) y toma aproximadamente 1.7GB de memoria. ¿Eso es un error?
Lewis
2
Hola @Orion, gracias por los comentarios. Dirígete al repositorio de Github y abre un problema con algunos detalles más (sistema operativo, versiones, código para reproducir esto). Intentaremos resolver esto juntos :)
EyalAr
@EyalAr Hola Eyal, ¿cómo cambiar el tamaño y mantener el aspecto? (cambiar el tamaño al tamaño máximo posible de ancho, alto) sin estirar
Daniel Krom
10
Sugeriría no usar lwip en 2017. Parece que el paquete ya no es compatible y tiene problemas de instalación masivos en Windows y ahora incluso en plataformas Unix.
zerefel
9
lwip lamentablemente es un proyecto muerto. agudo, sin embargo, todavía parece mantenerse activamente.
Laurent
16

Eche un vistazo a lwip: https://github.com/EyalAr/lwip

Muy simple y facil de usar

npm install lwip

y luego en su código de nodo,

// obtain an image object:
require('lwip').open('image.jpg', function(err, image){

  // check err...
  // define a batch of manipulations and save to disk as JPEG:
  image.batch()
    .scale(0.75)          // scale to 75%
    .rotate(45, 'white')  // rotate 45degs clockwise (white fill)
    .crop(200)            // crop a 200X200 square from center
    .blur(5)              // Gaussian blur with SD=5
    .writeFile('output.jpg', function(err){
      // check err...
      // done.
    });

});

He implementado con éxito esto en mi cargador de archivos y funciona como un encanto.

Arvind
fuente
1
Esto es lo que estaba buscando, no tener que instalar dependencias externas excesivas y pesadas para un par de funciones relacionadas con el cambio de tamaño de la imagen.
zacr0
3
Por cierto @EyalAr es el autor de este módulo de nodo. Su comentario también se enumera a continuación.
Arvind
Muy intuitivo de instalar y trabajar. Realmente me gusta que no esté obligado a implementar ninguna biblioteca binaria como ImageMagick.
ChrisRich
Eso es exactamente lo mismo que esta respuesta (propietario de lwip), pero más tarde: stackoverflow.com/a/24543924/1525495
Jorge Fuentes González
12

Hay una buena biblioteca de manipulación de imágenes escrita completamente en JavaScript, sin dependencias de ninguna otra biblioteca, Jimp. https://github.com/oliver-moran/jimp

Uso de ejemplo:

var Jimp = require("jimp");

// open a file called "lenna.png"
Jimp.read("lenna.png", function (err, lenna) {
    if (err) throw err;
    lenna.resize(256, 256)            // resize
         .quality(60)                 // set JPEG quality
         .write("lena-small.jpg"); // save
});
edtech
fuente
¿Qué tan rápido es esto en comparación con ImageMagik?
Christopher Grigg
2
sharp tiene un conjunto de puntos de referencia: sharp.dimens.io/en/stable/performance --- En esa prueba, jimp es 5 veces más lento que IM y 30 veces más lento que sharp. Por supuesto, lo suficientemente rápido es lo suficientemente rápido, y la velocidad no es el único factor a considerar.
jcupitt
En tiempo real tal vez no, pero Jimp es increíble simplemente para escribir archivos en miniatura de varios tamaños (y recuperarlos después como archivos en caché).
codificador de salvación
jimp no es compatible con webp y no lo será en un futuro próximo. Ver: github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov
8

sharp ha gozado de cierta popularidad recientemente, pero es la misma idea que las fijaciones * Magick.

Sin embargo, tener que instalar ImageMagick / GraphicsMagick para hacer un simple cambio de tamaño de imagen me parece demasiado exagerado

El cambio de tamaño de la imagen no es nada sencillo. El formato JPEG es particularmente complejo y hay varias formas de escalar gráficos con resultados de calidad variable, pocas de ellas de fácil implementación. Las bibliotecas de procesamiento de imágenes existen para hacer este trabajo, así que si no hay otra razón por la que no pueda instalarlas, hágalo.

Ry-
fuente
13
Tal vez soy un desarrollador vago, pero tan pronto como vi el proceso de instalación de ImageMagick y me pregunté cuánto gastaría en instalarlo en mi instancia Amazon AWS EC2, inmediatamente comencé a buscar otras opciones, especialmente considerando que todo lo que necesitaba era la capacidad de cambiar el tamaño de las imágenes para miniaturas.
ChrisRich
7

Canvas es 2,3 veces más rápido que ImageMagic.

Puede intentar comparar los módulos de Node.js para la manipulación de imágenes: https://github.com/ivanoff/images-manipulation-performance

author's results:
 sharp.js : 9.501 img/sec; minFreeMem: 929Mb
 canvas.js : 8.246 img/sec; minFreeMem: 578Mb
 gm.js : 4.433 img/sec; minFreeMem: 791Mb
 gm-imagemagic.js : 3.654 img/sec; minFreeMem: 804Mb
 lwip.js : 1.203 img/sec; minFreeMem: 54Mb
 jimp.js : 0.445 img/sec; minFreeMem: 82Mb
Dimitry Ivanov
fuente
3

Si no necesita una imagen grande, puede cambiar su tamaño en el lado del cliente antes de cargarla:

Leer archivos en JavaScript usando las API de archivos

Cambio de tamaño de la imagen del lado del cliente con javascript antes de cargarla en el servidor

Muchos usuarios pueden tener una buena imagen de sí mismos desde un teléfono inteligente, y muchos de ellos tienen más de 200kB. Tenga en cuenta que los datos proporcionados por el cliente no son confiables, por lo que aún se aplican las verificaciones del lado del servidor.

Andrei Volgin
fuente
2
Nunca se puede confiar en el cliente, un usuario solo necesita conocer el punto final de carga para enviar lo que quiera allí. Entonces, las validaciones como el tamaño del archivo aún se aplican. Sin embargo, cambiar el tamaño del lado del cliente es una buena idea.
Kev
1

Estaba usando lwip (como sugirió anteriormente arvind) pero cambié a png-crop . Parece funcionar un poco más rápido para mí (Win 8.1 x64, Node v0.12.7). El código en el repositorio parece increíblemente liviano y, desde el punto de vista operativo, es fácil de usar.

var pngcrop = require('png-crop');
var config = {left: 10, top: 100, height: 150, width: 150};
pngcrop.crop('cats.png','cats-cropped.png',config);

Por supuesto, solo hará archivos png ...

Dan Caseley
fuente
0

Sharp funciona muy bien y es fácil de usar con streams, funciona a las mil maravillas, pero necesitas compilarlo con la versión de nodo, esto es una desventaja. Estaba usando Sharp para el procesamiento de imágenes, con una imagen de un bucket de AWS S3 y funcionó perfectamente, pero tuve que usar otro módulo. GM no funcionó para mí, ¡pero Jimp funcionó muy bien!

Debes prestar atención a la ruta de la imagen escrita, podría darte algunos errores si comienzas la ruta con una "/".

Así es como usé Jimp en nodeJS:

const imageUrl = `SOME_URL`;
let imgExported = 'EXPORTED_PIC.png';

Jimp.read(imageUrl)
    .then(image => {
        image   
            .resize(X, Y) 
            .write(`tmp/`+ imgExported, err => { 
                if(err) 
                    console.error('Write error: ', err);
                else { ... // don't forget to put a callback() } }

            });

También tenga cuidado con el orden de ejecución, devuelva la llamada para que no sucedan otras cosas cuando no lo desee. Intenté usar "await" para Jimp.read () pero no funcionó bien.

Alex Seceleanu
fuente
Desde 0,20 nítidos, descargará automáticamente un binario precompilado para la versión exacta de su nodo en la mayoría de las plataformas, por lo que no es necesario compilar nada.
jcupitt
Desafortunadamente, no funcionó para mí. Necesitaba usar sharp en un sistema de archivos de solo lectura, con varias versiones de node.js y tuve que descargar el módulo de sharp para cada versión de nodo que estaba usando y estaba tomando demasiado tiempo.
Alex Seceleanu
0

Puedes hacer esto usando jimp (node_module)

Escritura local:

Jimp.read(path) // this can be url or local location
      .then(image=> {
          image
            .resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
            .write('path-to-save');
      })
      .catch(err => {
        console.log(err);
      });

Para subir a s3 o donde quieras.

Jimp.read(urls) // this can be url or local location
          .then(image=> {
              image
                .resize(size, Jimp.AUTO) // jimp.AUTO automatically sets the width so that the image doesnot looks odd
                .getBase64(Jimp.AUTO, (err, res) => {
                  const buf = new Buffer(
                    res.replace(/^data:image\/\w+;base64,/, ""),
                    "base64"
                  );
                  var data = {
                    Key: key,
                    Bucket: bucket,
                    Body: body,
                    ContentEncoding: "base64",
                    ContentType: "image/jpeg"
                  };
                  s3.putObject(data, function(err, data) {
                    if (err) {
                      throw err;
                    } else {
                      console.log("succesfully uploaded the image!");
                    }
                  });
                });
          })
          .catch(err => {
            console.log(err);
          });
Nouman Dilshad
fuente
0

Me gusta la biblioteca resize-img por su simplicidad.

const fs = require('fs');
const resizeImg = require('resize-img');

(async () => {
    const image = fs.readFileSync('unicorn.png');

    const newImage = await resizeImg(image, { width: 128, height: 128 });

    fs.writeFileSync('unicorn-128x128.png', newImage);
})();
ns16
fuente
0

Se implementó el cambio de tamaño de la imagen usando la API de Google Drive v3 . Este método se recomienda para que Google Apps Script inserte imágenes en Google Sheets.

Algoritmo:

  1. Sube la imagen a la carpeta de Google Drive.
  2. Obtener la URL pública en miniatura de la imagen.
  3. Reemplace el parámetro 'resize' en la URL con el ancho y / o alto necesarios. (El tamaño de miniatura predeterminado es 220px).
  4. Descargue la miniatura redimensionada de Google Drive.

Vea el ejemplo aquí: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

Y cuidado con las cuotas de GDrive:

  • consultas por día: 1000000000
  • consultas por 100 segundos por usuario: 1000
  • consultas por 100 segundos: 10000
Viacheslav Dobromyslov
fuente