为什么我使用位图缓冲区在索引和 x,y 之间转换的算法会导致图像垂直翻转?
Why does my algorithm to convert between index and x,y with bitmap buffers result in the image being flipped vertically?
当使用像这样的位图缓冲区时:
[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;
}
检查位图的 header。在这种情况下(从上到下),高度必须为负数。 documentation。
biHeight
The height of the bitmap, in pixels. If biHeight is positive,
the bitmap is a bottom-up DIB and its origin is the lower-left corner.
If biHeight is negative, the bitmap is a top-down DIB and its origin
is the upper-left corner.
If biHeight is negative, indicating a top-down DIB, biCompression must
be either BI_RGB or BI_BITFIELDS. Top-down DIBs cannot be compressed.
位图通常从bottom-left角开始,一直到top-right角。但不总是。
位图头文件中有一个值biHeight
,如果这个值为负数,则位图倒置,从bottom-left开始。如果此值为正,则位图从 top-left.
开始
如果您有权访问 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;
}
}
当使用像这样的位图缓冲区时:
[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;
}
检查位图的 header。在这种情况下(从上到下),高度必须为负数。 documentation。
biHeight The height of the bitmap, in pixels. If biHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner. If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.
If biHeight is negative, indicating a top-down DIB, biCompression must be either BI_RGB or BI_BITFIELDS. Top-down DIBs cannot be compressed.
位图通常从bottom-left角开始,一直到top-right角。但不总是。
位图头文件中有一个值biHeight
,如果这个值为负数,则位图倒置,从bottom-left开始。如果此值为正,则位图从 top-left.
如果您有权访问 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;
}
}