【问题标题】:Node.js: image resizing without ImageMagickNode.js:不使用 ImageMagick 调整图像大小
【发布时间】:2014-07-24 10:44:00
【问题描述】:

我正在 Node.js (+ express 4) 上开发一个网络应用程序,用户可以通过将其上传到服务器来设置他们的个人资料图片。我们已经限制了文件 mimetype 和最大文件大小,因此用户不能上传超过 200KB 的 png 或 jpeg 图像。

问题是我们想将上传的图像分辨率(服务器端)调整为 200x200,以改善页面加载并节省磁盘空间。经过一番研究,所有答案都指向使用基于 ImageMagick 或 GraphicsMagick 的任何模块。

但是,必须安装 ImageMagick/GraphicsMagick 来进行简单的图像调整对我来说似乎太过分了,那么,除了 Node.js 之外,还有其他解决方案吗?

编辑:我已将接受的解决方案更改为 sharp,因为不再维护以前的解决方案 (lwip)。感谢您的所有反馈!

【问题讨论】:

  • 嗨。我有个问题。如何将图像大小减小到 200KB 以下?请解释一下方法。谢谢。
  • 您好,如果您没有找到以前发布的任何相关问题,那么这个问题值得作为新问题发布。为了给您一些启发,请尝试在为您在此问题中找到的工具提供的 API 中寻找压缩和调整大小的方法。

标签: image node.js image-resizing


【解决方案1】:

我会投票给sharp:

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

它很快,typically 6x faster than the fastest imagemagick-based node bindings,并且在非常少的内存中运行,perhaps 10x less。直接指向libvips 图像库的清晰链接,无需对外部程序进行脱壳,而且库本身在此任务上比 *magick 更快、更高效。它支持有用的东西,如流、缓冲区和文件系统输入和输出、颜色管理、透明度、承诺、覆盖、WebP、SVG 等等。

从Sharp 0.20 开始,npm 将在大多数平台上自动下载完整的预编译二进制文件,因此不需要 node-gyp。只需输入:

npm install sharp

或:

yarn add sharp

你走了。

【讨论】:

  • 从 v0.12.0 开始,sharp 不再为 Linux 和 Windows 用户提供任何外部运行时依赖项,因为它捆绑了预编译版本的 libvips。您会发现调整大小操作比 LWIP 快约 10 倍,而且内存使用量只是其一小部分。
  • 在 0.15 版中锐利地添加了原生 gif 和 svg 支持 sharp.dimens.io/en/stable/changelog
  • 100多个文件,但都是npm自动为你管理的,你不用多想。
  • @CoDEmanX 也许先尝试运行npm install --global --production windows-build-tools。另见github.com/Microsoft/nodejs-guidelines/blob/master/…
  • 当我尝试在 Linux 上安装它时,我得到离开目录 /home/myhomeDir/node_modules/sharp/build' gyp ERR! build error gyp ERR! stack Error: make` 失败,退出代码:2。这是什么原因?
【解决方案2】:

我最近开始为 NodeJS 开发一个图像处理模块,没有任何运行时依赖 (read why)。它仍处于早期阶段,但已经可用。

您所要求的将按如下方式完成:

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

更多信息请访问模块的Github repo。

【讨论】:

  • 你的模块很棒。但是,它需要太多的内存。我试过writeFile 一个1.8Mb 图像,它需要130Mb 的内存。之后,我通过将4MB, 11000x6000 图像调整为多个缩略图(640,560,480,...,160)来进行测试,它大约需要 1.7GB 内存。这是一个错误吗?
  • 嗨@Orion,感谢您的反馈。请前往 Github 存储库并打开一个包含更多详细信息(操作系统、版本、重现此代码的代码)的问题。我们会一起努力解决这个问题:)
  • @EyalAr 嘿 Eyal,如何调整大小并保持纵横比? (调整到最大可能的宽度,高度)而不拉伸
  • 我建议不要在 2017 年使用 lwip。该软件包似乎不再受支持,并且在 Windows 甚至 Unix 平台上都存在大量安装问题。
  • 不幸的是,lwip 是一个死项目。 sharp 但似乎仍在积极维护中。
【解决方案3】:

看看lwip:https://github.com/EyalAr/lwip

非常简单易用

npm install lwip

然后在你的节点代码中,

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

});

我已经在我的file uploader 中成功实现了这一点,它就像一个魅力。

【讨论】:

  • 这是我一直在寻找的,不必为与图像调整大小相关的几个函数安装过度、繁重的外部依赖项。
  • 顺便说一句 @EyalAr 是这个节点模块的作者。他的评论也列在下面。
  • 安装和使用非常直观。我真的很喜欢你不需要实现像 ImageMagick 这样的任何二进制库。
  • 这和这个答案完全一样(lwip所有者),但后来:stackoverflow.com/a/24543924/1525495
