node.js:确定流的长度,然后将其通过管道传输到最终目标

时间:2019-01-02 14:43:46

标签: node.js node-streams pngquant

此问题背后的上下文是,我正在使用图像缓冲区,使用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://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,我尝试了length-stream module,您可以在其中将侦听器插入管道中(在myPngQuanterres之间)以确定其长度经过。尽管这确实可以确定压缩流的长度,但并没有及时向res添加任何标头。我也尝试过stream-length,但根本无法正常工作。

任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:2)

从本质上讲,很好的流实际上没有长度信息(流可以是无限的,例如打开/dev/random),因此我看到的最简单的选择是使用另一个临时缓冲区。不幸的是,pngquant没有用于对缓冲区进行操作的选项,但是除了完全使用其他程序包之外,您无能为力。

第二次编辑,因为流缓冲可能不起作用:

有一个名为Here's some helpful documentation from Mozilla on this function.的程序包,可以轻松实现流到缓冲区的转换。根据{{​​3}},应将代码修改为:

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);