Node.js: Größenänderung von Bildern ohne ImageMagick

85

Ich entwickle eine Web-App auf Node.js (+ Express 4), in der Benutzer ihr Profilbild festlegen können, indem sie es auf den Server hochladen. Wir beschränken bereits den Dateimimetyp und die maximale Dateigröße, sodass der Benutzer nicht mehr als 200 KB PNG- oder JPEG-Bilder hochladen kann.

Das Problem ist, dass wir die Größe der hochgeladenen Bilder auf 200 x 200 ändern möchten, um das Laden von Seiten zu verbessern und Speicherplatz auf der Festplatte zu sparen. Nach einigen Recherchen deuteten alle Antworten auf die Verwendung eines Moduls hin, das auf ImageMagick oder GraphicsMagick basiert.

Die Installation von ImageMagick / GraphicsMagick für eine einfache Größenänderung von Bildern scheint mir jedoch zu übertrieben. Gibt es für Node.js eine andere Lösung als diese?

Bearbeiten: Ich habe die akzeptierte Lösung in scharf geändert, da die vorherige Lösung (lwip) nicht mehr beibehalten wird. Vielen Dank für Ihr Feedback!

zacr0
quelle
Hallo. Ich habe eine Frage. Wie kann die Bildgröße auf unter 200 KB verringert werden? Bitte erläutern Sie den Weg. Vielen Dank.
C.Petrescu
Hallo, diese Frage lohnt es sich, sie als neue zu veröffentlichen, wenn Sie keine verwandte Frage finden, die zuvor gestellt wurde. Versuchen Sie, in der API nach Komprimierungs- und Größenänderungsmethoden zu suchen, die für die in dieser Frage enthaltenen Tools bereitgestellt werden.
zacr0

Antworten:

92

Ich würde für scharf stimmen :

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 ist schnell, normalerweise 6x schneller als die schnellsten Imagemagick-basierten Knotenbindungen und läuft in sehr wenig Speicher, vielleicht 10x weniger . scharfe Links zur libvips-Bildbibliothek direkt, es gibt kein Shelling zu einem externen Programm, und die Bibliothek selbst ist bei dieser Aufgabe schneller und effizienter als * magick. Es unterstützt nützliche Dinge wie die Eingabe und Ausgabe von Streams, Puffern und Dateisystemen, Farbmanagement, Transparenz, Versprechen, Überlagerungen, WebP, SVG und mehr.

Ab Punkt 0.20 lädt npm auf den meisten Plattformen automatisch vollständige vorkompilierte Binärdateien herunter, sodass Node-Gyp nicht erforderlich ist. Geben Sie einfach ein:

npm install sharp

oder:

yarn add sharp

Und los geht's.

jcupitt
quelle
7
Ab Version 0.12.0 sharpgibt es keine externen Laufzeitabhängigkeiten mehr für Linux- und Windows-Benutzer, da eine vorkompilierte Version von libvips gebündelt wird. Sie werden feststellen, dass Größenänderungsvorgänge ~ 10x schneller als LWIP und zu einem Bruchteil der Speichernutzung sind.
Lovell Fuller
4
scharf hinzugefügt native GIF- und SVG-Unterstützung mit Version 0.15 scharf.dimens.io/en/stable/changelog
jcupitt
1
Es sind Hunderte von Dateien, aber alle werden automatisch von npm für Sie verwaltet. Sie müssen nicht darüber nachdenken.
JCupitt
4
@CoDEmanX Vielleicht versuchen Sie es npm install --global --production windows-build-toolszuerst. Siehe auch github.com/Microsoft/nodejs-guidelines/blob/master/…
Lovell Fuller
1
Ich habe ein kleines Skript erstellt, mit dem ich leicht erkennen kann, was die Dinge tun und wie es in Inhalten wie Boostrap-Karten und Hintergrund aussehen würde: Cover, um die Parameter optimal zu optimieren, vielleicht von Interesse github.com/lcherone/sharp-test
Lawrence Cherone
71

Ich habe vor kurzem begonnen, ein Bildverarbeitungsmodul für NodeJS ohne Laufzeitabhängigkeiten zu entwickeln ( lesen Sie warum ). Es ist noch in einem frühen Stadium, aber bereits verwendbar.

Was Sie verlangen, würde wie folgt geschehen:

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

Weitere Infos im Github-Repo des Moduls .

