使用NodeJS的图像处理库”sharp”来拼接图像

首先

最近我遇到了一个问题,想要像NodeJS中的ImageMagick的append那样简单地将大小不同的图片横向连接起来。但是由于太简单了,很难找到相关的文章,所以我想写下备忘录作为记录。

要做的事情

    sharpで画像情報取得、連結

版本

NodeJS: v12.14.1
銳利: v0.23.4

产物

出现的图像

output.png

程式碼

yarn init -y
yarn add sharp

这里是源代码的链接:
https://github.com/engabesi/appendImages

首先,我会粘贴整篇文章。

const sharp = require("sharp");

(async () => {
  const imagePaths = ["images/1.jpg", "images/2.jpg", "images/3.jpg"];
  const imageAttrs = [];

  // 連結する画像の情報取得
  const promises = [];
  const imagePromise = path =>
    new Promise(async resolve => {
      const image = await sharp(path);
      let width = 0,
        height = 0;
      await image
        .metadata()
        .then(meta => ([width, height] = [meta.width, meta.height]));
      const buf = await image.toBuffer();
      resolve({ width, height, buf });
    });
  imagePaths.forEach(path => promises.push(imagePromise(path)));
  await Promise.all(promises).then(values => {
    values.forEach(value => imageAttrs.push(value));
  });

  // outputする画像の設定
  const outputImgWidth = imageAttrs.reduce((acc, cur) => acc + cur.width, 0);
  const outputImgHeight = Math.max(...imageAttrs.map(v => v.height));
  let totalLeft = 0;
  const compositeParams = imageAttrs.map(image => {
    const left = totalLeft;
    totalLeft += image.width;
    return {
      input: image.buf,
      gravity: "northwest",
      left: left,
      top: 0
    };
  });

  // 連結処理
  sharp({
    create: {
      width: outputImgWidth,
      height: outputImgHeight,
      channels: 4,
      background: { r: 255, g: 255, b: 255, alpha: 0 }
    }
  })
    .composite(compositeParams)
    .toFile("output.png");
})();

只需运行node index.js即可将图片在左上角连接起来。

解释

首先,导入sharp库。
关于sharp的详细信息,请参阅官方文档。
https://github.com/lovell/sharp
https://sharp.pixelplumbing.com/en/stable/

const sharp = require("sharp");

获取图像信息

声明一个数组来存储图片链接路径和图片信息的数组。

const imagePaths = ["images/1.jpg", "images/2.jpg", "images/3.jpg"];
const imageAttrs = [];

创建一个Promise来获取图像的width、height和buffer,并使用Promise.all来并行执行所有图像。
在Promise.all的then中,将获取到的信息push到之前声明的图像信息数组中。

const promises = [];
const imagePromise = path =>
  new Promise(async resolve => {
    const image = await sharp(path);
    let width = 0, height = 0;
    await image
      .metadata()
      .then(meta => ([width, height] = [meta.width, meta.height]));
    const buf = await image.toBuffer();
    resolve({ width, height, buf });
  });
imagePaths.forEach(path => promises.push(imagePromise(path)));
await Promise.all(promises).then(values => {
  values.forEach(value => imageAttrs.push(value));
});

为什么在执行Promise时(imagePromise(path))不在then中处理呢,因为这里的then会按照完成顺序依次执行。
这次我们希望固定连接顺序,所以在Promise.all的then中进行处理。

设定输出图像

获取width值时将获取所有图像的宽度总和,获取height值时将获取所有图像的最大高度。

const outputImgWidth = imageAttrs.reduce((acc, cur) => acc + cur.width, 0);
const outputImgHeight = Math.max(...imageAttrs.map(v => v.height));

sharp会使用composite方法进行图像合并处理等操作。
对于该composite方法,我们需要进行param参数的设置。

let totalLeft = 0;
const compositeParams = imageAttrs.map(image => {
  const left = totalLeft;
  totalLeft += image.width;
  return {
    input: image.buf,
    gravity: "northwest",
    left: left,
    top: 0
  };
});

将图像的缓冲区放入输入。
通过方向来指定重力。由于本次是左上对齐的连接方式,因此使用northwest。
left和top使用像素为单位设置偏移量。
请详细阅读sharp官方文档。
https://sharp.pixelplumbing.com/en/stable/api-composite/

输出图片

最后使用sharp将图像进行输出。

sharp({
  create: {
    width: outputImgWidth,
    height: outputImgHeight,
    channels: 4,
    background: { r: 255, g: 255, b: 255, alpha: 0 }
  }
})
  .composite(compositeParams)
  .toFile("output.png");

这样就会在根目录下创建一个output.png文件。
如果不需要连接处的空白部分透明,或者想要减小文件尺寸,
您可以将channels从4更改为3,并消除背景的alpha通道,
还可以根据喜好自由地更改输出图片的扩展名为jpg等进行修改。

概述

我在这里没有使用reject来处理错误等等,可能是有点强行,但我已经实现了图像连接处理。
虽然我翻阅了文档,但我没有发现自己在重新发明轮子。
如果有的话,请告诉我,我会很感激。

广告
将在 10 秒后关闭
bannerAds