node.js:在流通过管道传输到最终目的地之前确定流的长度

node.js:在流通过管道传输到最终目的地之前确定流的长度,node.js,node-streams,pngquant,Node.js,Node Streams,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://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://stackoverflow.com/a/28440633/4070848
//   https://stackoverflow.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://stackoverflow.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,我尝试了,您可以在管道中插入一个侦听器(在
myPngQuanter
res
之间),以确定它通过时的长度。虽然这似乎可以确定压缩流的长度,但没有及时向
res
添加任何头。我也试过了,但根本无法让它工作


感谢您的帮助。

从本质上讲,流并没有真正的长度信息(流可以是无限的,例如打开
/dev/random
),因此我能看到的最简单的选择是使用另一个临时缓冲区。不幸的是,
pngquant
没有在缓冲区上操作的选项,但是除了使用完全不同的软件包之外,您没有什么可以做的

第二次编辑,因为流缓冲区可能无法工作:

有一个名为的包,它允许轻松实现流到缓冲区的转换。根据,代码应修改为:

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);
});
或者使用
wait
,如果您恰好处于
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);

好主意。在调用
compressedStream.PIPE(res)
Hmm时,我得到
Error[ERR\u STREAM\u CANNOT\u PIPE]:CANNOT PIPE,不可读。现在我得到
TypeError[ERR\u INVALID\u ARG\u TYPE]:第一个参数必须是string或Buffer类型之一。调用
res.write(compressedBuffer)
时接收到类型布尔值。实际上,
compressedBuffer
的值在该点是
false
,而
compressedStream.size()
0
。我还从
流缓冲区
包的自述文件中注意到它是“不应该是一个速度恶魔,它更适合测试/调试或奇怪的边缘情况。它与一个内部缓冲区一起工作,它将内容复制到/从/周围”。我想知道,使用它,而不只是从端到端(如我的原始代码中)进行流式传输,而不需要“大小检查”,它真的会减慢多少速度“在结束之前,这很奇怪。如果
流缓冲区真的那么慢,请使用不同的软件包查看最新编辑是否有帮助。话虽如此,完全有可能
pngquant
内部在某个点读取完整的内存,我真的怀疑您的PNG图像是否足够大,这是否重要。我喜欢它!!很好用!我做的唯一一个小改动与核心问题完全无关,即使用
res.send(compressedBuffer)
而不是
res.write(compressedBuffer)
。。。看见我喜欢这样一个事实,即使用此解决方案,我们根据“before”和“after”的
buffer.length
来确定大小。不确定是否有更有效/更快的方法,但您的解决方案肯定有效。。。谢谢