Node.js: thay đổi kích thước hình ảnh mà không cần ImageMagick


85

Tôi đang phát triển một ứng dụng web trên Node.js (+ express 4), nơi người dùng có thể đặt hình ảnh hồ sơ của họ bằng cách tải nó lên máy chủ. Chúng tôi đã giới hạn mimetype tệp và kích thước tệp tối đa, vì vậy người dùng không thể tải lên hơn 200KB hình ảnh png hoặc jpeg.

Vấn đề là chúng tôi muốn thay đổi kích thước (bên máy chủ) độ phân giải hình ảnh đã tải lên thành 200x200 để cải thiện khả năng tải trang và tiết kiệm dung lượng trên đĩa. Sau một số nghiên cứu, tất cả các câu trả lời đều chỉ ra việc sử dụng bất kỳ mô-đun nào dựa trên ImageMagick hoặc GraphicsMagick.

Tuy nhiên, việc phải cài đặt ImageMagick / GraphicsMagick để thay đổi kích thước hình ảnh đơn giản dường như quá mức cần thiết đối với tôi, vì vậy, có giải pháp nào khác ngoài giải pháp này cho Node.js không?

Chỉnh sửa: Tôi đã thay đổi giải pháp được chấp nhận thành sharp vì giải pháp trước đó (lwip) không còn được duy trì. Cảm ơn tất cả phản hồi của bạn!


Chào. Tôi có một câu hỏi. Làm thế nào để giảm kích thước hình ảnh xuống dưới 200KB? Xin vui lòng, giải thích về cách. Cảm ơn.
C.Petrescu

Xin chào, câu hỏi đó đáng được đăng dưới dạng câu hỏi mới nếu bạn không tìm thấy bất kỳ câu hỏi liên quan nào đã được đăng trước đó. Để cung cấp cho bạn một chút thông tin, hãy thử tìm kiếm các phương pháp nén và thay đổi kích thước trong API được cung cấp cho các công cụ bạn có thể tìm thấy trong câu hỏi này.
zacr0

Câu trả lời:


92

Tôi sẽ bỏ phiếu cho sắc nét :

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

Nó nhanh, thường nhanh hơn 6 lần so với các liên kết nút dựa trên imagemagick nhanh nhất và chạy trong rất ít bộ nhớ, có lẽ ít hơn 10 lần . liên kết sắc nét trực tiếp đến thư viện hình ảnh libvips , không có tác động nào đến chương trình bên ngoài và bản thân thư viện nhanh hơn và hiệu quả hơn * magick ở tác vụ này. Nó hỗ trợ những thứ hữu ích như luồng, bộ đệm và đầu vào và đầu ra của hệ thống tệp, quản lý màu sắc, độ trong suốt, lời hứa, lớp phủ, WebP, SVG, v.v.

Kể từ sharp 0,20, npm sẽ tự động tải xuống các tệp nhị phân được biên dịch trước hoàn chỉnh trên hầu hết các nền tảng, vì vậy không cần đến node-gyp. Chỉ cần nhập:

npm install sharp

hoặc là:

yarn add sharp

Và bạn đi.


7
Kể từ phiên bản v0.12.0, sharpkhông còn bất kỳ phụ thuộc thời gian chạy bên ngoài nào cho người dùng Linux và Windows vì nó bao gồm phiên bản libvips được biên dịch trước. Bạn sẽ thấy các thao tác thay đổi kích thước nhanh hơn LWIP ~ 10 lần và chỉ sử dụng một phần nhỏ bộ nhớ.
Lovell Fuller

4
sắc nét thêm gif bản địa và hỗ trợ svg với phiên bản 0,15 sharp.dimens.io/en/stable/changelog
jcupitt

1
Đó là 100 tệp, nhưng tất cả chúng đều được quản lý tự động cho bạn bằng npm, bạn không cần phải suy nghĩ về điều đó.
jcupitt

4
@CoDEmanX Có lẽ hãy thử chạy npm install --global --production windows-build-toolstrước. Xem thêm github.com/Microsoft/nodejs-guidelines/blob/master/…
Lovell Fuller

1
Tôi đã xây dựng một tập lệnh nhỏ giúp bạn dễ dàng xem mọi thứ đang diễn ra như thế nào và nó sẽ trông như thế nào trong nội dung như thẻ boostrap và nền: cover để tối ưu hóa tốt nhất các thông số, có thể là của intrest github.com/lcherone/sharp-test
Lawrence Cherone

71

Gần đây tôi đã bắt đầu phát triển một mô-đun xử lý hình ảnh cho NodeJS mà không có bất kỳ phụ thuộc thời gian chạy nào ( đọc lý do ). Nó vẫn còn ở giai đoạn đầu, nhưng đã có thể sử dụng được.

