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
来确定大小。不确定是否有更有效/更快的方法,但您的解决方案肯定有效。。。谢谢