获取PNG图像时出现意外的缓冲区结果

时间:2018-06-18 13:41:14

标签: node.js request

我使用热门库(例如axiosrequest)从网上抓取几张随机PNG图像,但两者似乎都返回了错误的文件签名。

请将以下代码段作为示例(https://repl.it/@phobos/Request-png-file-wrong-buffer):

const request = require('request');
const png = require('pngjs').PNG;

const url = 'https://www.sample-videos.com/img/Sample-png-image-100kb.png';

  function getPngBuffer() {
  return new Promise((resolve, reject) => {
    request.get(url, (err, res, body) => {
      if (err || !body) return reject(err || new Error('no body'));

      const buf = Buffer.from(body);

      console.log('\nGOT SIG: ', buf.slice(0, 8));
      console.log('EXPECTED SIG:', '<Buffer 89 50 4e 47 0d 0a 1a 0a>\n')

      new png({ filterType:4 }).parse(buf, (err, png) => {
            if (err) return reject(err);
            return resolve('Worked!')
      });

    });
  })
}

getPngBuffer()
  .then(console.log)
  .catch(console.error);

当我请求任意PNG图像并通过Buffer API查看第一个字符时,我看到错误的值。

根据png规范,它应该是89 50 4e 47 0d 0a 1a 0a,实际上,如果我通过浏览器下载图像并通过十六进制编辑器检查它确实是这样。

当我记录buf时,它会给我ef bf bd 50 4e 47 0d 0a

基本上,它不是âPNG而是返回o?=PNG而不是像pngjs这样的内容。

解决这个明显问题的最佳方法是什么,我真的不想改变buf给它预期的文件签名,因为我也必须改变它CRC。

提前致谢

2 个答案:

答案 0 :(得分:1)

我认为这是一个相对简单的修复,我们需要将请求编码设置为null:

const request = require('request');
const png = require('pngjs').PNG;

const url = 'https://i.pinimg.com/originals/5f/3a/bb/5f3abbf32683629689eda72189f755da.png';

  function getPngBuffer() {
  return new Promise((resolve, reject) => {

    var options = 
    {
      url: url,
      encoding: null
    };
    request.get(options, (err, res, body) => {
      if (err || !body) return reject(err || new Error('no body'));

      const buf = Buffer.from(body);

      console.log('\nGOT SIG: ', buf.slice(0, 8));
      console.log('EXPECTED SIG:', '<Buffer 89 50 4e 47 0d 0a 1a 0a>\n')

      new png({ filterType:4 }).parse(buf, (err, png) => {
            if (err) return reject(err);
            return resolve('Worked!')
      });

    });
  })
}

getPngBuffer()
  .then(console.log)
  .catch(console.error);

只需在传递给request.get的options对象中将编码设置为null即可。我用图像遇到过这几次。

来自Request docs:

encoding - 用于响应数据的setEncoding的编码。如果为null,则将主体作为Buffer返回。其他任何东西(包括默认值undefined)将作为encoding参数传递给toString()(默认情况下这实际上是utf8)。 (注意:如果您需要二进制数据,则应设置encoding:null。)

这个解决方案对我有用(虽然我使用的是不同的图像,但我希望结果是一样的)

答案 1 :(得分:1)

问题是编码,如果没有设置,则默认值为utf8body将转换为字符串。

只需将encoding: null传递给请求,然后删除Buffer.from,因为body已经是缓冲区。

  

encoding - 用于响应数据的setEncoding的编码。如果   null,body作为Buffer返回。别的什么(包括   默认值undefined)将作为encoding参数传递   to toString()(意思是默认情况下这实际上是utf8)。 (注意:如果   你希望二进制数据,你应该设置encoding:null。)

const options =  {
  url: url,
  encoding: null
};

request.get(options, (err, res, buf) => {
  if (err || !buf) return reject(err || new Error('no body'));

  console.log('\nGOT SIG: ', buf.slice(0, 8));
  console.log('EXPECTED SIG:', '<Buffer 89 50 4e 47 0d 0a 1a 0a>\n')

  new png({ filterType:4 }).parse(buf, (err, png) => {
        if (err) return reject(err);
        return resolve('Worked!')
  });

});