Bitmap lesen und schreiben
-
Hallo,
ich möchte eine Bitmap Datei einlesen, diese dann verändern und wieder speichern. Ich habe auch schon 3 oder 4 Beispiele gefunden, die sich entweder erst garnich kompilieren lassen oder nichts vernünftiges tun.Das große Problem ist eigentlich das Einlesen. Dazu verwende ich 2 Strukturen
struct BITMAPFILEHEADER { unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; }; struct BITMAPINFOHEADER { unsigned long biSize; unsigned long biWidth; unsigned long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; unsigned long biXPelsPerMeter; unsigned long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; };Mit
fp = fopen(filename, "rb")öffne ich die Datei zum binären lesen und mit
fp = fopen(filename, "wb")eine andere Datei zum binären schreiben.
Mit
fread(&FileHeader, sizeof(FileHeader), 1, fp) fread(&InfoHeader, sizeof(InfoHeader), 1, fp)lese ich dann das Bild ein.
Wenn ich aber dann mit
fwrite(&FileHeader, sizeof(FileHeader), 1, fp)den Dateiheader in eine andere Datei übertrage, kommt nur das "MB" am Anfang an. Alles andere sieht eher zufällig aus, obwohl ich es vorher auf 0 gesetzt habe.
Ich hoffe, jemand hat nen Tip
Gruß
jabaa
-
Wie wäre es wenn du statt zweimal
fpfür verschiedene Dateien,fpReadundfpWritenimmst? So holst du dir 2 Handels auf Files die dann zT gelesen und zT geschrieben werden .. das da murks bei rumkommt ist nicht verwunderlich
Falls du das natürlich alles in der richtigen Reihenfolge machst, dann brauchen mer mehr Code
Ich nehme mal einfach an das du die Datei auf dem selben Rechner erstellst und es daher nichts mit Endianess zu tun haben kann ...
-
Ja ne sorry, aber ich hab das eben so ausm Quelltext kopiert. Im ganzen gibts ne Methode
void Bitmap::LoadBitmap(const char *filename){ FILE *fp; ...}zum einlesen und eine Methode
void Bitmap::SaveBitmap(const char *filename){ FILE *fp; ...}zum schreiben. Somit hat das eine fp nen anderen Gültigkeitsbereich als das andere fp
-
Hier ein minimal Beispiel:
Bitmap.hpp#ifndef BITMAP_H #define BITMAP_H typedef unsigned short WORD; typedef unsigned long DWORD; typedef unsigned long LONG; #include "fstream" class Bitmap { public: void LoadBitmap(const char *Filename); void SaveBitmap(const char *Filename); void *bits; //BITMAPFILEHEADER typedef struct { WORD bfType; DWORD bfSize; DWORD bfReserved; DWORD bfOffBits; }BITMAPFILEHEADER; //BITMAPINFOHEADER typedef struct { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; }BITMAPINFOHEADER; BITMAPFILEHEADER FileHeader; typedef struct { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; }BITMAPINFOHEADER; BITMAPFILEHEADER FileHeader; BITMAPINFOHEADER InfoHeader; }; #endif // BITMAP_HBitmap.cpp
#include "Bitmap.hpp" #include <stdlib.h> #include <iostream> void Bitmap::LoadBitmap(const char *filename) { FILE *fp; int bitsize; int infosize; if ((fp = fopen(filename, "rb")) == NULL) return; if (fread(&FileHeader, sizeof(FileHeader), 1, fp) < 1) { fclose(fp); return; } if (FileHeader.bfType != 'MB') { fclose(fp); return; } infosize = FileHeader.bfOffBits - sizeof(FileHeader); infosize = 40; if (fread(&InfoHeader, infosize, 1,fp) < infosize) { fclose(fp); return; } if ((bitsize = InfoHeader.biSize) == 0) bitsize = (InfoHeader.biWidth * InfoHeader.biBitCount + 7) / 8 * abs(InfoHeader.biHeight); if ((bits = malloc(bitsize)) == NULL) { fclose(fp); return; } if (fread(bits, 1, bitsize, fp) < bitsize) { fclose(fp); return; } fclose(fp); return; } void Bitmap::SaveBitmap(const char *Filename) { FILE *File=NULL; File=fopen(Filename,"wb"); fwrite(&FileHeader,sizeof(BITMAPFILEHEADER),1,File); fwrite(&InfoHeader,sizeof(BITMAPINFOHEADER),1,File); fclose(File); };main.cpp
#include <iostream> #include <fstream> #include <cstdlib> #include "Bitmap.hpp" int main(){ Bitmap bmp; bmp.LoadBitmap("penguins.bmp"); bmp.SaveBitmap("penguins_cod.bmp"); return 0; }
-
Und hier die Header:
Original: 424D 36C0 0000 0000 0000 3600 0000 2800 0000 8000 0000 8000 0000 0100 1800 0000 0000 00C0 0000 130B 0000 130B 0000 0000 0000 0000 0000 Kopie: 424D FE0A 0000 0000 0000 3600 0000 2800 0000 1E00 0000 1E00 0000 0100 1800 0000 0000 C80A 0000 0000 0000 0000 0000 0000 0000 0000 0000 7D7EStellenweise passt es. Aber allein dass der Header länger geworden ist ist sehr komisch
-
Den Fehler machst du bei der Angabe von Byte-Anzahl deiner Elemente (z.B. Zeile 14 in bitmap.cpp des letzten Beitrags). Es sollte heißen:
fwrite(&FileHeader, 1, sizeof(FileHeader), fp)
-
Die Reihenfolge ändert das Ergebnis garnicht. Ob jetzt 40 x 1 Byte in die Struktur geschrieben wird oder 1 x 40 Byte ist wohl nicht so der Unterschied. Hat auf jeden nix geändert
-
Was hat denn "sizeof(FileHeader)" für einen Wert? Laut http://de.wikipedia.org/wiki/Windows_Bitmap muß dabei ja 14 rauskommen.
Ich tippe darauf, daß das Standard-Padding bei deinem Compiler einen zu hohen Wert hat. Beim MSVC gibt es die "#pragma pack(x)"-Anweisung dafür (beim gcc weiß ich nicht, ob der das auch so unterstützt).
-
Was soll denn eigentlich das hier bewirken:
infosize = FileHeader.bfOffBits - sizeof(FileHeader); infosize = 40;Du berechnest erst die Headergröße und überschreibst den Wert sofort wieder. Und beim Schreiben nimmst du auch wieder eine (möglicherweise andere) Header-Größe an.
PS: HAst du schon mal an fstream gedacht?
-
Wie wärs mit C++ (hat CStoll schon gesagt)?
-
Da infosize zunächst noch nich richtig eingelesen werden kann, setz ich den Wert manuell auf 40, was meiner Meinung nach ein korrekter Wert ist.
Mit fstream hab ichs auch versucht. Da kam ähnlicher Mist bei raus. Ganz ganz komisch. Gibt es keine fertigen Packete für sowas? Ich muss es ja nich unbedingt selbst schreiben. Aber ich kann auch im Internet nix finden.
Gruß
jabaa
-
Deswegen solltest du trotzdem mal prüfen, ob die beiden Header-Strukturen die richtige Größe haben. Wenn dein Compiler dort einige Füll-Bytes einbaut, um die Elemente besser im Speicher ausrichten zu können, passt die Daten-Anordnung nicht mehr zum Dateiinhalt.
-
Hallo jabaa,
hast du meinen Beitrag nicht gelesen oder aber nicht verstanden, was ich dir mit "Padding" nahelegen wollte?
So wie CStoll geschrieben hat, baut der Compiler (aus Performance-Gründen) einige Füll-Bytes ("Padding") ein, um z.B. Integer auf einer durch 4 teilbaren Adresse abzulegen.
Um das Abzustellen, gibt es die '#pragma pack(1)' - Direktive (aber wie schon geschrieben, je nach Compiler etwas modifiziert)...Und mein Link zeigt eine Bitmap-Leseroutine aus diesem Forum...