【问题标题】:Need help in image handling in node.js在 node.js 中的图像处理方面需要帮助
【发布时间】:2021-04-13 12:24:52
【问题描述】:

例如,有什么方法可以在需要时调整图像大小。 想做的是这样 /image.jpg 给我原始图像,但 image_200x200.jpg 给我调整大小的图像,宽度和高度为 200px。 我想让它在渲染时调整图像大小,这样我就不必存储调整大小的图像。提前致谢

【问题讨论】:

    标签: javascript node.js image express sharp


    【解决方案1】:

    有什么办法吗?

    是的,有。但是您必须注意,这样做,每次请求时都会调整图像的大小。如果您预计网站上的流量会很大,那么除非您将这些调整大小的图像实际存储在某种缓存中,否则这不是一个可持续的解决方案。

    即使您确实缓存了它们,请注意,如果没有任何 URL 签名(确保 URL 是由您的服务器发出的),恶意用户可能希望向您的服务器发送垃圾邮件,其中他们每次都使用随机大小的请求,强制在您的服务器上进行调整大小操作并使其不堪重负。

    既然这已经解决了,让我们尝试寻找解决方案。

    我们如何在 Express 中路由请求?

    Express 提供了一种serve static files 的方法,我们可以在不需要调整大小时保留它。如果在此位置未找到文件,则将检查下一条路线。因此,在下一个中,我们将尝试检查是否需要调整大小,然后再尝试匹配其他路由。我们可以通过使用匹配特定模式的正则表达式来定位那些。

    此示例将匹配以 _{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
    

    中间件

    middleware 是 Express 在请求路由时调用的函数。在这种情况下,我们可以这样声明:

    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 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 函数。让我们用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;
    }
    

    【讨论】:

    • 非常感谢您的帮助。非常感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 2019-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    相关资源
    最近更新 更多