Преобразование 1-битного файла bmp в массив в C / Stack Overflow

Я хочу превратить 1-битный файл bmp переменной высоты / ширины в простой двумерный массив со значениями 0 или 1. У меня нет опыта редактирования изображений в коде и большинстве библиотек, которые я Я обнаружил, что это связано с большей битовой глубиной, чем мне нужно. Любая помощь по этому поводу будет здорово.

4

Решение

Вот код для чтения монохромного файла .bmp

#include <stdio.h>
#include <string.h>
#include <malloc.h>

unsigned char *read_bmp(char *fname,int* _w, int* _h)
{
unsigned char head[54];
FILE *f = fopen(fname,"rb");

// BMP header is 54 bytes
fread(head, 1, 54, f);

int w = head[18] + ( ((int)head[19]) << 8) + ( ((int)head[20]) << 16) + ( ((int)head[21]) << 24);
int h = head[22] + ( ((int)head[23]) << 8) + ( ((int)head[24]) << 16) + ( ((int)head[25]) << 24);

// lines are aligned on 4-byte boundary
int lineSize = (w / 8 + (w / 8) % 4);
int fileSize = lineSize * h;

unsigned char *img = malloc(w * h), *data = malloc(fileSize);

// skip the header
fseek(f,54,SEEK_SET);

// skip palette - two rgb quads, 8 bytes
fseek(f, 8, SEEK_CUR);

// read data
fread(data,1,fileSize,f);

// decode bits
int i, j, k, rev_j;
for(j = 0, rev_j = h - 1; j < h ; j++, rev_j--) {
for(i = 0 ; i < w / 8; i++) {
int fpos = j * lineSize + i, pos = rev_j * w + i * 8;
for(k = 0 ; k < 8 ; k++)
img[pos + (7 - k)] = (data[fpos] >> k ) & 1;
}
}

free(data);
*_w = w; *_h = h;
return img;
}

int main()
{
int w, h, i, j;
unsigned char* img = read_bmp("test1.bmp", &w, &h);

for(j = 0 ; j < h ; j++)
{
for(i = 0 ; i < w ; i++)
printf("%c ", img[j * w + i] ? '0' : '1' );

printf("\n");
}

return 0;
}

Это простой C, так что не приведение указателей — будьте осторожны при использовании его в C ++.

Самая большая проблема заключается в том, что строки в файлах .bmp выровнены по 4 байта, что очень важно для однобитных изображений. Таким образом, мы рассчитываем размер строки как «ширина / 8 + (ширина / 8)% 4». Каждый байт содержит 8 пикселей, а не один, поэтому мы используем цикл на основе k.

Я надеюсь, что другой код очевиден — много было сказано о .bmp данных заголовка и поддона (8 байт, которые мы пропускаем).

Образец изображения

Ожидаемый результат:

0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
0 0 0 0 0 0 1 1 1 1 0 0 1 1 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 1 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 1 0 0 0
0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 1 0 1 1 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0
10

Другие решения

Следующий код c работает с монохромными растровыми изображениями любого размера. Я предполагаю, что у вас есть ваше растровое изображение в буфере с высотой и шириной, инициализированными из файла. Так

// allocate mem for global buffer
if (!(img = malloc(h * w)) )
return(0);

int i = 0, k, j, scanline;

// calc the scanline. Monochrome images are
// padded with 0 at every line end. This
// makes them divisible by 4.
scanline = ( w + (w % 8) ) >> 3;

// account for the paddings
if (scanline % 4)
scanline += (4 - scanline % 4);

// loop and set the img values
for (i = 0, k = h - 1; i < h; i++)
for (j = 0; j < w; j++) {
img[j+i*w] = (buffer[(j>>3)+k*scanline])
& (0x80 >> (j % 8));
}

Надеюсь это поможет. Преобразовать его в 2D теперь тривиально: но если вы заблудились, вот математика для преобразования 1D массива в 2D, предположим, что r & c — строка и столбец, а w — ширина:
, c + r * w = r, c

Если вы получили дополнительные замечания, ответьте мне, я вышел !!!

0

Давайте рассмотрим монохромное растровое изображение a1x7, то есть это растровое изображение прямой линии шириной 7 пикселей. Сохранить этот образ в ОС Windows; так как 7 не делится поровну на 4, он добавляет в него дополнительные 3 байта.

Таким образом, biSizeImage структуры BITMAPINFOHEADER будет показывать в общей сложности 4 байта. Тем не менее члены biHeight и biWidth будут правильно указывать истинные размеры растрового изображения.

Приведенный выше код завершится ошибкой, потому что 7/8 = 0 (округляя, как это делают все компиляторы c). Следовательно, цикл «i» не будет выполняться, как и «k».

Это означает, что вектор «img» теперь содержит значения мусора, которые не соответствуют пикселям, содержащимся в «данных», то есть результат неверен.

И благодаря индуктивному рассуждению, если оно не удовлетворяет базовому случаю, то, скорее всего, оно не принесет большого пользы для общих случаев.

-2