EyalAr
quelle
7
Ihr Modul ist fantastisch. Es braucht jedoch so viel Speicher. Ich habe versucht, writeFile ein 1.8MbBild zu erstellen, und es benötigt 130 MB Speicher. Danach mache ich einen Test, indem ich die 4MB, 11000x6000Größe eines Bildes auf mehrere Miniaturansichten (640.560.480, ..., 160) ändere. Es benötigt ungefähr 1,7 GB Speicher. Ist das ein Fehler?
Lewis
2
Hallo @Orion, danke für das Feedback. Bitte gehen Sie zum Github-Repo und öffnen Sie ein Problem mit einigen weiteren Details (Betriebssystem, Versionen, Code, um dies zu reproduzieren). Wir werden versuchen, dies gemeinsam zu lösen :)
EyalAr
@EyalAr Hey Eyal, wie kann man die Größe ändern und den Aspekt beibehalten? (Größe ändern auf maximal mögliche Größe von Breite, Höhe) ohne Dehnung
Daniel Krom
10
Ich würde vorschlagen, lwip 2017 nicht zu verwenden. Das Paket scheint nicht mehr unterstützt zu werden und es gibt massive Installationsprobleme unter Windows und jetzt sogar auf Unix-Plattformen.
Zerefel
9
lwip ist leider ein totes projekt. scharf scheint jedoch immer noch aktiv gepflegt zu werden.
Laurent
16

Schauen Sie sich lwip an: https://github.com/EyalAr/lwip

Sehr einfach und leicht zu bedienen

npm install lwip

und dann in Ihrem Knotencode,

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

});

Ich habe dies erfolgreich in meinem Datei-Uploader implementiert und es funktioniert wie ein Zauber.

Arvind
quelle
1
Dies ist, wonach ich gesucht habe, ohne übermäßige, starke externe Abhängigkeiten für einige Funktionen im Zusammenhang mit der Größenänderung von Bildern installieren zu müssen.
zacr0
3
Btw @EyalAr ist der Autor dieses Knotenmoduls. Sein Kommentar ist auch unten aufgeführt.
Arvind
Sehr intuitiv zu installieren und zu arbeiten. Ich mag es wirklich, dass Sie keine binären Bibliotheken wie ImageMagick implementieren müssen.
ChrisRich
Das ist genau das gleiche wie diese Antwort (lwip Besitzer), aber später: stackoverflow.com/a/24543924/1525495
Jorge Fuentes González
12

Es gibt eine gute Bildbearbeitungsbibliothek, die vollständig in JavaScript geschrieben ist, ohne Abhängigkeiten zu anderen Bibliotheken, Jimp. https://github.com/oliver-moran/jimp

Anwendungsbeispiel:

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
quelle
Wie schnell ist das im Vergleich zu ImageMagik?
Christopher Grigg
2
scharf hat eine Reihe von Benchmarks: scharf.dimens.io/en/stable/performance --- Bei diesem Test ist jimp 5x langsamer als IM und 30x langsamer als scharf. Natürlich ist schnell genug schnell genug und Geschwindigkeit ist nicht der einzige zu berücksichtigende Faktor.
JCupitt
Echtzeit vielleicht nicht, aber Jimp ist großartig, um nur Miniaturbilddateien in mehreren Größen zu schreiben (und sie anschließend als zwischengespeicherte Dateien abzurufen).
Coderofsalvation
jimp unterstützt webp nicht und wird es in naher Zukunft nicht unterstützen. Siehe: github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov
8

scharf hat in letzter Zeit einige Popularität genossen, aber es ist die gleiche Idee wie * Magick-Bindungen.

Die Installation von ImageMagick / GraphicsMagick für eine einfache Bildgrößenänderung scheint mir jedoch zu übertrieben

Die Größenänderung von Bildern ist alles andere als einfach. Das JPEG-Format ist besonders komplex und es gibt verschiedene Möglichkeiten, Grafiken mit Ergebnissen unterschiedlicher Qualität zu skalieren, von denen nur wenige einfach zu implementieren sind. Für diesen Job gibt es Bildverarbeitungsbibliotheken. Wenn es also keinen anderen Grund gibt, warum Sie sie nicht installieren können, versuchen Sie es.

Ry-
quelle
13
Vielleicht bin ich ein fauler Entwickler, aber als ich den Installationsprozess für ImageMagick sah und mich fragte, wie viel ich für die Installation auf meiner Amazon AWS EC2-Instanz ausgeben würde, suchte ich sofort nach anderen Optionen - vor allem, wenn ich bedachte, dass alles, was ich brauchte die Möglichkeit, die Größe von Bildern für Miniaturansichten zu ändern.
ChrisRich
7

