为什么我的用于在位图缓冲区之间转换索引和x、y的算法导致图像在垂直方向上翻转?

11

当使用位图缓冲区时,如下所示:

[50, 50, 50, 255, 50, 50, 50, 255, ...]
[r,  g,  b,  a,   r,  g,  b,  a, ...]

我经常像这样使用数学:

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;

为了计算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;
}

你知道位图是从左上角开始的吗? - Bacon
@Bacon 是的...我有。但我的数学很差。我显然做错了什么,但只是没有看到它。 - J.Todd
2个回答

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

以下代码适用于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;
    }
}

1

检查您位图的头文件。在情况(从上到下)下,高度必须为负。文档

biHeight 位图的高度,以像素为单位。如果biHeight为正, 位图是自下而上的DIB,其原点为左下角。 如果biHeight为负,则位图是自上而下的DIB,其原点为左上角。

如果biHeight为负,则表示为自上而下的DIB,biCompression必须 是BI_RGB或BI_BITFIELDS。自上而下的DIB不能被压缩。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接