Чтение данных из файла BMP в C - PullRequest
0 голосов
/ 22 апреля 2020

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

bmp. c

struct pixel* read_data(FILE* stream, const struct bmp_header* header){
  if(stream == NULL || header == NULL){
    return 0;
  }
  // w == 1 && p == 1;   w == 2 && p == 2;   w == 3 && p == 3;   w == 4 && p == 0  
  int padding = header->width % 4; 
  int num_of_pixels = header->width * header->height;
  struct pixel* Pixel[num_of_pixels];

  fseek(stream, 54, SEEK_SET); //move 54B (header size)
  int index_p = 0;
  for(int i = 0; i < header->height; i++){
    for(int j = 0; j < header->width; j++){
      Pixel[index_p] = malloc(sizeof(struct pixel));
      fread(&(Pixel[index_p]->blue), 1, 1, stream); 
      fread(&(Pixel[index_p]->green), 1, 1, stream); 
      fread(&(Pixel[index_p]->red), 1, 1, stream); 
      index_p++;
    }
    fseek(stream, padding, SEEK_CUR);  //padding at the end of row
  }
  return *Pixel;
}

bmp.h

struct pixel {
    uint8_t blue;
    uint8_t green;
    uint8_t red;
    //uint8_t alpha;
} __attribute__((__packed__));

/**
 * Read the pixels
 *
 * Reads the data (pixels) from stream representing the image. If the stream
 * is not open or header is not provided, returns `NULL`.
 *
 * @param stream opened stream, where the image data are located
 * @param header the BMP header structure
 * @return the pixels of the image or `NULL` if stream or header are broken
 */
struct pixel* read_data(FILE* stream, const struct bmp_header* header);

заголовок при необходимости (в основном мы используем только 24-битный цвет)

struct bmp_header{
    uint16_t type;              // "BM" (0x42, 0x4D)
    uint32_t size;              // file size
    uint16_t reserved1;         // not used (0)
    uint16_t reserved2;         // not used (0)
    uint32_t offset;            // offset to image data (54B)
    uint32_t dib_size;          // DIB header size (40B)
    uint32_t width;             // width in pixels
    uint32_t height;            // height in pixels
    uint16_t planes;            // 1
    uint16_t bpp;               // bits per pixel (24)
    uint32_t compression;       // compression type (0/1/2) 0
    uint32_t image_size;        // size of picture in bytes, 0
    uint32_t x_ppm;             // X Pixels per meter (0)
    uint32_t y_ppm;             // X Pixels per meter (0)
    uint32_t num_colors;        // number of colors (0)
    uint32_t important_colors;  // important colors (0)
} __attribute__((__packed__));

main. c Мне не нужно присваивать какие-либо переменные вызываемым функциям, потому что у нас есть программа для проверки этого, я просто должен вызвать их в main

int main(){

  struct bmp_header* header;
  FILE *stream = fopen("./assets/square.2x3.bmp", "rb");
  header = read_bmp_header(stream);
  read_data(stream, header);
  read_bmp(stream);
  struct bmp_image* image;
  image = malloc(sizeof(struct bmp_image));
  free_bmp_image(image);  
  fclose(stream);
  return 0;
}

testing (есть еще тестов, но этого должно быть достаточно)

1: 
FILE* stream = "Qk0+AAAAAAAAADYAAAAoAAAAAgAAAAEAAAABABgAAAAAAAgAAAAjLgAAIy4AAAAAAAAAAAAA/wAAAP8AAAA="; // base64 encoded stream
struct bmp_header* header = read_bmp_header(stream);
fseek(stream, offset, SEEK_SET);
Assertion 'read_data(stream, header) == "/wAAAP8A"' failed. [got "/wAAFctV"]

2: 
FILE* stream = "Qk1GAAAAAAAAADYAAAAoAAAAAgAAAAIAAAABABgAAAAAABAAAAAjLgAAIy4AAAAAAAAAAAAA/wAAAAAAAAAAAP8A/wAAAA=="; // base64 encoded stream
struct bmp_header* header = read_bmp_header(stream);
fseek(stream, offset, SEEK_SET);
Assertion 'read_data(stream, header) == "/wAAAAAAAAD/AP8A"' failed. [got "/wAAAAAAAAAAAAAA"]

Так что после "==" ожидается результат и в скобках мой результат из моего кода. Как я уже говорил, это может быть что-то с отступом, так как он начинается хорошо, но не заканчивается хорошо. Спасибо за помощь.

1 Ответ

2 голосов
/ 22 апреля 2020

Короткий ответ : установите заполнение на (4-((3*width)%4))%4

Длинный ответ :

Ваш код включен:

int padding = header->width % 4; 

//Some lines of code

fseek(stream, padding, SEEK_CUR);

В растровом изображении заполнение добавляется до тех пор, пока каждая строка не будет кратна 4 байтам. Вы взяли отступы как width % 4.

Во-первых, каждый пиксель занимает 3 байта (для rgb). Так и должно быть (3*width)%4. Далее нам нужно вычесть его из 4 байтов (поскольку заполнение равно 4- pixels occupied). Так что отступ будет 4-((3*width)%4). Другая небольшая модификация, если (3*width)%4==0, тогда заполнение будет равно 4 (тогда как мы ожидаем, что оно будет 0). Итак, мы берем еще один мод4, просто чтобы быть уверенным,

Таким образом, отступы будут (4-((3*width)%4))%4

РЕДАКТИРОВАТЬ:

Как указано пользователем Крейг Эстей в комментариях, лучше использовать sizeof (struct pixel) вместо 3

...