[C] problem z edycją nagłówka BMP


(Przemekbaranowski) #1

Próbuję zrobić programik, którego elementem będzie odczyt (nie zaimplementowana jeszcze edycja) i zapis z powrotem do tego samego pliku BMP.

#include 

#include 



struct bmp_file_header {

    unsigned short type;

    unsigned long size;

    unsigned long reserved;

    unsigned long bitmap_offset;

    unsigned long header_size;

    signed long width;

    signed long height;

    unsigned short planes;

    unsigned short bits_per_pixel;

    unsigned long compression;

    unsigned long bitmap_size;

    signed long horizontal_resolution;

    signed long vertical_resolution;

    unsigned long num_colors;

    unsigned long num_important_colors;

}BMP;



void BMP_header_reader(){

 FILE *plik;

 plik = fopen("test.bmp","r");



 fread(&BMP.type,sizeof(BMP.type),1,plik);

 fread(&BMP.size,sizeof(BMP.size),1,plik);

 fread(&BMP.reserved,sizeof(BMP.reserved),1,plik);

 fread(&BMP.bitmap_offset,sizeof(BMP.bitmap_offset),1,plik);

 fread(&BMP.header_size,sizeof(BMP.header_size),1,plik);

 fread(&BMP.width,sizeof(BMP.width),1,plik);

 fread(&BMP.height,sizeof(BMP.height),1,plik);

 fread(&BMP.planes,sizeof(BMP.planes),1,plik);

 fread(&BMP.bits_per_pixel,sizeof(BMP.bits_per_pixel),1,plik);

 fread(&BMP.compression,sizeof(BMP.compression),1,plik);

 fread(&BMP.bitmap_size,sizeof(BMP.bitmap_size),1,plik);

 fread(&BMP.horizontal_resolution,sizeof(BMP.horizontal_resolution),1,plik);

 fread(&BMP.vertical_resolution,sizeof(BMP.vertical_resolution),1,plik);

 fread(&BMP.num_colors,sizeof(BMP.num_colors),1,plik);

 fread(&BMP.num_important_colors,sizeof(BMP.num_important_colors),1,plik);


 fclose(plik);

 printf("type: %hu\n",BMP.type);

 printf("size: %lu\n",BMP.size);

  printf("reserved: %lu\n",BMP.reserved);

 printf("offset: %lu\n",BMP.bitmap_offset);

}




void test (){

long int i;

unsigned char *tablica;

tablica = (unsigned char*)malloc(BMP.bitmap_size);

for (i=0;i

FILE *plik;

plik = fopen("test.bmp","rb");

fseek(plik,BMP.bitmap_offset,0);

fread(tablica,sizeof(char),BMP.bitmap_size,plik);

fclose(plik);


for (i=0;i<100;i++)

printf("%ld: %hu\n",i,tablica[i]);


tablica[10]=33;


plik=fopen("test.bmp","wb");

fseek(plik,0,0);

fwrite(&BMP,sizeof(BMP),1,plik);

fseek(plik,BMP.bitmap_offset,0);

fwrite(tablica,sizeof(char),BMP.bitmap_size,plik);

fclose(plik);


}



int main()

{

  BMP_header_reader();

  test();

    return 0;

}

jeżeli nie przepiszę same dane o pixelach, miejsce gdzie powinien byc nagłówek, zostaje zastąpiony zerami. Jeżeli przepiszę także cały nagłówek (struct BMP), nagłówek przepisuje się błędnie:

nagłówek pliku przed wykonaniem programu:

bcba210ffc347167m.png

i po:

d24e7c443e92ae47m.png

Widać że pierwsze 2 bajty nagłówka przepisane są prawidłowo, a reszta jest przesunięta o 2 bajty;/

Co robię źle?

Czym można zastąpic funkcję fwrite, żeby dało się przepisać same dane o kolorach bez kasowania nagłówka?


([alex]) #2

Jeżeli chcesz nadpisać część pliku to otwórz w trybie rb+: plik=fopen("test.bmp","rb+");

Nie wiem czemu odczytujesz składowe po kolei zamiast: fread(&BMP,sizeof(BMP),1,plik);

Przesunięcie wynika z wyrównania:

type zajmuje dwa bajty więc wydawać się mogło że size ma przesunięcie dwa bajty odnośnie początku struktury, ale ze względu na wyrównanie size ma przesunięcie cztery bajty.

Kontrola przesunięcia niestety jest różna w różnych kompilatorach, np:

  • Visual __declspec(align(8)) struct bmp_file_header { ...

  • gcc struct ... { ... } __attribute__ ((__packed__));

  • w niektórych kompilatorach działa też #pragma pack(1)


(Przemekbaranowski) #3

kurcze dziwna sprawa - rozpisałem funkcję fwrite, która zapisywała nagłówek na pomniejsze funkcje zapisujące po jednym elemencie struktury nagłówka i wszystko zadziałało jak należy.

Też mnie dziwi dlaczego nie mogłem użyć pojedyńczego fread albo fwrite;/


([alex]) #4

Przecież ci wyjaśniłem dla czego - wyrównanie.


(Monczkin) #5

Przebar , nazwij proszę temat konkretnie, bez zbędnych problemów w tytule. Inaczej wyciągnę konsekwencje. Przeczytaj proszę ten temat. viewtopic.php?f=16&t=394978