Node.js: 不使用ImageMagick进行图像调整大小

99

我正在使用Node.js (+ express 4)开发一个Web应用程序,用户可以通过将其上传到服务器来设置其个人资料图像。我们已经限制了文件MIME类型和最大文件大小,因此用户无法上传超过200KB的PNG或JPEG图像。

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

然而,为了进行简单的图像调整大小而安装ImageMagick/GraphicsMagick似乎太过于复杂了,那么除了这个之外,还有没有其他适用于Node.js的解决方案呢?

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


嗨,我有一个问题。如何将图像大小减小到200KB以下?请解释一下方法。谢谢。 - C.Petrescu
你好,如果你没有找到任何相关的问题,请将该问题发布为一个新问题。为了给你一些提示,尝试在此问题中提供的工具API中查找压缩和调整大小方法。 - zacr0
12个回答

104

我会投票给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
  });

它非常快,通常比基于imagemagick的最快的节点绑定快6倍,并且在非常小的内存中运行,可能少10倍。Sharp直接链接到libvips图像库,无需外部程序支持,该库本身在此任务上比*magick更快、更高效。它支持流、缓冲区和文件系统输入输出、颜色管理、透明度、承诺、覆盖、WebP、SVG等有用的功能。

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

npm install sharp
或者:
yarn add sharp

然后你就可以出发了。


7
自v0.12.0版本起,对于Linux和Windows用户,sharp不再有任何外部运行时依赖项,因为它捆绑了预编译版本的libvips。您会发现调整大小操作比LWIP快约10倍,且内存使用仅为其一小部分。 - Lovell Fuller
4
Sharp在0.15版本中加入了本地GIF和SVG支持。http://sharp.dimens.io/en/stable/changelog - jcupitt
4
@CoDEmanX 或许先尝试运行 npm install --global --production windows-build-tools 命令。另请参考 https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules。 - Lovell Fuller
1
当我尝试在Linux上安装它时,出现以下情况: 离开目录 /home/myhomeDir/node_modules/sharp/build' gyp ERR! build error gyp ERR! stack Error: make` 失败,退出代码为:2。这是什么原因? - CodeMind
1
我编写了一个小脚本,可以轻松地“查看”事物正在做什么以及在像Bootstrap卡片和背景:覆盖之类的内容中如何显示,以最佳优化参数,也许这很有趣 https://github.com/lcherone/sharp-test - Lawrence Cherone
显示剩余14条评论

72

我最近开始开发一个基于NodeJS的图像处理模块,没有任何运行时依赖(阅读原因)。它目前还处于早期阶段,但已经可以使用。

您所要求的操作应按以下方式完成:

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存储库


7
你的模块很棒。但是它占用了太多的内存。我尝试使用writeFile写入一个大小为1.8Mb的图片,它需要占用130Mb的内存。之后,我尝试对一个4MB,11000x6000的图片进行缩略图处理(640、560、480……160),它大约需要占用1.7GB的内存。这是一个bug吗? - Lewis
2
嗨@Orion,感谢您的反馈。请前往Github存储库并打开一个问题,提供更多详细信息(操作系统,版本,可重现此问题的代码)。我们将一起努力解决这个问题 :) - EyalAr
@EyalAr 嘿,Eyal,请问如何调整大小并保持宽高比?(调整到最大可能的宽度和高度),但又不会拉伸。 - Daniel Krom
11
我建议在2017年不要使用lwip。该软件包似乎已不再受支持,并且在Windows上安装存在巨大问题,现在甚至在Unix平台上也是如此。 - zerefel
9
很遗憾,lwip项目已经停止开发了。然而,sharp 似乎仍在积极维护。 - laurent

16

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

});

我已经成功地在我的文件上传器中实现了这个功能,它的效果非常好。


1
这正是我所期望的,不需要安装过度臃肿、重量级的外部依赖项来处理与图像调整大小相关的几个函数。 - zacr0
3
顺便说一下,@EyalAr是这个节点模块的作者。他的评论也在下面列出。 - Arvind
非常直观易懂的安装和使用。我真的很喜欢你不需要实现任何二进制库,比如ImageMagick。 - ChrisRich
这与此答案(lwip所有者)完全相同,但稍晚:https://dev59.com/1mAg5IYBdhLWcg3wDHU4#24543924 - Jorge Fuentes González

15

有一个非常好的图像处理库,名为Jimp,它完全由JavaScript编写,没有依赖于任何其他库。 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相比,这个有多快? - Christopher Grigg
2
Sharp有一组基准测试:http://sharp.dimens.io/en/stable/performance --- 在这个测试中,Jimp比IM慢5倍,比Sharp慢30倍。当然,足够快就是足够快,速度并不是唯一需要考虑的因素。 - jcupitt
实时可能不是很好,但 Jimp 对于编写多尺寸的缩略图文件(并在以后检索它们作为缓存文件)非常棒。 - coderofsalvation
jimp 目前不支持 webp 格式,并且在最近的未来也不会支持。请参阅:https://github.com/oliver-moran/jimp/issues/144 - Viacheslav Dobromyslov

10
根据 images-manipulation-performance,Canvas 比 ImageMagick 更快,速度快 2.3 倍。
示例结果:
每秒处理图片数 最小空闲内存
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

9

Sharp最近变得越来越受欢迎,但它的思想与Magick绑定是相同的。

然而,为了做一个简单的图像大小调整而安装ImageMagick/GraphicsMagick似乎太过头了。

图片大小调整并不简单。JPEG格式特别复杂,并且有多种缩放图形的方法,其结果质量各异,其中很少有易于实现的方法。图像处理库存在于执行此任务,因此如果没有其他原因不能安装它们,请尽管安装。


13
也许我是一个懒惰的开发者,但一看到ImageMagick的安装过程并思考在我的亚马逊AWS EC2实例上安装它将花费多少时间,我就立刻开始寻找其他选择——特别是考虑到我所需要的只是调整图像大小以制作缩略图的功能。 - ChrisRich

4

2
你永远不能相信客户端,用户只需要知道上传端点就可以发送任何他想要的东西。因此,像文件大小这样的验证仍然适用。但是,在客户端进行调整大小是一个好主意。 - Kev

1
我曾使用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文件...

0

Sharp的使用非常顺畅,且与流式处理非常易用,完美无缺。但是需要用node版本编译,这是个缺点。 我曾经在处理一个AWS S3存储桶中的图像时使用了Sharp,结果完美完成了任务,但是还得使用另外一个模块。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() } }

            });

同时要注意执行顺序,放置回调函数以防止在不需要时发生其他事情。尝试使用 "await" 来读取 Jimp,但效果不佳。


从sharp 0.20开始,在大多数平台上,它会自动下载与您的节点版本完全匹配的预编译二进制文件,因此无需构建任何内容。 - jcupitt
不幸的是,它对我不起作用。我需要在只读文件系统中使用sharp,在不同的node.js版本中运行,并且我必须为我使用的每个节点版本下载sharp模块,这需要太多时间。 - Alex Seceleanu

0

使用Google Drive API v3实现图像调整大小。此方法建议用于Google Apps Script将图像插入到Google Sheets中。

算法:

  1. 上传图像到Google Drive文件夹。
  2. 获取图像缩略图公共URL。
  3. 在URL中替换'resize'参数为必要的宽度和/或高度。(默认缩略图大小为220px)。
  4. 从Google Drive下载调整大小的缩略图。

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

注意GDrive的配额限制:

  • 每天查询次数:1000000000
  • 每个用户每100秒查询次数:1000
  • 每100秒查询次数:10000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接