Работа с заполнением в файле BMP в C
Я пытаюсь отредактировать файл 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)
и это работает, как я тестировал это с изображениями с различной шириной.
Я успешно извлек данные B,G,R из BMP-файла и поместил их в массив, поэтому я опубликую только ту часть кода, с которой у меня возникли проблемы.
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 ответа
Проблема в этой части:
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
изначально указывал на).
Заполнение должно быть добавлено в каждой строке. В циклах вы настраиваете 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;
}
}
Есть ли способ, которым я могу идентифицировать отступы пикселей..
Да - в моем цикле выше с настройками для заполнения, он автоматически пропускает сам отступ. Вы можете безопасно удалить явный цикл '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;
...
}
"Заполняющие байты" - это байты, следующие за пикселями строки развертки. Вас интересует не столько отступ, сколько размер строки развертки и размер пикселя:
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];
}
]
}