【解决方案4】:

有一个很好的图像处理库,完全用 JavaScript 编写,不依赖于任何其他库,Jimp。 https://github.com/oliver-moran/jimp

示例用法:

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

【讨论】:

  • 与 ImageMagik 相比有多快?
  • sharp 有一组基准测试:sharp.dimens.io/en/stable/performance --- 在该测试中,jimp 比 IM 慢 5 倍,比sharp 慢 30 倍。当然,足够快就是足够快,速度并不是唯一需要考虑的因素。
  • 实时可能不是,但 Jimp 非常适合编写多尺寸缩略图文件(然后将它们作为缓存文件检索)。
  • jimp 不支持 webp,近期也不支持。见:github.com/oliver-moran/jimp/issues/144
【解决方案5】:

sharp 最近很受欢迎,但它与 *Magick 绑定的想法相同。

但是,必须安装 ImageMagick/GraphicsMagick 来调整图像大小对我来说似乎太过分了

图像大小调整绝非简单。 JPEG 格式特别复杂,有多种方法可以缩放具有不同质量结果的图形,但其中很少有容易实现的。存在图像处理库来完成这项工作,所以如果没有其他原因无法安装它们,那就去吧。

【讨论】:

  • 也许我是一个懒惰的开发人员,但是当我看到 ImageMagick 的安装过程并想知道我会花多少钱在我的 Amazon AWS EC2 实例上安装它时,我立即开始寻找其他选项- 尤其是考虑到我所需要的只是为缩略图调整图像大小的能力。
【解决方案6】:

根据images-manipulation-performance,Canvas 比 ImageMagick 快 2.3 倍。

示例结果:

Library Imges per Second Minimum Free Memory
sharp.js 9.501 929Mb
canvas.js 8.246 578Mb
gm.js 4.433 791Mb
gm-imagemagic.js 3.654 804Mb
lwip.js 1.203 54Mb
jimp.js 0.445 82Mb

【讨论】:

    【解决方案7】:

    如果你不需要大图,可以在上传前在客户端调整大小:

    Reading files in JavaScript using the File APIs

    Image resizing client-side with javascript before upload to the server

    许多用户可能会从智能手机上看到自己的好照片,其中许多用户超过 200kB。请注意,客户端提供的数据不可信,因此仍然适用服务器端检查。

    【讨论】:

    • 你永远不能信任客户端,用户只需要知道上传端点就可以在那里发送他想要的任何东西。因此,文件大小等验证仍然适用。但是,在客户端调整大小是个好主意。
    【解决方案8】:

    我使用的是 lwip(如 arvind 之前建议的那样),但切换到 png-crop。它对我来说似乎工作得更快一些(Win 8.1 x64,Node v0.12.7)。代码库中的代码看起来非常轻量级,并且在操作上使用起来很简单。

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

    当然,它只会做 png 文件...

    【讨论】:

      【解决方案9】:

      Sharp 工作得很好,很容易与流一起使用,就像一个魅力,但你需要用 node 版本编译它,这是它的缺点。 我使用 Sharp 进行图像处理,使用来自 AWS S3 存储桶的图像并且运行良好,但我不得不使用另一个模块。 GM 没有为我工作,但 Jimp 工作得很好!

      你要注意所写图片的路径,如果路径以“/”开头可能会给你一些错误。

      这就是我在 nodeJS 中使用 Jimp 的方式:

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

      还要注意执行的顺序,设置一个回调,这样当你不想的时候其他事情就不会发生。尝试对 Jimp.read() 使用“等待”,但效果不佳。

      【讨论】:

      • 从 sharp 0.20 开始,它会在大多数平台上为您的确切节点版本自动下载预编译的二进制文件,因此无需构建任何东西。
      • 不幸的是,它对我不起作用。我需要在只读文件系统中使用sharp,有各种node.js版本,我必须为我使用的每个节点版本下载sharp模块,这花费了太多时间。
      【解决方案10】:

      您可以使用 jimp (node_module) 来做到这一点

      本地写入:

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

      上传到 s3 或任何你喜欢的地方。

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

      【讨论】:

        【解决方案11】:

        我喜欢 resize-img 库的简单性。

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

        【讨论】:

          【解决方案12】:

          使用Google Drive API v3 实现图像大小调整。建议 Google Apps 脚本使用此方法将图像插入 Google 表格。

          算法:

          1. Upload 图片到 Google Drive 文件夹。
          2. Get 图片缩略图公共 URL。
          3. 将 URL 中的“resize”参数替换为必要的宽度和/或高度。 (默认缩略图大小为 220 像素)。
          4. 从 Google 云端硬盘下载调整大小的缩略图。

          请参见此处的示例: https://github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

          注意 GDrive 配额:

          • 每天查询:1000000000
          • 每位用户每 100 秒的查询数:1000
          • 每 100 秒查询数:10000

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多