Canvas ist 2,3-mal schneller als ImageMagic.

Sie können versuchen, Node.js-Module für die Bildbearbeitung zu vergleichen - 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
quelle
3

Wenn Sie kein großes Bild benötigen, können Sie die Größe auf der Clientseite ändern, bevor Sie es hochladen:

Lesen von Dateien in JavaScript mithilfe der Datei-APIs

Ändern der Bildgröße auf der Clientseite mit Javascript vor dem Hochladen auf den Server

Viele Benutzer haben möglicherweise ein gutes Bild von sich selbst von einem Smartphone, und viele von ihnen sind über 200 KB groß. Beachten Sie, dass vom Client bereitgestellte Daten nicht vertrauenswürdig sind, sodass weiterhin serverseitige Überprüfungen gelten.

Andrei Volgin
quelle
2
Sie können dem Client niemals vertrauen, ein Benutzer muss nur den Upload-Endpunkt kennen, um dort zu senden, was er will. Daher gelten weiterhin Überprüfungen wie die Dateigröße. Eine Größenänderung auf der Client-Seite ist jedoch eine gute Idee.
Kev
1

Ich habe lwip verwendet (wie zuvor von arvind vorgeschlagen), aber auf png-crop umgestellt . Es scheint für mich etwas schneller zu funktionieren (Win 8.1 x64, Node v0.12.7). Der Code im Repo sieht unglaublich leicht aus und ist betrieblich einfach zu bedienen.

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

Natürlich werden nur PNG-Dateien ausgeführt ...

Dan Caseley
quelle
0

Sharp funktioniert sehr gut und ist einfach mit Streams zu verwenden, funktioniert wie ein Zauber, aber Sie müssen es mit der Knotenversion kompilieren, dies ist ein Nachteil. Ich habe Sharp für die Bildverarbeitung mit einem Bild aus einem AWS S3-Bucket verwendet und habe einwandfrei funktioniert, musste aber ein anderes Modul verwenden. GM hat nicht für mich gearbeitet, aber Jimp hat sehr gut gearbeitet!

Sie müssen auf den Pfad des geschriebenen Bildes achten. Wenn Sie den Pfad mit einem "/" beginnen, kann dies zu Fehlern führen.

So habe ich Jimp in nodeJS verwendet:

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

            });

Achten Sie auch auf die Reihenfolge der Ausführung und rufen Sie zurück, damit andere Dinge nicht passieren, wenn Sie nicht möchten. Ich habe versucht, "warte" für Jimp.read () zu verwenden, aber es hat den Job nicht gut gemacht.

Alex Seceleanu
quelle
Ab Punkt 0.20 wird auf den meisten Plattformen automatisch eine vorkompilierte Binärdatei für Ihre genaue Knotenversion heruntergeladen, sodass Sie nichts erstellen müssen.
JCupitt
Leider hat es bei mir nicht funktioniert. Ich musste scharf in einem schreibgeschützten Dateisystem mit verschiedenen node.js-Versionen verwenden, und ich musste das scharfe Modul für jede von mir verwendete Knotenversion herunterladen, und es dauerte zu lange.
Alex Seceleanu
0

Sie können dies mit jimp (node_module) tun.

Lokales Schreiben:

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

Zum Hochladen auf s3 oder wo immer Sie möchten.

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
quelle
0

Ich mag resize-img Bibliothek für seine Einfachheit.

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
quelle
0

Implementierte Größenänderung von Bildern mithilfe der Google Drive API v3 . Diese Methode wird für Google Apps Script empfohlen, um Bilder in Google Sheets einzufügen.

Algorythm:

  1. Laden Sie das Bild in den Google Drive-Ordner hoch.
  2. Holen image thumbnail öffentliche URL.
  3. Ersetzen Sie den Parameter 'Größe ändern' in der URL durch die erforderliche Breite und / oder Höhe. (Die Standardgröße für Miniaturansichten beträgt 220 Pixel.)
  4. Laden Sie die Miniaturansicht in der Größe von Google Drive herunter.

Siehe Beispiel hier: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

Und Vorsicht vor GDrive-Quoten:

  • Anfragen pro Tag: 1000000000
  • Abfragen pro 100 Sek. pro Benutzer: 1000
  • Abfragen pro 100 Sek.: 10000
Viacheslav Dobromyslov
quelle