使用NodeJS的图像处理库”sharp”来拼接图像
首先
最近我遇到了一个问题,想要像NodeJS中的ImageMagick的append那样简单地将大小不同的图片横向连接起来。但是由于太简单了,很难找到相关的文章,所以我想写下备忘录作为记录。
要做的事情
- sharpで画像情報取得、連結
版本
NodeJS: v12.14.1
銳利: v0.23.4
产物
出现的图像
程式碼
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来处理错误等等,可能是有点强行,但我已经实现了图像连接处理。
虽然我翻阅了文档,但我没有发现自己在重新发明轮子。
如果有的话,请告诉我,我会很感激。