Tworzę aplikację internetową na Node.js (+ express 4), w której użytkownicy mogą ustawić swój obraz profilu, przesyłając go na serwer. Już ograniczamy typ MIME pliku i maksymalny rozmiar pliku, więc użytkownik nie może przesłać więcej niż 200 KB obrazów png lub jpeg.
Problem polega na tym, że chcielibyśmy zmienić rozmiar (po stronie serwera) przesyłanego obrazu do rozdzielczości 200x200, aby poprawić ładowanie strony i zaoszczędzić miejsce na dysku. Po kilku badaniach wszystkie odpowiedzi wskazywały na użycie dowolnego modułu opartego na ImageMagick lub GraphicsMagick.
Jednak konieczność zainstalowania ImageMagick / GraphicsMagick, aby wykonać prostą zmianę rozmiaru obrazu, wydaje mi się zbyt przesadą, więc czy istnieje inne rozwiązanie niż to dla Node.js?
Edycja: Zmieniłem zaakceptowane rozwiązanie na ostre, ponieważ poprzednie rozwiązanie (lwip) nie jest już obsługiwane. Dziękujemy za Twoją opinię!
źródło
Odpowiedzi:
Głosowałbym na ostry :
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 });
Jest szybki, zwykle 6x szybszy niż najszybsze wiązania węzłów oparte na obrazie i działa przy bardzo małej ilości pamięci, być może 10x mniej . ostre linki do biblioteki obrazów libvips bezpośrednio, nie ma wyrzucania do zewnętrznego programu, a sama biblioteka jest szybsza i bardziej wydajna niż * magia w tym zadaniu. Obsługuje przydatne rzeczy, takie jak strumień, bufor i wejście i wyjście systemu plików, zarządzanie kolorami, przezroczystość, obietnice, nakładki, WebP, SVG i inne.
Od wersji Sharp 0.20 npm będzie automatycznie pobierać kompletne, wstępnie skompilowane pliki binarne na większości platform, więc nie ma potrzeby korzystania z node-gyp. Wystarczy wpisać:
lub:
I ruszaj.
źródło
sharp
nie ma już żadnych zewnętrznych zależności wykonawczych dla użytkowników Linuksa i Windows, ponieważ zawiera wstępnie skompilowaną wersję libvips. Przekonasz się, że operacje zmiany rozmiaru są ~ 10x szybsze niż LWIP i przy ułamku użycia pamięci.npm install --global --production windows-build-tools
najpierw uruchomić . Zobacz także github.com/Microsoft/nodejs-guidelines/blob/master/…Niedawno zacząłem tworzyć moduł przetwarzania obrazu dla NodeJS bez żadnych zależności w czasie wykonywania ( przeczytaj dlaczego ). Jest wciąż na wczesnym etapie, ale już można go używać.
To, o co prosisz, powinno wyglądać następująco:
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. }); });
Więcej informacji w repozytorium Github modułu .
źródło
writeFile
uzyskać1.8Mb
obraz i wymaga 130 MB pamięci. Następnie4MB, 11000x6000
wykonuję test, zmieniając rozmiar obrazu do kilku miniatur (640,560,480, ..., 160) i zajmuje około 1,7 GB pamięci. Czy to błąd?Spójrz na lwip: https://github.com/EyalAr/lwip
Bardzo prosty i łatwy w użyciu
a następnie w kodzie węzła,
// 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. }); });
Z powodzeniem zaimplementowałem to w moim programie do przesyłania plików i działa to jak urok.
źródło
Istnieje dobra biblioteka do manipulacji obrazami, napisana w całości w JavaScript, bez zależności od innych bibliotek, Jimp. https://github.com/oliver-moran/jimp
Przykładowe użycie:
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 });
źródło
Sharp cieszy się ostatnio dużą popularnością, ale jest to ten sam pomysł, co wiązania * Magick.
Zmiana rozmiaru obrazu nie jest prosta. Format JPEG jest szczególnie złożony i istnieje kilka sposobów skalowania grafiki w celu uzyskania wyników o różnej jakości. Niewiele z nich można łatwo zaimplementować. Istnieją biblioteki przetwarzające obrazy, które wykonują to zadanie, więc jeśli nie ma innego powodu, dla którego nie możesz ich zainstalować, zrób to.
źródło
Canvas jest 2,3 razy szybsze niż ImageMagic.
Możesz spróbować porównać moduły Node.js do manipulacji obrazami - 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
źródło
Jeśli nie potrzebujesz dużego obrazu, możesz zmienić jego rozmiar po stronie klienta przed przesłaniem:
Odczytywanie plików w języku JavaScript przy użyciu interfejsów API plików
Obraz zmieniający rozmiar po stronie klienta za pomocą javascript przed przesłaniem na serwer
Wielu użytkowników może mieć dobry obraz siebie ze smartfona, a wielu z nich ma ponad 200 kB. Należy pamiętać, że dane dostarczone przez klienta nie są zaufane, więc sprawdzanie po stronie serwera nadal ma zastosowanie.
źródło
Używałem lwip (jak sugerował wcześniej arvind), ale przełączyłem się na png-crop . Wydaje mi się, że działa trochę szybciej (Win 8.1 x64, Node v0.12.7). Kod w repozytorium wygląda na niewiarygodnie lekki, a operacyjnie jest prosty w użyciu.
var pngcrop = require('png-crop'); var config = {left: 10, top: 100, height: 150, width: 150}; pngcrop.crop('cats.png','cats-cropped.png',config);
Oczywiście będzie to robić tylko pliki png ...
źródło
Sharp działa bardzo dobrze i jest łatwy w użyciu ze strumieniami, działa jak urok, ale musisz go skompilować z wersją węzła, jest to wada. Używałem Sharp do przetwarzania obrazu, z obrazem z wiadra AWS S3 i działałem idealnie, ale musiałem użyć innego modułu. GM nie działał dla mnie, ale Jimp pracował bardzo dobrze!
Musisz zwrócić uwagę na ścieżkę zapisanego obrazu, może to spowodować błędy, jeśli zaczniesz ścieżkę od znaku „/”.
Oto jak użyłem Jimp w 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() } } });
Uważaj również na kolejność wykonywania, umieść callback, aby inne rzeczy nie wydarzyły się, gdy nie chcesz. Próbowałem użyć "await" dla Jimp.read (), ale to nie działa dobrze.
źródło
Możesz to zrobić za pomocą jimp (node_module)
Zapis lokalny:
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); });
Aby przesłać do s3 lub gdziekolwiek chcesz.
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); });
źródło
Lubię bibliotekę resize-img ze względu na jej prostotę.
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); })();
źródło
Zaimplementowano zmianę rozmiaru obrazu za pomocą Google Drive API v3 . Ta metoda jest zalecana w przypadku Google Apps Script do wstawiania obrazów do Arkuszy Google.
Algorytm:
Zobacz przykład tutaj: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150
I uważaj na limity GDrive:
źródło