我正在尝试在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数据并将其放入数组中,因此我只会发布我遇到问题的部分代码。
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;
}
}
我想要做的是“绘制”输出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;
}
}
答案 0 :(得分:3)
问题出在这一部分:
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;
}
}
有没有办法识别填充像素..
是的 - 在上面的循环中调整了填充,它会自动跳过填充本身。您可以安全地将显式&#39;设置填充删除为0&#39;循环结束。
答案 1 :(得分:3)
类似的东西:
...
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;
...
}
答案 2 :(得分:1)
&#34;填充字节&#34;是扫描线像素后面的字节。您对填充不像扫描线尺寸和像素大小那么感兴趣:
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];
}
]
}