在C中处理BMP文件中的填充

时间:2016-03-28 11:53:39

标签: c image image-processing padding bmp

我正在尝试在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;
    }
}

3 个答案:

答案 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的地方)。

应在每行添加 。在循环中,您可以调整ab,但忘记调整填充。

我建议使用更直接的代码(未经测试!):

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