javascript 在带有(Array)Buffers的NodeJ代码中,使用了本机readUInt16BE,但我的上下文是浏览器,因此我想使用use DataView.getUint16

s2j5cfk0  于 5个月前  发布在  Java
关注(0)|答案(1)|浏览(55)

我在Node.js中遇到了一个JPEG解析函数,我正试图将其应用到浏览器环境中。原始代码可以在这里找到。
原始代码使用Node.js的Buffer类。由于我想将其用于浏览器环境,因此必须使用DataView.getUint16(0, false /* big endian */)而不是buffer.readUInt16BE(0) /*BE = big endian */
有趣的是,DataView也可以在NodeJ中使用,所以结果可能是交叉引用。
以下是我到目前为止发现的:

  • 引入一个从4开始的变量j有助于获得第一次迭代的正确偏移量,因为缓冲区4的第一个字节被切片:
let j=4 // match the buffer slicing above

字符串

  • 为下一次阅读而向j添加+ 2并不能帮助获得下一次迭代的正确偏移量,尽管缓冲区正好被分割为两个字节
j+=2; // match the buffer slicing below ( i + 2 )
    buffer = buffer.slice(i + 2); // Buffer is sliced of two bytes, 0 offset is now 2 bytes further ?


下面是添加了日志记录的函数

function calculate (buffer) {

  // Skip 4 chars, they are for signature
  buffer = buffer.slice(4);
  let j=4 // match the buffer slicing above
  let aDataView=new DataView(buffer.buffer);
  var i, next;
  while (buffer.length) {
    // read length of the next block
    i = buffer.readUInt16BE(0);
    console.log("i="+i,"read="+aDataView.getUint16(j,false));
    j+=2; // match the buffer slicing below ( i + 2 )
    // ensure correct format
    validateBuffer(buffer, i);

    // 0xFFC0 is baseline standard(SOF)
    // 0xFFC1 is baseline optimized(SOF)
    // 0xFFC2 is progressive(SOF2)
    next = buffer[i + 1];
    if (next === 0xC0 || next === 0xC1 || next === 0xC2) {
      return extractSize(buffer, i + 5);
    }

    // move to the next block
    buffer = buffer.slice(i + 2);
  }

  throw new TypeError('Invalid JPG, no size found');
}


this image上的实际结果:

node .\start.js 
i=16 read=16 # Seems to be the correct offset
i=91 read=19014 # Wrong offset
i=132 read=18758


到目前为止,我的调试步骤如下:从npm npm install buffer-image-size --save安装buffer-image-size编写start.js如下

var sizeOf = require('buffer-image-size');
const fs = require('fs');

fileBuffer = fs.readFileSync("flowers.jpg");
var dimensions = sizeOf(fileBuffer);
console.log(dimensions.width, dimensions.height);


编辑**“node_modules\buffer-image-size\lib\types\jpg.js”**添加提到的行和日志记录
你有没有什么线索

*为什么j加2不能得到正确的偏移量
*如何获得相同的算法,而无需一遍又一遍地切片缓冲区

我感谢任何关于解决这个问题的见解或指导。谢谢!

lyfkaqu1

lyfkaqu11#

是的,避免既提前偏移又重新切片缓冲区,这只会让人困惑。我会写

function calculate(typedArray) {
  const view = new DataView(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);
  let i = 0;
  // Skip 4 chars, they are for signature
  i += 4;

  while (i < view.byteLength) {
    // read length of the next block
    const blockLen = view.getUint16(i, false /* big endian */);

    // ensure correct format
    // index should be within buffer limits
    if (i + blockLen > view.byteLength) {
      throw new TypeError('Corrupt JPG, exceeded buffer limits');
    }
    // Every JPEG block must begin with a 0xFF
    if (view.getUint8(i + blockLen) !== 0xFF) {
      throw new TypeError('Invalid JPG, marker table corrupted');
    }

    // 0xFFC0 is baseline standard(SOF)
    // 0xFFC1 is baseline optimized(SOF)
    // 0xFFC2 is progressive(SOF2)
    const next = view.getUint8(i + blockLen + 1);
    if (next === 0xC0 || next === 0xC1 || next === 0xC2) {
      return extractSize(view, i + blockLen + 5);
    }

    // move to the next block
    i += blockLen + 2;
  }

  throw new TypeError('Invalid JPG, no size found');
}

字符串
请注意,这段代码是源代码的直接翻译,有点令人困惑和错误:

  • i不指向段的开始,而是指向段中的两个字节(在标记之后)
  • 代码跳过了第一个动态段(无可否认,它是is required to be an APP0 segment
  • 代码假定所有段在其头中指定了可变长度,并忽略独立标记和填充字节
  • 该代码可能会导致RangeError异常访问超出缓冲区末尾的字节,因为它只检查 past 块是否在限制范围内。

相关问题