Cách nén ảnh trong Node.js bằng Sharp

Nén ảnh cho web hoặc trong ứng dụng có thể cải thiện tối đa hiệu suất. Sharp sẽ giúp bạn nén ảnh trong Node.js thật dễ dàng.

Lập trình Node.js

Những ảnh lớn không cần thiết có thể làm chậm thời gian phản hồi, hao phí băng thông và mang tới trải nghiệm chậm chạp cho người dùng, nhất là với những ai dùng gói dung lượng mạng hạn chế. Điều này dẫn tới tỷ lệ thoát hay ít chuyển trang hơn trên web.

Nén ảnh trước khi upload chúng có thể giảm thiểu những vấn đề này và cung cấp trải nghiệm người dùng tốt hơn. Mô đun Sharp làm quá trình này diễn ra nhanh chóng và dễ dàng.

Thiết lập môi trường phát triển

Để minh họa quá trình nén ảnh, bắt đầu bằng cách thiết lập một dịch vụ upload ảnh bằng multer. Bạn có thể tăng tốc quá trình này bằng cách sao chép mẫu mong muốn từ repository GitHub.

Sau khi nhân bản repository GitHub, chạy lệnh này để cài các phần phụ thuộc ảnh dịch vụ upload ảnh:

npm install

Tiếp theo, cài đặt Sharp bằng cách chạy lệnh này:

npm install sharp

Mô đun Sharp là một thư viện Node.js hiệu suất cao cho việc xử lý và thao tác hình ảnh. Bạn có thể dùng Sharp để chỉnh lại kích thước, cắt, xoay và thực hiện các hoạt động khác trên ảnh hiệu quả. Sharp cũng hỗ trợ tuyệt vời cho việc nén ảnh.

Kỹ thuật nén ảnh cho các định dạng khác nhau

JPG/JPEG

JPEG là một tiêu chuẩn nén hình ảnh được phát triển bởi Joint Photographic Experts Group để nén ảnh chụp chân thực bằng các tông màu và chuyển màu liên tục. Nó dùng thuật ngữ nén lossy, tạo file nhỏ hơn bằng cách loại bỏ một số dữ liệu ảnh.

Để nén ảnh JPEG bằng Sharp, nhập mô đun Sharp và chuyển filePath hoặc một bộ đệm của ảnh làm đối số. Tiếp theo, gọi phương thức .jpeg trên phiên bản Sharp. Sau đó, chuyển một đối tượng cấu hình với thuộc tính quality mà lấy số nằm giữa 0 và 100 làm giá trị. Trong đó, 0 trả về ảnh nén nhỏ nhất với chất lượng thấp nhất, còn 100 cho ảnh nén cao nhất với chất lượng tốt nhất.

Bạn có thể đặt giá trị theo nhu cầu. Nếu muốn có kết quả nén ảnh tốt nhất, giữ giá trị nằm giữa 50-80 để đạt được sự cân bằng giữa kích thước và chất lượng.

Hoàn thiện công việc bằng cách lưu ảnh đã nén vào hệ thống file bằng phương thức .toFile. Chuyển đường dẫn file bạn muốn ghi làm đối số.

Ví dụ:

await sharp(req.file.path)
        .jpeg({ quality: 60 })
        .toFile(`./images/compressed-${req.file.filename}`)
        .then(() => {
          console.log(`Compressed ${req.file.filename} successfully`);
        });

Giá trị mặc định cho quality80.

PNG

PNG là một định dạng file ảnh cho nén lossless và hỗ trợ background trong suốt.

Nén ảnh PNG bằng Sharp tương tự như nén một ảnh JPEG bằng Sharp. Tuy nhiên, có hai thay đổi bạn cần thực hiện khi ảnh ở định dạng PNG.

  1. Sharp xử lý ảnh PNG bằng phương thức .png thay cho .jpeg.
  2. Phương thức .png dùng compressionLevel, là số nằm giữa 0 và 9 thay cho quality trong đối tượng cấu hình. 0 cho giá trị nén nhanh và lớn nhất có thể, còn 9 cho giá trị nén chậm và nhỏ nhất.

Ví dụ:

await sharp(req.file.path)
        .png({
          compressionLevel: 5,
        })
        .toFile(`./images/compressed-${req.file.filename}`)
        .then(() => {
          console.log(`Compressed ${req.file.filename} successfully`);
        });

Giá trị mặc định cho compressionLevel6.

Các định dạng khác

Sharp hỗ trợ nén ở các định dạng ảnh khác nhau, bao gồm WebP, TIFF, AVIF, HEIF.

Nén ảnh bằng Sharp

Nếu đã nhân bản repository GitHub, mở file app.js và thêm các import sau.

const sharp = require("sharp");
const { exec } = require("child_process");

Excel là một hàm được cung cấp bởi mô đun child_process, cho phép bạn triển khai các lệnh shell hoặc quá trình bên ngoài từ ứng dụng Node.js.

Bạn có thể dùng hàm này để chạy lệnh so sánh kích thước file trước và sau khi nén.

Tiếp theo, thay thế trình xử lý POST ‘/single’ bằng khối code bên dưới:

app.post("/upload-and-compress", upload.single("image"), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(404).send("Please upload a valid image");
    }

    const compressedFileName = req.file.filename.split(".")[0];
    const compressedImageFilePath = `./images/${compressedFileName}-compressed.png`;

    await sharp(req.file.path)
      .jpeg({ quality: 50 })
      .toFile(compressedImageFilePath)
      .then(() => {
        let sizeBeforeCompression, sizeAfterCompression;
        const sizeBeforeCompressionCommand = `du -h ${req.file.path}`;
        const sizeAfterCompressionCommand = `du -h ${compressedImageFilePath}`;

        exec(sizeBeforeCompressionCommand, (err, stdout, stderr) => {
          sizeBeforeCompression = stdout.split("\\t")[0];

          exec(sizeAfterCompressionCommand, (err, stdout, stderr) => {
            sizeAfterCompression = stdout.split("\\t")[0];

            res.send({
              message: "Image uploaded and compressed successfully",
              sizeBeforeCompression,
              sizeAfterCompression,
            });
          });
        });
      });
  } catch (error) {
    console.log(error);
  }
});

Khối code trên triển khai kỹ thuật nén ảnh JPEG và so sánh kích thước trước và sau khi dùng lệnh du.

Lệnh du là một tiện ích Unix, viết tắt của “disk usage”. Nó ước tính không gian file và phân tích mức sử dụng ổ đĩa trong một thư mục hoặc một nhóm thư mục. Khi bạn chạy lệnh du bằng flag -h, nó hiện dung lượng file mà từng thư mục phụ sử dụng cùng nội dung ở dạng con người có thể đọc.

Khởi động dịch vụ upload bằng cách chạy lệnh này:

node app.js

Tiếp theo, kiểm tra ứng dụng bằng cách gửi ảnh JPG sang route localhost: <PORT>/upload-and-compress bằng app client Postman hoặc bất kỳ công cụ kiểm thử API khác.

Bạn sẽ thấy một phản hồi tương tự như sau:

{
  "message": "Image uploaded and compressed successfully",
  "sizeBeforeCompression": "13M",
  "sizeAfterCompression": "3.1M"
}

Trên đây là cách nén ảnh trong Node.js bằng Sharp. Hi vọng bài viết hữu ích với các bạn.

Thứ Sáu, 27/10/2023 16:58
51 👨 163
0 Bình luận
Sắp xếp theo