Node.js: ridimensionamento dell'immagine senza ImageMagick


86

Sto sviluppando un'app web su Node.js (+ express 4) dove gli utenti possono impostare la propria immagine del profilo caricandola sul server. Abbiamo già limitato il tipo MIME e la dimensione massima del file, quindi l'utente non può caricare più di 200 KB di immagini png o jpeg.

Il problema è che vorremmo ridimensionare (lato server) la risoluzione dell'immagine caricata a 200x200 per migliorare il caricamento della pagina e risparmiare spazio su disco. Dopo alcune ricerche, tutte le risposte indicavano l'utilizzo di qualsiasi modulo basato su ImageMagick o GraphicsMagick.

Tuttavia, dover installare ImageMagick / GraphicsMagick per fare un semplice ridimensionamento dell'immagine sembra troppo eccessivo per me, quindi, c'è qualche altra soluzione oltre a questa per Node.js?

Modifica: ho modificato la soluzione accettata in nitida poiché la soluzione precedente (lwip) non viene più mantenuta. Grazie per tutto il tuo feedback!


Ciao. Ho una domanda. Come ridurre la dimensione dell'immagine al di sotto di 200 KB? Per favore, spiega il modo. Grazie.
C.Petrescu

Ciao, vale la pena pubblicarla come nuova domanda se non ne trovi una correlata che era stata precedentemente pubblicata. Per darti un po 'di luce, prova a cercare metodi di compressione e ridimensionamento nell'API fornita per gli strumenti che puoi trovare in questa domanda.
zacr0

Risposte:


92

Voterei per 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
  });

È veloce, genere 6 volte più veloce delle associazioni di nodi basate su imagemagick più veloci e funziona con pochissima memoria, forse 10 volte meno . collegamenti diretti alla libreria di immagini libvips , non ci sono sbocchi su un programma esterno e la libreria stessa è più veloce ed efficiente di * magick in questo compito. Supporta cose utili come stream, buffer e input e output del file system, gestione del colore, trasparenza, promesse, sovrapposizioni, WebP, SVG e altro.

A partire da sharp 0.20, npm scaricherà automaticamente i binari precompilati completi sulla maggior parte delle piattaforme, quindi non c'è bisogno di node-gyp. Basta inserire:

npm install sharp

o:

yarn add sharp

E via.


7
A partire dalla v0.12.0, sharpnon ha più dipendenze di runtime esterne per gli utenti Linux e Windows poiché raggruppa una versione precompilata di libvips. Scoprirai che le operazioni di ridimensionamento sono ~ 10 volte più veloci di LWIP e con una frazione dell'utilizzo della memoria.
Lovell Fuller

4
sharp aggiunto supporto nativo gif e svg con la versione 0.15 sharp.dimens.io/en/stable/changelog
jcupitt

1
Sono centinaia di file, ma sono tutti gestiti automaticamente da npm, non c'è bisogno di pensarci.
jcupitt

4
@CoDEmanX Forse prova a eseguire npm install --global --production windows-build-toolsprima. Vedi anche github.com/Microsoft/nodejs-guidelines/blob/master/…
Lovell Fuller

1
Ho creato un piccolo script che rende facile vedere cosa stanno facendo le cose e come apparirebbero in contenuti come schede boostrap e sfondo: copertina per ottimizzare al meglio i parametri, forse è di interesse github.com/lcherone/sharp-test
Lawrence Cherone

71

Recentemente ho iniziato a sviluppare un modulo di elaborazione delle immagini per NodeJS senza dipendenze di runtime ( leggi perché ). È ancora nelle fasi iniziali, ma già utilizzabile.

Quello che stai chiedendo sarebbe fatto come segue:

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.
    });
});

Maggiori informazioni nel repository Github del modulo .


7
Il tuo modulo è fantastico. Tuttavia, ci vuole così tanta memoria. Ho cercato di un'immagine, e richiede 130MB di memoria. Dopodiché, eseguo un test ridimensionando un'immagine a più miniature (640,560,480, ..., 160) e richiede circa 1,7 GB di memoria. È un bug? writeFile1.8Mb4MB, 11000x6000
Lewis,

2
Ciao @ Orion, grazie per il feedback. Vai al repository Github e apri un problema con alcuni dettagli in più (sistema operativo, versioni, codice per riprodurlo). Cercheremo di risolverlo insieme :)
EyalAr

@ EyalAr Hey Eyal, come ridimensionare e mantenere l'aspetto? (ridimensionare alla dimensione massima possibile di larghezza, altezza) senza allungamento
Daniel Krom

10
Suggerirei di non utilizzare lwip nel 2017. Il pacchetto sembra non essere più supportato e presenta enormi problemi di installazione su Windows e ora anche su piattaforme Unix.
zerefel

9
lwip purtroppo è un progetto morto. sharp tuttavia sembra ancora essere attivamente mantenuto.
laurent

16

Dai un'occhiata a lwip: https://github.com/EyalAr/lwip

Molto semplice e facile da usare

npm install lwip

e poi nel codice del tuo 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.
    });

});

L'ho implementato con successo nel mio uploader di file e funziona a meraviglia.


1
Questo è quello che stavo cercando, non dover installare dipendenze esterne eccessive e pesanti per un paio di funzioni legate al ridimensionamento delle immagini.
zacr0

3
Btw @EyalAr è l'autore di questo modulo del nodo. Il suo commento è anche elencato di seguito.
Arvind

Molto intuitivo da installare e utilizzare. Mi piace davvero che non sia necessario implementare alcuna libreria binaria come ImageMagick.
ChrisRich

