簡體   English   中英

在 node.js 中需要圖像處理方面的幫助

[英]Need help in image handling in node.js

例如,有什么方法可以在需要時調整圖像大小。 想要使 /image.jpg 給我原始圖像,但 image_200x200.jpg 給我調整大小的圖像,寬度和高度為 200px。 我想讓它在渲染時調整圖像大小,這樣我就不必存儲調整大小的圖像。 提前致謝

有什么辦法嗎?

就在這里。 但是您必須知道,這樣做,每次請求時都會調整圖像的大小。 如果您希望網站上的流量很大,那么這不是一個可持續的解決方案,除非您將這些調整大小的圖像實際存儲在某種緩存中。

即使您確實緩存了它們,請注意,如果沒有任何 URL 簽名(確保 URL 是由您的服務器發出的),惡意用戶可能希望通過每次使用隨機大小的請求向您的服務器發送垃圾郵件,以強制調整服務器上的操作並壓倒它。

既然這已經解決了,讓我們嘗試找到解決方案。

我們如何在 Express 中路由請求?

Express 提供了一種提供 static 文件的方法,我們可以在不需要調整大小時保留這些文件。 如果在此位置找不到文件,則將檢查下一個路由。 因此,在下一個中,我們將嘗試檢查是否需要調整大小,然后再嘗試匹配其他路由。 我們可以通過使用匹配特定模式的正則表達式來定位那些。

此示例將匹配以_{n}x{n}和“jpeg”、“jpg”或“png”擴展名結尾的 URL:

app.use(express.static(Path.join(__dirname, 'public'))); // If a file is found
app.use('/(*_\\d+x\\d+.(jpe?g|png))', resizingMiddleware); // If resizing is needed
// ... Other routes

中間件

中間件是在請求路由時由 Express 調用的 function。 在這種情況下,我們可以這樣聲明:

function resizingMiddleware(req, res, next)  {
  const data = parseResizingURI(req.baseUrl); // Extract data from the URI

  if (!data) { return next(); } // Could not parse the URI

  // Get full file path in public directory
  const path = Path.join(__dirname, 'public', data.path);

  resizeImage(path, data.width, data.height)
    .then(buffer => {
      // Success. Send the image
      res.set('Content-type', mime.lookup(path)); // using 'mime-types' package
      res.send(buffer);
    })
    .catch(next); // File not found or resizing failed
}

從 URI 中提取數據

正如您在上面看到的,我使用parseResizingURI來獲取原始文件名以及請求的尺寸。 讓我們寫這個 function:

function limitNumberToRange(num, min, max) {
  return Math.min(Math.max(num, min), max);
}

function parseResizingURI(uri) {
  // Attempt to extract some variables using Regex
  const matches = uri.match(
    /(?<path>.*\/)(?<name>[^\/]+)_(?<width>\d+)x(?<height>\d+)(?<extension>\.[a-z\d]+)$/i
  );

  if (matches) {
    const { path, name, width, height, extension } = matches.groups;
    return {
      path: path + name + extension, // Original file path
      width: limitNumberToRange(+width, 16, 2000),   // Ensure the size is in a range
      height: limitNumberToRange(+height, 16, 2000), // so people don't try 999999999
      extension: extension
    };
  }
  return false;
}

調整圖像大小

在中間件中,你可能還會看到一個resizeImage function。 讓我們用sharp來寫它:

function resizeImage(path, width, height) {
  return sharp(path).resize({
    width,
    height,
    // Preserve aspect ratio, while ensuring dimensions are <= to those specified
    fit: sharp.fit.inside,
  }).toBuffer();
}

把它們放在一起

最后,我們得到以下代碼:

// Don't forget to install all used packages:
// $ npm install --save mime-types express sharp

const Path = require('path');
const mime = require('mime-types')
const sharp = require('sharp');
const express = require('express');
const app = express();

// Existing files are sent through as-is
app.use(express.static(Path.join(__dirname, 'public')));
// Requests for resizing
app.use('/(*_\\d+x\\d+.(jpe?g|png))', resizingMiddleware);
// Other routes...
app.get('/', (req, res) => { res.send('Hello World!'); });

app.listen(3000);

function resizingMiddleware(req, res, next)  {
  const data = parseResizingURI(req.baseUrl); // Extract data from the URI

  if (!data) { return next(); } // Could not parse the URI

  // Get full file path in public directory
  const path = Path.join(__dirname, 'public', data.path);

  resizeImage(path, data.width, data.height)
    .then(buffer => {
      // Success. Send the image
      res.set('Content-type', mime.lookup(path)); // using 'mime-types' package
      res.send(buffer);
    })
    .catch(next); // File not found or resizing failed
}

function resizeImage(path, width, height) {
  return sharp(path).resize({
    width,
    height,
    // Preserve aspect ratio, while ensuring dimensions are <= to those specified
    fit: sharp.fit.inside,
  }).toBuffer();
}

function limitNumberToRange(num, min, max) {
  return Math.min(Math.max(num, min), max);
}

function parseResizingURI(uri) {
  // Attempt to extract some variables using Regex
  const matches = uri.match(
    /(?<path>.*\/)(?<name>[^\/]+)_(?<width>\d+)x(?<height>\d+)(?<extension>\.[a-z\d]+)$/i
  );

  if (matches) {
    const { path, name, width, height, extension } = matches.groups;
    return {
      path: path + name + extension, // Original file path
      width: limitNumberToRange(+width, 16, 2000),   // Ensure the size is in a range
      height: limitNumberToRange(+height, 16, 2000), // so people don't try 999999999
      extension: extension
    };
  }
  return false;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM