在 C 中处理 BMP 文件中的填充
Dealing with padding in a BMP file in C
我正在尝试用 C 编辑 BMP 文件。我的代码适用于没有填充的 BMP 文件,但我在处理填充时遇到了问题。
我读过一些关于 BMP 文件的其他问题,但大多数使用其他语言,如 C# 和 Java,所以我觉得它们不是很有用。
这是像素阵列的样子,但要大得多:
char bmpArray[MAX] = {B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0}
零用于填充字节,使每一行都可以被 4 整除,这取决于图像的像素宽度。我想要做的是将这些填充字节保留在相同位置,只处理 B、G、R 字节。如果我对填充值应用编辑,生成的图像将会失真。
我做了一个函数,根据宽度生成填充字节的数量。
它使用这个公式 4 - ((width * 3) % 4)
并且它在我用不同宽度的图像测试它时有效。
我成功提取了 BMP 文件的 B、G、R 数据并将其放入数组中,所以我只 post 我遇到问题的部分代码。
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
c++;
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00;
}
}
我想要做的是 "draw" 输出 BMP 文件的每一行,然后在我到达行尾时立即停止,即宽度 * 3,然后绘制填充转到下一行像素之前的字节数。
或者,有没有一种方法可以使用单个 for 循环识别填充像素,然后使用 if 语句不修改填充像素?例如:
for (int a = 0; a < bmpArraySize; a++) {
paddingBytes = ??? //for example for the first row
// paddingBytes are i + width*3 + 1
// and i + width*3 + 2 and i + width*3 + 3 if padding = 3
if (a = paddingBytes) {
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
}
else {
bmpArray[a] = 255;
}
}
问题出在这部分:
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00; /* ONLY HERE is 'c' updated! */
}
}
在每一行的末尾,填写从 c
开始的填充,它从 0
开始,因此会覆盖第一行的前几个字节。然后,每个 next 行都被复制,但您继续从头开始覆盖(c
最初指向的地方)。
应在每行上添加填充。在循环中,您调整 a
和 b
但忘记调整填充。
我建议使用更直接的代码(未经测试!):
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3 + padding)+b] < 127) {
bmpArray[a*(width*3 + padding)+b] = 0;
} else {
bmpArray[a*(width*3 + padding)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[a*(width*3 + padding) + 3*width + pad] = 0x00;
}
}
is there a way I can identify the padding pixels ..
是的——在我上面的调整填充的循环中,它会自动跳过填充本身。您可以安全地删除末尾的显式 'set padding to 0' 循环。
类似于:
...
int originalLineSize = width * 3;
int workLineSize = originalLineSize + 4 - originalLineSize % 4;
for (int a = 0; a < bmpArraySize; ++a) {
if ((a % workLineSize) >= originalLineSize)
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
...
}
"padding bytes" 是扫描线像素后面的字节。您对填充不如对扫描线大小和像素大小感兴趣:
iScanlineSize = ((width * bitsperpixel) + 31) / 32 * 4;
iBytesperPixel = bitsperpixel / 8;
现在您可以遍历扫描线并寻址像素和像素部分(颜色),如下所示:
for (int a = 0; a < height; a++) {
for (int b = 0; b < width; b++) {
for (int c = 0; c < iBytesperPixel; c++) {
pixelPart= bmpArray[a*iScanlineSize + b*iBytesperPixel + c];
}
]
}
我正在尝试用 C 编辑 BMP 文件。我的代码适用于没有填充的 BMP 文件,但我在处理填充时遇到了问题。
我读过一些关于 BMP 文件的其他问题,但大多数使用其他语言,如 C# 和 Java,所以我觉得它们不是很有用。
这是像素阵列的样子,但要大得多:
char bmpArray[MAX] = {B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0,
B,G,R,B,G,R,B,G,R,0,0,0}
零用于填充字节,使每一行都可以被 4 整除,这取决于图像的像素宽度。我想要做的是将这些填充字节保留在相同位置,只处理 B、G、R 字节。如果我对填充值应用编辑,生成的图像将会失真。
我做了一个函数,根据宽度生成填充字节的数量。
它使用这个公式 4 - ((width * 3) % 4)
并且它在我用不同宽度的图像测试它时有效。
我成功提取了 BMP 文件的 B、G、R 数据并将其放入数组中,所以我只 post 我遇到问题的部分代码。
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
c++;
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00;
}
}
我想要做的是 "draw" 输出 BMP 文件的每一行,然后在我到达行尾时立即停止,即宽度 * 3,然后绘制填充转到下一行像素之前的字节数。
或者,有没有一种方法可以使用单个 for 循环识别填充像素,然后使用 if 语句不修改填充像素?例如:
for (int a = 0; a < bmpArraySize; a++) {
paddingBytes = ??? //for example for the first row
// paddingBytes are i + width*3 + 1
// and i + width*3 + 2 and i + width*3 + 3 if padding = 3
if (a = paddingBytes) {
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
}
else {
bmpArray[a] = 255;
}
}
问题出在这部分:
int c = 0;
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3)+b] < 127) {
bmpArray[a*(width*3)+b] = 0;
} else {
bmpArray[a*(width*3)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[c++] = 0x00; /* ONLY HERE is 'c' updated! */
}
}
在每一行的末尾,填写从 c
开始的填充,它从 0
开始,因此会覆盖第一行的前几个字节。然后,每个 next 行都被复制,但您继续从头开始覆盖(c
最初指向的地方)。
应在每行上添加填充。在循环中,您调整 a
和 b
但忘记调整填充。
我建议使用更直接的代码(未经测试!):
for (int a = 0; a < height; a++) {
for (int b = 0; b < width*3; b++) {
if (bmpArray[a*(width*3 + padding)+b] < 127) {
bmpArray[a*(width*3 + padding)+b] = 0;
} else {
bmpArray[a*(width*3 + padding)+b] = 255;
}
}
for (int pad = 0; pad < padding; pad++) {
bmpArray[a*(width*3 + padding) + 3*width + pad] = 0x00;
}
}
is there a way I can identify the padding pixels ..
是的——在我上面的调整填充的循环中,它会自动跳过填充本身。您可以安全地删除末尾的显式 'set padding to 0' 循环。
类似于:
...
int originalLineSize = width * 3;
int workLineSize = originalLineSize + 4 - originalLineSize % 4;
for (int a = 0; a < bmpArraySize; ++a) {
if ((a % workLineSize) >= originalLineSize)
bmpArray[a] = 0x00;
}
else if (bmpArray[a] < 127) {
bmpArray[a] = 0;
...
}
"padding bytes" 是扫描线像素后面的字节。您对填充不如对扫描线大小和像素大小感兴趣:
iScanlineSize = ((width * bitsperpixel) + 31) / 32 * 4;
iBytesperPixel = bitsperpixel / 8;
现在您可以遍历扫描线并寻址像素和像素部分(颜色),如下所示:
for (int a = 0; a < height; a++) {
for (int b = 0; b < width; b++) {
for (int c = 0; c < iBytesperPixel; c++) {
pixelPart= bmpArray[a*iScanlineSize + b*iBytesperPixel + c];
}
]
}