node.js: определить длину потока перед его передачей в конечный пункт назначения
Контекст этого вопроса заключается в том, что я беру буфер изображения, сжимаю его с помощью pngquant, а затем передаю сжатый образ в ответ. Что-то вроде:
// https://www.npmjs.com/package/pngquant
const PngQuant = require('pngquant');
// start with base64-encoded png image data:
var base64data = '.......';
// then create buffer from this, as per:
// https://stackru.com/a/28440633/4070848
// https://stackru.com/a/52257416/4070848
var imgBuffer = Buffer.from(base64data, 'base64');
// set up pngquant...
const optionsArr = [ ..... ];
const myPngQuanter = new PngQuant(optionsArr);
// convert buffer into stream, as per:
// https://stackru.com/a/16044400/4070848
var bufferStream = new stream.PassThrough();
bufferStream.end(imgBuffer);
// pipe the image buffer (stream) through pngquant (to compress it) and then to res...
bufferStream.pipe(myPngQuanter).pipe(res);
Я хочу определить степень сжатия, достигнутую операцией pngquant. Я могу легко найти начальный размер с помощью:
const sizeBefore = imgBuffer.length;
Мне также нужен размер сжатого потока. Кроме того, эта информация должна быть доступна до того, как поток будет передан res
назначение, потому что мне нужно добавить заголовок res
на основе статистики сжатия.
Получить sizeAfter
Я пробовал модуль length-stream, где вы можете вставить слушателя в канал (между myPngQuanter
а также res
) определить длину по мере прохождения. Хотя это, кажется, работает для определения длины сжатого потока, это не происходит вовремя, чтобы добавить какие-либо заголовки к res
, Я также пробовал длину потока, но не могу заставить его работать вообще.
Любая помощь приветствуется.
1 ответ
Хорошо потоки по своей природе не имеют информации о длине (поток может быть бесконечным, например, открытие /dev/random
), поэтому самый простой вариант, который я вижу, это использование другого временного буфера. К сожалению, это pngquant
не имеет опций для работы с буферами, но вы мало что можете с этим поделать, кроме использования совсем другого пакета.
2-е редактирование, поскольку потоковый буфер может не работать:
Есть пакет под названием stream-to-array
, что позволяет легко реализовать преобразование потока в буфер. Согласно README, код должен быть изменен на:
const toArray = require('stream-to-array');
const util = require('util');
toArray(bufferStream.pipe(myPngQuanter))
.then(function (parts) {
const buffers = parts
.map(part => util.isBuffer(part) ? part : Buffer.from(part));
const compressedBuffer = Buffer.concat(buffers);
console.log(compressedBuffer.length); // here is the size of the compressed data
res.write(compressedBuffer);
});
Или в качестве альтернативы await
, если вы оказались в async
контекст:
const toArray = require('stream-to-array');
const util = require('util');
const parts = await toArray(bufferStream.pipe(myPngQuanter));
const buffers = parts.map(part => util.isBuffer(part) ? part : Buffer.from(part));
const compressedBuffer = Buffer.concat(buffers);
console.log(compressedBuffer.length); // here is the size of the compressed data
res.write(compressedBuffer);