为什么我的使用位图缓冲区在索引和x,y之间进行转换的算法会导致图像垂直翻转?

Viz*_*ary 11 javascript algorithm bitmap

使用位图缓冲区时,例如:

[50, 50, 50, 255, 50, 50, 50, 255, ...]
[r,  g,  b,  a,   r,  g,  b,  a, ...]
Run Code Online (Sandbox Code Playgroud)

我经常这样使用数学:

let bufferWidth = width * 4;
buffer.forEach((channel, index) => {
    let y = Math.floor(index / bufferWidth);
    let x = Math.floor((index % bufferWidth) / 4);
    let remainder = index % 4;
Run Code Online (Sandbox Code Playgroud)

为了计算x,y或反之亦然,以使用位图数据的平面缓冲区。几乎总是我最终得到的结果是错误的,而以某种方式最终将它们的结果翻转回去,但是很明显,我对此有想法。

这种数学运算有什么问题,会导致位图被翻转?

完整代码,用于裁剪位图的函数:

function crop(
  buffer,
  width,
  height,
  leftLimit,
  rightLimit,
  lowerLimit,
  upperLimit
) {
  let croppedWidth = rightLimit - leftLimit;
  let croppedHeight = upperLimit - lowerLimit;
  let length = croppedHeight * croppedWidth * 4;
  let bufferWidth = width * 4;
  let croppedBuffer = new Uint8Array(length);
  buffer.forEach((channel, index) => {
    let y = Math.floor(index / bufferWidth);
    let x = Math.floor((index % bufferWidth) / 4);
    let remainder = index % 4;
    let yCropped = y - lowerLimit;
    let xCropped = x - leftLimit;
    let indexCropped = yCropped * croppedWidth * 4 + xCropped * 4 + remainder;
    if (
      xCropped >= 0 &&
      xCropped <= croppedWidth &&
      yCropped >= 0 &&
      yCropped <= croppedHeight
    ) {
      croppedBuffer[indexCropped] = buffer[index];
    }
  });
  return croppedBuffer;
}
Run Code Online (Sandbox Code Playgroud)

Bar*_*ani 4

位图通常从左下角开始到右上角。但不总是。

位图头文件中有一个值biHeight,如果该值为负数,则位图是颠倒的,从左下角开始。如果该值为正,则位图从左上角开始。

如果您有权访问,biHeight则只需翻转其值即可将位图正面朝上显示。

为了使计算更容易,选择任何有效的 X/Y 点,然后source_index在缓冲区中找到相应的点,如下所示。将该点复制到目标缓冲区中。

请注意,您需要一个额外的循环来将 4 个字节从源复制到目标(您的代码中没有该循环,所以我根本不确定您的代码是如何工作的)

for(let i = 0; i < bytes_per_pixel; i++)
    buffer_cropped[dst_index + i] = buffer[source_index + i];
Run Code Online (Sandbox Code Playgroud)

下面的代码应该适用于 32 位图像(每像素 4 字节)。请注意,24 位图像需要填充。

if (height < 0) 
    height = -height;
let bytes_per_pixel = 4;
let cropped_x = 10;
let cropped_y = 10;
let cropped_width = width / 2;
let cropped_height = height / 2;

if (new_x < 0 || new_x >= new_width || 
    new_y < 0 || new_y >= new_height) { error... }
if (cropped_width < 1 || cropped_width > width || 
    cropped_height < 1 || cropped_height > height) { error... }

let dst_index = 0;
for(let y = cropped_y; y < cropped_y + cropped_height; y++)
{
    for(let x = cropped_x; x < cropped_x + cropped_width; x++)
    {
        //use for right-side up bitmap:
        //int source_index = (y * width + x) * bytes_per_pixel;
        ////

        //use for upside-down bitmap:
        let source_index = ((height - y - 1)* width + x) * bytes_per_pixel;
        ////

        for(let i = 0; i < bytes_per_pixel; i++)
            buffer_cropped[dst_index + i] = buffer[source_index + i];
        dst_index += bits_per_pixel;
    }
}
Run Code Online (Sandbox Code Playgroud)