Những gì bạn đang yêu cầu sẽ được thực hiện như sau:

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

Thông tin thêm tại mô-đun của repo Github .


7
Mô-đun của bạn thật tuyệt vời. Tuy nhiên, nó chiếm rất nhiều bộ nhớ. Tôi đã thử tạo writeFile một 1.8Mbhình ảnh và nó yêu cầu bộ nhớ 130Mb. Sau đó, tôi thực hiện một bài kiểm tra bằng cách thay đổi kích thước 4MB, 11000x6000hình ảnh thành một số hình thu nhỏ (640,560,480, ..., 160) và nó chiếm khoảng 1,7GB bộ nhớ. Đó có phải là một lỗi?
Lewis

2
Xin chào @Orion, cảm ơn vì phản hồi. Vui lòng truy cập repo Github và mở sự cố với một số chi tiết hơn (Hệ điều hành, phiên bản, mã để tái tạo điều này). Chúng tôi sẽ cố gắng giải quyết vấn đề này cùng nhau :)
EyalAr

@EyalAr Này Eyal, làm thế nào để thay đổi kích thước và giữ nguyên kích thước? (thay đổi kích thước kích thước tối đa có thể của chiều rộng, chiều cao) mà không kéo dài
Daniel Krom

10
Tôi sẽ đề nghị không sử dụng lwip vào năm 2017. Gói này dường như không còn được hỗ trợ nữa và nó có vấn đề cài đặt lớn trên Windows và bây giờ ngay cả trên nền tảng Unix.
zerefel

9
lwip không may là một dự án chết. sắc nét tuy nhiên dường như vẫn được duy trì tích cực.
laurent

16

Hãy xem lwip: https://github.com/EyalAr/lwip

rất đơn giản và dễ để sử dụng

npm install lwip

và sau đó trong mã nút của bạn,

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

});

Tôi đã thực hiện thành công điều này trong trình tải lên tệp của mình và nó hoạt động như một sự quyến rũ.


1
Đây là những gì tôi đang tìm kiếm, không phải cài đặt phụ thuộc bên ngoài quá mức cần thiết cho một vài chức năng liên quan đến thay đổi kích thước hình ảnh.
zacr0

3
Btw @EyalAr là tác giả của mô-đun nút này. Bình luận của anh ấy cũng được liệt kê bên dưới.
Arvind

Rất trực quan để cài đặt và làm việc. Tôi thực sự thích rằng bạn không bắt buộc phải triển khai bất kỳ thư viện nhị phân nào như ImageMagick.
ChrisRich

Điều đó hoàn toàn giống với câu trả lời này (chủ sở hữu lwip), nhưng muộn hơn: stackoverflow.com/a/24543924/1525495
Jorge Fuentes González

12

Có một thư viện thao tác hình ảnh tốt được viết hoàn toàn bằng JavaScript, không phụ thuộc vào bất kỳ thư viện nào khác, Jimp. https://github.com/oliver-moran/jimp

Ví dụ sử dụng:

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

Tốc độ này so với ImageMagik là bao nhiêu?
Christopher Grigg

2
sharp có một tập hợp các điểm chuẩn: sharp.dimens.io/en/stable/performance --- Trong bài kiểm tra đó, jimp chậm hơn IM 5x và chậm hơn 30 lần so với sharp. Tất nhiên, đủ nhanh là đủ nhanh và tốc độ không phải là yếu tố duy nhất cần xem xét.
jcupitt

Thời gian thực có thể không, nhưng Jimp thật tuyệt vời khi chỉ viết các tệp hình thu nhỏ nhiều kích thước (và truy xuất chúng dưới dạng tệp được lưu trong bộ nhớ cache sau đó).
coderofsalvation

jimp không hỗ trợ webp và sẽ không hỗ trợ trong tương lai gần nhất. Xem: github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov

8

sharp gần đây đã rất phổ biến, nhưng nó cũng giống như các ràng buộc * Magick.

Tuy nhiên, việc phải cài đặt ImageMagick / GraphicsMagick để thay đổi kích thước hình ảnh đơn giản có vẻ quá mức cần thiết đối với tôi

Thay đổi kích thước hình ảnh là bất cứ điều gì nhưng đơn giản. Định dạng JPEG đặc biệt phức tạp và có một số cách để chia tỷ lệ đồ họa với kết quả có chất lượng khác nhau, một số cách dễ dàng thực hiện. Thư viện xử lý hình ảnh tồn tại để thực hiện công việc này, vì vậy nếu không có lý do nào khác khiến bạn không thể cài đặt chúng, hãy tiếp tục.


