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


85

我正在Node.js(+ express 4)上开发一个Web应用程序,用户可以通过将其配置文件图像上传到服务器来对其进行设置。我们已经限制了文件的模仿类型和最大文件大小,因此用户上传的png或jpeg图片不能超过200KB。

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

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

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


你好 我有个问题 如何将图像大小减小到200KB以下?请解释一下方法。谢谢。
C.Petrescu'5

您好,如果您找不到以前发布过的任何相关问题,则可以将其作为新问题发布。为了给您一些启发,请尝试在针对此问题的工具提供的API中寻找压缩和调整大小的方法。
zacr0

Answers:


92

我会投票给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倍。直接链接到libvips图像库,没有外壳程序到外部程序,并且该库本身比* magick更快,更高效。它支持有用的功能,例如流,缓冲区和文件系统的输入和输出,颜色管理,透明度,承诺,覆盖,WebP,SVG等。

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

npm install sharp

要么:

yarn add sharp

然后离开。


7
从v0.12.0版本开始,sharpLinux和Windows用户不再具有任何外部运行时依赖项,因为它捆绑了libvips的预编译版本。您会发现调整大小的操作比LWIP快10倍左右,而占用的内存却很少。
Lovell Fuller 2015年

4
尖锐加入天然GIF和与版本0.15支持SVG sharp.dimens.io/en/stable/changelog
jcupitt

1
它有100个文件,但是npm会自动为您管理所有文件,您无需考虑。
jcupitt

4
@CoDEmanX也许先尝试运行npm install --global --production windows-build-tools。又见github.com/Microsoft/nodejs-guidelines/blob/master/...
洛弗尔富勒

1
我构建了一个小脚本,可以轻松查看正在执行的操作以及在boostrap卡和背景等内容中的外观:覆盖以最佳地优化参数,也许是有趣的github.com/lcherone/sharp-test
Lawrence Cherone

71

我最近开始为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 repo上有更多信息。


7
您的模块很棒。但是,这需要占用大量内存。我试着writeFile 一个1.8Mb图像,它需要的内存130MB。之后,我通过将4MB, 11000x6000图像调整为几个缩略图(640,560,480,...,160)进行测试,它大约需要1.7GB的内存。那是个错误吗?
刘易斯

2
您好@Orion,感谢您的反馈。请转到Github存储库,并打开包含更多详细信息(操作系统,版本,可重现此内容的代码)的问题。我们将尝试共同解决这个问题:)
EyalAr 2014年

@EyalAr嘿,Eyal,如何调整大小和保持外观?(调整为最大可能的宽度,高度大小)而无需拉伸
Daniel Krom

10
我建议不要在2017年使用lwip。该软件包似乎不再受支持,并且在Windows甚至现在在Unix平台上都存在大量安装问题。
zerefel

9
不幸的是,lwip是一个死项目。尖锐,但似乎仍在积极维护。
劳伦特(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 2014年

3
Btw @EyalAr是此节点模块的作者。他的评论也在下面列出。
2014年

安装和使用非常直观。我真的很喜欢您不需要实现任何像ImageMagick这样的二进制库。
ChrisRich

这与这个答案(lwip所有者)完全相同,但是后来:stackoverflow.com/a/24543924/1525495
Jorge FuentesGonzález'19

12

有一个很好的图像处理库,完全用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相比,速度有多快?
Christopher Grigg

2
夏普有一套基准:sharp.dimens.io/en/stable/performance ---在该测试中,jimp比IM慢5倍,比Sharp慢30倍。当然,足够快就是足够快,并且速度不是唯一要考虑的因素。
jcupitt

实时可能不是,但是Jimp很棒,它只写了多个尺寸的缩略图文件(然后将它们作为缓存文件检索)。
救赎的编码者,2017年

jimp不支持webp,并且在不久的将来将不支持。参见:github.com/oliver-moran/jimp/issues/144
Viacheslav Dobromyslov

8

Sharp最近受到了欢迎,但是它与* Magick绑定相同。

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

调整图像大小绝非易事。JPEG格式特别复杂,并且有多种方法可以缩放图形以得到质量变化的结果,其中很少有易于实现的方法。图像处理库可以完成这项工作,因此,如果没有其他原因无法安装它们,那就去做吧。


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


3

如果不需要大图像,可以在客户端上调整大小,然后再上传:

使用File API以JavaScript读取文件

在上载到服务器之前,用javascript调整客户端图像的大小

许多用户可能通过智能手机对自己有很好的了解,其中许多用户的容量超过200kB。请注意,客户端提供的数据将不受信任,因此服务器端检查仍然适用。


2
您永远无法信任客户端,用户只需要知道上传端点即可将任何他想要的东西发送到那里。因此,诸如文件大小之类的验证仍然适用。但是,在客户端调整大小是一个好主意。
凯夫2015年

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可以很好地工作,并且易于使用流,就像魅力一样工作,但是您需要使用节点版本进行编译,这是它的缺点。我使用Sharp进行图像处理,并使用了AWS S3存储桶中的图像,并且运行良好,但是我不得不使用另一个模块。通用汽车没有为我工作,但吉普却表现出色!

您必须注意所写图片的路径,如果以“ /”开头的路径可能会给您带来一些错误。

这就是我在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()使用“等待”,但效果不佳。


从0.20开始,它将在大多数平台上自动为您的确切节点版本下载一个预编译的二进制文件,因此无需构建任何东西。
jcupitt

不幸的是,它对我没有用。我需要在具有各种node.js版本的只读文件系统中使用Sharp,并且我必须为所使用的每个节点版本下载Sharp模块,这花费了太多时间。
Alex Seceleanu

0

您可以使用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);
          });

0

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

0

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

算法:

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

在此处查看示例: https //github.com/dobromyslov/google-drive-utils/blob/511c44c2c48862b47c60038423b7f71bf1d28f49/src/index.ts#L150

并提防GDrive配额:

  • 每天查询量:1000000000
  • 每用户每100秒的查询数:1000
  • 每100秒的查询数:10000
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.