使用 Jimp 处理图像时 NodeJS 达到 6Gb 的峰值
NodeJS peaking at 6Gb when manipulating images with Jimp
我需要在像素尺度上编辑 34000 张照片,所以我写了一个程序,如果图像中的像素超过特定的 RBG 值(240、240、240),我就替换它们,基本上我只想隔离白色像素并将其他所有内容设置为黑色。这是我的代码:
const jimp = require('jimp')
var fs = require('fs');
const PNG = require('pngjs').PNG;
const frames = fs.readdirSync("./out/")
for (let i = 0; i < frames.length; i++) {
function work(frames, i) {
if (frames[i] !== ".DS_Store") {
jimp.read('./out/' + frames[i], (err, image) => {
const bitmap = new Uint8ClampedArray(image.bitmap.data)
let texterHighlit = 240
let nextD = 4;
let items = [];
for (i = 0; i < bitmap.length + 1; i++) {
if (i === nextD) {
if (bitmap[i - 4] > texterHighlit && bitmap[i - 3] > texterHighlit && bitmap[i - 2] > texterHighlit) {
items.push(255)
items.push(255)
items.push(255)
items.push(255)
} else {
items.push(0)
items.push(0)
items.push(0)
items.push(255)
}
nextD = nextD + 4;
}
}
var img_width = image.bitmap.width;
var img_height = image.bitmap.height;
var img_data = Uint8ClampedArray.from(items);
var img_png = new PNG({ width: img_width, height: img_height })
img_png.data = Buffer.from(img_data);
img_png.pack().pipe(fs.createWriteStream("./out/" + frames[i]))
return "done";
})
}
}
work(frames, i)
}
现在,这对一些图像非常有效,但是当在大型数据集(如我提到的 34 000 个图像文件夹)上使用它时,问题开始出现。
作为参考,我在 CentOS8 上使用 PM2 和 --no-autorestart
标志 运行 这段代码。当不使用 PM2 而只使用 node <file>
时,进程被杀死并在控制台中输出“killed”,它不会显示“运行 out of memory”。我已经尝试调试它很长时间了,但没有找到阻止它的方法,我尝试不使用 Jimp,而是使用一个名为 image-pixels 的包,它产生了相同的结果。
有没有办法防止这种情况发生,或者我是否必须在较小的文件夹(例如每个文件夹 1000 张图像)上手动执行此操作?
好吧,所以异步 正确完成 是最后的答案,感谢 NeonSurvivor#2046
在 Discord 上给我的这个答案!
const jimp = require('jimp')
var fs = require('fs');
(async() => {
async function work(frame) {
if (frame === '.DS_Store') return;
const image = await jimp.read('./out/' + frame);
const texterHighlit = 240;
image.scan(0, 0, image.bitmap.width, image.bitmap.height, (x, y, idx) => {
const { data } = image.bitmap;
data[idx] = data[idx + 1] = data[idx + 2] = 255 * [0, 1, 2].every(offset => data[idx + offset] > texterHighlit);
data[idx + 3] = 255;
});
image.write('./out/' + frame);
return 'done';
}
for (const frame of fs.readdirSync('./out/')) {
await work(frame);
await new Promise(res => setTimeout(res, 500));
}
})()
我需要在像素尺度上编辑 34000 张照片,所以我写了一个程序,如果图像中的像素超过特定的 RBG 值(240、240、240),我就替换它们,基本上我只想隔离白色像素并将其他所有内容设置为黑色。这是我的代码:
const jimp = require('jimp')
var fs = require('fs');
const PNG = require('pngjs').PNG;
const frames = fs.readdirSync("./out/")
for (let i = 0; i < frames.length; i++) {
function work(frames, i) {
if (frames[i] !== ".DS_Store") {
jimp.read('./out/' + frames[i], (err, image) => {
const bitmap = new Uint8ClampedArray(image.bitmap.data)
let texterHighlit = 240
let nextD = 4;
let items = [];
for (i = 0; i < bitmap.length + 1; i++) {
if (i === nextD) {
if (bitmap[i - 4] > texterHighlit && bitmap[i - 3] > texterHighlit && bitmap[i - 2] > texterHighlit) {
items.push(255)
items.push(255)
items.push(255)
items.push(255)
} else {
items.push(0)
items.push(0)
items.push(0)
items.push(255)
}
nextD = nextD + 4;
}
}
var img_width = image.bitmap.width;
var img_height = image.bitmap.height;
var img_data = Uint8ClampedArray.from(items);
var img_png = new PNG({ width: img_width, height: img_height })
img_png.data = Buffer.from(img_data);
img_png.pack().pipe(fs.createWriteStream("./out/" + frames[i]))
return "done";
})
}
}
work(frames, i)
}
现在,这对一些图像非常有效,但是当在大型数据集(如我提到的 34 000 个图像文件夹)上使用它时,问题开始出现。
作为参考,我在 CentOS8 上使用 PM2 和 --no-autorestart
标志 运行 这段代码。当不使用 PM2 而只使用 node <file>
时,进程被杀死并在控制台中输出“killed”,它不会显示“运行 out of memory”。我已经尝试调试它很长时间了,但没有找到阻止它的方法,我尝试不使用 Jimp,而是使用一个名为 image-pixels 的包,它产生了相同的结果。
有没有办法防止这种情况发生,或者我是否必须在较小的文件夹(例如每个文件夹 1000 张图像)上手动执行此操作?
好吧,所以异步 正确完成 是最后的答案,感谢 NeonSurvivor#2046
在 Discord 上给我的这个答案!
const jimp = require('jimp')
var fs = require('fs');
(async() => {
async function work(frame) {
if (frame === '.DS_Store') return;
const image = await jimp.read('./out/' + frame);
const texterHighlit = 240;
image.scan(0, 0, image.bitmap.width, image.bitmap.height, (x, y, idx) => {
const { data } = image.bitmap;
data[idx] = data[idx + 1] = data[idx + 2] = 255 * [0, 1, 2].every(offset => data[idx + offset] > texterHighlit);
data[idx + 3] = 255;
});
image.write('./out/' + frame);
return 'done';
}
for (const frame of fs.readdirSync('./out/')) {
await work(frame);
await new Promise(res => setTimeout(res, 500));
}
})()