È esattamente la stessa di questa risposta (proprietario di lwip), ma in seguito: stackoverflow.com/a/24543924/1525495
Jorge Fuentes González

12

Esiste una buona libreria per la manipolazione delle immagini scritta interamente in JavaScript, senza dipendenze da altre librerie, Jimp. https://github.com/oliver-moran/jimp

Utilizzo di esempio:

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
});

Quanto è veloce rispetto a ImageMagik?
Christopher Grigg

2
sharp ha una serie di benchmark: sharp.dimens.io/en/stable/performance --- In quel test, jimp è 5 volte più lento di IM e 30 volte più lento di sharp. Naturalmente, abbastanza veloce è abbastanza veloce e la velocità non è l'unico fattore da considerare.
jcupitt

In tempo reale forse no, ma Jimp è fantastico solo per scrivere file di miniature di dimensioni multiple (e recuperarli come file memorizzati nella cache in seguito).
coderofsalvation

jimp non supporta webp e non lo supporterà nel prossimo futuro. Vedi: github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov

8

sharp ha goduto di una certa popolarità recentemente, ma è la stessa idea degli attacchi * Magick.

Tuttavia, dover installare ImageMagick / GraphicsMagick per eseguire un semplice ridimensionamento dell'immagine sembra troppo eccessivo per me

Il ridimensionamento delle immagini è tutt'altro che semplice. Il formato JPEG è particolarmente complesso e ci sono diversi modi per ridimensionare la grafica con risultati di qualità variabile, alcuni dei quali facilmente implementabili. Esistono librerie di elaborazione delle immagini per fare questo lavoro, quindi se non c'è altro motivo per cui non puoi installarle, provaci.


13
Forse sono uno sviluppatore pigro, ma non appena ho visto il processo di installazione di ImageMagick e mi chiedevo quanto avrei speso per installarlo sulla mia istanza Amazon AWS EC2, ho subito iniziato a cercare altre opzioni, soprattutto considerando che tutto ciò di cui avevo bisogno era la possibilità di ridimensionare le immagini per le miniature.
ChrisRich

7

Canvas è 2,3 volte più veloce di ImageMagic.

Puoi provare a confrontare i moduli Node.js per la manipolazione delle immagini: 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

3

Se non hai bisogno di un'immagine grande, puoi ridimensionarla sul lato client prima di caricarla:

Lettura di file in JavaScript utilizzando le API di file

Ridimensionamento dell'immagine lato client con javascript prima del caricamento sul server

Molti utenti potrebbero avere una buona immagine di se stessi da uno smartphone e molti di loro superano i 200kB. Tieni presente che i dati forniti dal client non devono essere considerati attendibili, quindi i controlli lato server si applicano comunque.


2
Non puoi mai fidarti del client, un utente deve solo conoscere l'endpoint di caricamento per inviare quello che vuole lì. Quindi, le convalide come la dimensione del file si applicano ancora. Tuttavia, il ridimensionamento sul lato client è comunque una buona idea.
Kev

1

Stavo usando lwip (come suggerito in precedenza da arvind) ma sono passato a png-crop . Sembra funzionare un po 'più velocemente per me (Win 8.1 x64, Node v0.12.7). Il codice nel repository sembra incredibilmente leggero e operativamente è semplice da usare.

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

Certo, farà solo file png ...


0

Sharp funziona molto bene ed è facile da usare con gli stream, funziona come un incantesimo, ma è necessario compilarlo con la versione del nodo, questo è uno svantaggio. Stavo usando Sharp per l'elaborazione delle immagini, con un'immagine da un bucket AWS S3 e funzionava perfettamente, ma ho dovuto usare un altro modulo. GM non ha funzionato per me, ma Jimp ha funzionato molto bene!

Devi prestare attenzione al percorso dell'immagine scritta, potrebbe darti degli errori se inizi il percorso con una "/".

Ecco come ho usato Jimp in 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() } }

            });

Fai anche attenzione all'ordine di esecuzione, metti un callback in modo che altre cose non accadano quando non vuoi. Ho provato a usare "await" per Jimp.read () ma non ha funzionato bene.


Da sharp 0.20, scaricherà automaticamente un binario precompilato per la tua versione esatta del nodo sulla maggior parte delle piattaforme, quindi non è necessario creare nulla.
jcupitt

Purtroppo non ha funzionato per me. Avevo bisogno di usare sharp in un file system di sola lettura, con varie versioni di node.js e dovevo scaricare il modulo sharp per ogni versione di nodo che stavo usando e ci stava mettendo troppo tempo.
Alex Seceleanu

0

Puoi farlo usando jimp (node_module)

Scrittura locale:

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);
      });

Per caricare su s3 o dove vuoi.

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);
          });

0

Mi piace la libreria resize-img per la sua semplicità.

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);
})();

0

Ridimensionamento dell'immagine implementato utilizzando l' API di Google Drive v3 . Questo metodo è consigliato per Google Apps Script per inserire immagini in Fogli Google.

Algoritmo:

  1. Carica l' immagine nella cartella Google Drive.
  2. Ottieni l'URL pubblico della miniatura dell'immagine.
  3. Sostituisci il parametro "ridimensiona" nell'URL con la larghezza e / o l'altezza necessarie. (La dimensione predefinita della miniatura è 220 px).
  4. Scarica la miniatura ridimensionata da Google Drive.

Vedi esempio qui: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

E fai attenzione alle quote di GDrive:

  • query al giorno: 1000000000
  • query per 100 secondi per utente: 1000
  • query per 100 sec: 10000
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.