2016-03-28 37 views
2

我正在尝试编辑C中的BMP文件。我的代码适用于没有填充的BMP文件,但我在填充时遇到了问题。在C中处理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

什么使用imgArray? –

+0

我修正了这个问题。我从另一个堆栈溢出问题中复制了那部分代码,并忘记更改数组名称。 – user6005857

+0

在循环遍历列时,应该增加'c'。 –

回答

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开始时等覆盖第第一行的几个字节。然后,每个下一个行被复制,但您从头开始继续覆盖(其中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; 
    } 
} 

是我有办法可以识别填充像素..

是 - 我的循环以上的调整对于填充,它会自动跳过填充本身。您可以安全地删除显式的'设置填充为0'循环结束。

+0

非常好!你认为使用第二种方法做它是可行的(1循环)? – user6005857

+0

@ user6005857:是的,但我建议不要这样做。你可以通过'height *(width * 3 + padding)'做一个循环,但是然后内部表达式需要辨别像素和填充,变得相当复杂。 – usr2564301

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; 
    ... 
} 
+0

非常聪明。这是一个很好的方法来做到这一点! – user6005857

1

的“填充字节”是一个扫描线的像素中之后的字节。你是不是在填充作为扫描线的大小和像素大小,以便感兴趣的是:

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