13
Có lẽ tôi là một nhà phát triển lười biếng, nhưng ngay sau khi tôi nhìn thấy quá trình cài đặt ImageMagick và tự hỏi tôi sẽ chi bao nhiêu để cài đặt nó trên phiên bản Amazon AWS EC2 của mình, tôi đã ngay lập tức bắt đầu tìm kiếm các tùy chọn khác - đặc biệt là khi xem xét rằng tất cả những gì tôi cần là khả năng thay đổi kích thước hình ảnh cho hình thu nhỏ.
ChrisRich

7

Canvas nhanh hơn 2,3 lần so với ImageMagic.

Bạn có thể thử so sánh các mô-đun Node.js để thao tác hình ảnh - 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

Nếu bạn không cần hình ảnh lớn, bạn có thể thay đổi kích thước hình ảnh đó ở phía máy khách trước khi tải lên:

Đọc tệp trong JavaScript bằng API tệp

Thay đổi kích thước hình ảnh phía máy khách bằng javascript trước khi tải lên máy chủ

Nhiều người dùng có thể có một bức ảnh đẹp của mình từ điện thoại thông minh và nhiều người trong số họ có hơn 200kB. Lưu ý rằng dữ liệu do máy khách cung cấp không đáng tin cậy, do đó, kiểm tra phía máy chủ vẫn được áp dụng.


2
Bạn không bao giờ có thể tin tưởng khách hàng, người dùng chỉ cần biết điểm cuối tải lên để gửi bất cứ thứ gì họ muốn ở đó. Vì vậy, các xác thực như kích thước tệp vẫn được áp dụng. Tuy nhiên, thay đổi kích thước ở phía khách hàng là một ý tưởng hay.
Kev

1

Tôi đang sử dụng lwip (như arvind đề xuất trước đây) nhưng đã chuyển sang png-crop . Nó có vẻ hoạt động nhanh hơn một chút đối với tôi (Win 8.1 x64, Node v0.12.7). Mã trong repo trông cực kỳ nhẹ và hoạt động rất đơn giản để sử dụng.

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

Tất nhiên, nó sẽ chỉ làm các tệp png ...


0

Sharp hoạt động rất tốt và dễ sử dụng với các luồng, hoạt động như một sự quyến rũ, nhưng bạn cần phải biên dịch nó với phiên bản nút, đây là một nhược điểm của nó. Tôi đang sử dụng Sharp để xử lý hình ảnh, với hình ảnh từ bộ chứa AWS S3 và hoạt động hoàn hảo, nhưng tôi phải sử dụng một mô-đun khác. GM không làm việc cho tôi, nhưng Jimp đã làm việc rất tốt!

Bạn phải chú ý đến đường dẫn của bức tranh được viết, nó có thể gây ra một số lỗi nếu bạn bắt đầu đường dẫn bằng dấu "/".

Đây là cách tôi sử dụng Jimp trong 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() } }

            });

Ngoài ra, hãy để ý thứ tự thực hiện, đặt lệnh gọi lại để những việc khác không xảy ra khi bạn không muốn. Đã thử sử dụng "await" cho Jimp.read () nhưng nó không hoạt động tốt.


Từ sharp 0,20, nó sẽ tự động tải xuống tệp nhị phân được biên dịch trước cho phiên bản nút chính xác của bạn trên hầu hết các nền tảng, vì vậy không cần phải xây dựng bất kỳ thứ gì.
jcupitt

Thật không may, nó không làm việc cho tôi. Tôi cần sử dụng sharp trong hệ thống tệp chỉ đọc, với nhiều phiên bản node.js khác nhau và tôi phải tải xuống mô-đun sharp cho mỗi phiên bản node mà tôi đang sử dụng và việc này mất quá nhiều thời gian.
Alex Seceleanu

0

Bạn có thể làm điều này bằng cách sử dụng jimp (node_module)

Ghi địa phương:

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

Để tải lên s3 hoặc bất cứ nơi nào bạn muốn.

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

Tôi thích thư viện resize-img vì sự đơn giản của nó.

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

Đã triển khai thay đổi kích thước hình ảnh bằng API Google Drive v3 . Phương pháp này được khuyến nghị cho Google Apps Script để chèn hình ảnh vào Google Trang tính.

Thuật ngữ:

  1. Tải lên hình ảnh thư mục Google Drive.
  2. Nhận URL công khai hình ảnh thu nhỏ.
  3. Thay thế thông số 'thay đổi kích thước' trong URL bằng chiều rộng và / hoặc chiều cao cần thiết. (Kích thước hình thu nhỏ mặc định là 220px).
  4. Tải xuống hình thu nhỏ đã thay đổi kích thước từ Google Drive.

Xem ví dụ tại đây: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

Và hãy cẩn thận với hạn ngạch GDrive:

  • truy vấn mỗi ngày: 1000000000
  • truy vấn mỗi 100 giây cho mỗi người dùng: 1000
  • truy vấn mỗi 100 giây: 10000
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.