diverse Fragen zu Bildformat einlesen
-
lemon03 schrieb:
Bin noch beim Überlegen ...
Du hast doch vier Bytes ausgegeben, die zu biWidth gehören.
Wo soll denn da der lange Wert her kommen?Ich habe die Ausgabe nur ganz kurz gesehen, da sich bei abload.de gleich wieder ein Fenster/Popup davor gesetzt hat. Und auf solchen Seite klicke ich nichts an.
Copy&Paste der Konsole mit Code-Tags geht auch.Das sieht dann so aus:
Microsoft Windows [Version 10.0.10586] (c) 2015 Microsoft Corporation. Alle Rechte vorbehalten. C:\>Und jeder kann es lesen.
-
lemon03 schrieb:
@ dirkski
Danke für die Anregungen, aber die momentane Ausgabe soll nur dazu dienen, überhaupt in eine solche Bitmap-Struktur durchzusteigen, also erst mal alle Werte laut Tabelle nachvollziehbar auszugeben.
Später interessieren mich nur die Farbwerte.
Ok, würde aber evtl. einfacher gehen auf die Member zuzugreifen...
Hier als Vorschlag (ist nicht perfekt):
#include <string> #include <iostream> #include <fstream> #include <iomanip> #include <exception> struct BMPFileHeader { uint16_t bfType; // ASCII-Zeichenkette "BM" (Hex: 0x42 0x4D Dez: 19778). uint32_t bfSize; // Größe der BMP-Datei in Byte. (unzuverlässig) uint32_t bfReserved; // Reserviert, von der Software abhängig, standardmäßig 0 uint32_t bfOffBits; // Offset der Bilddaten in Byte vom Beginn der Datei an, bei Echtfarben fast immer 54 (manche Software ignoriert diese Angabe daher fehlerhafterweise). }; struct BMPInfoHeader { uint32_t biSize; // 40 (Größe der BITMAPINFOHEADER-Struktur in Byte) int32_t biWidth; // Breite der Bitmap in Pixel. int32_t biHeight; // Der Betrag gibt die Höhe der Bitmap in Pixel an. // Ist der Wert positiv, so ist die Bitmap eine sogenannte "bottom-up"-Bitmap // (die Bilddaten beginnen mit der untersten und enden mit der obersten Bildzeile). // Dies ist die gebräuchlichste Variante. // Ist der Wert negativ, so ist die Bitmap eine "top-down"-Bitmap // (die Bilddaten beginnen mit der obersten und enden mit der untersten Bildzeile). uint16_t biPlanes; // 1 (Stand in einigen älteren Formaten wie PCX für die Anzahl der Farbebenen, // wird aber für BMP nicht verwendet) uint16_t biBitCount; // Gibt die Farbtiefe der Bitmap in bpp an; muss einer der folgenden Werte sein: // 1, 4, 8, 16, 24 oder 32. Bei 1, 4 und 8 bpp sind die Farben indiziert. uint32_t biCompression; // Einer der folgenden Werte: // 0 (BI_RGB): Bilddaten sind unkomprimiert. // 1 (BI_RLE8): Bilddaten sind lauflängenkodiert für 8 bpp. Nur erlaubt wenn biBitCount=8 und biHeight positiv. // 2 (BI_RLE4): Bilddaten sind lauflängenkodiert für 4 bpp. Nur erlaubt wenn biBitCount=4 und biHeight positiv. // 3 (BI_BITFIELDS): Bilddaten sind unkomprimiert und benutzerdefiniert (mittels Farbmasken) kodiert. Nur erlaubt wenn biBitCount=16 oder 32. uint32_t biSizeImage; // Wenn biCompression=BI_RGB: Entweder 0 oder die Größe der Bilddaten in Byte. // Ansonsten: Größe der Bilddaten in Byte. int32_t biXPelsPerMeter; // Horizontale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt. int32_t biYPelsPerMeter; // Vertikale Auflösung des Zielausgabegerätes in Pixel pro Meter; wird aber für BMP-Dateien meistens auf 0 gesetzt. uint32_t biClrUsed; // Wenn biBitCount=1: 0. // Wenn biBitCount=4 oder 8: die Anzahl der Einträge der Farbtabelle; 0 bedeutet die maximale Anzahl (2, 16 oder 256). // Ansonsten: Die Anzahl der Einträge der Farbtabelle (0=keine Farbtabelle). Auch wenn sie in diesem Fall nicht notwendig ist, kann dennoch eine für die Farbquantisierung empfohlene Farbtabelle angegeben werden. uint32_t biClrImportant; // Wenn biBitCount=1, 4 oder 8: Die Anzahl sämtlicher im Bild verwendeten Farben; 0 bedeutet alle Farben der Farbtabelle. // Ansonsten: // Wenn eine Farbtabelle vorhanden ist und diese sämtliche im Bild verwendeten Farben enthält: deren Anzahl. // Ansonsten: 0. }; struct BMP { BMPFileHeader head; BMPInfoHeader info; }; std::istream & operator>>(std::istream & is, BMPFileHeader & head) { std::cerr << __func__ << " (BMPFileHeader): "; if(is.good()) is.read(reinterpret_cast<char*>(&head.bfType), sizeof(uint16_t) ); if(is.good()) is.read(reinterpret_cast<char*>(&head.bfSize), sizeof(uint32_t)*3 ); // bfSize ... bfOffBits = 3* if(!is.good()) { std::cerr << "read error (BMPFileHeader)!\n"; return is; } std::cerr << " bfType = " << head.bfType << ", bfSize = " << head.bfSize << ", bfReserved = " << head.bfReserved << ", bfOffBits = " << head.bfOffBits << " (is.tellg() = " << is.tellg() << ")\n"; return is; } std::istream & operator>>(std::istream & is, BMPInfoHeader & info) noexcept { std::cerr << __func__ << " (BMPInfoHeader): "; if( is.good()) is.read(reinterpret_cast<char*>(&info), sizeof(uint32_t)*3 ); if( is.good()) is.read(reinterpret_cast<char*>(&info.biPlanes), sizeof(uint16_t)*2 ); if( is.good()) is.read(reinterpret_cast<char*>(&info.biCompression), sizeof(uint32_t)*6 ); if(!is.good()) { std::cerr << "read error (BMPInfoHeader)!\n"; return is; } std::cerr << " biSize: " << info.biSize << ", biWidth: " << info.biWidth << ", biHeight: " << info.biHeight << ", biPlanes: " << info.biPlanes << ", biBitCount: " << info.biBitCount << ", biCompression: " << info.biCompression << " (is.tellg() = " << is.tellg() << ")\n"; return is; } std::istream & operator>>(std::istream & is, BMP & bmp) { std::cerr << __func__ << " (BMP): "; is >> bmp.head >> bmp.info; if(!is.good()) { std::cerr << "read error (BMP)!\n"; return is; } return is; } int main(int argc, char *argv[]) { std::string filename; if( argv[1]) filename = argv[1]; else filename = "/usr/share/xml/docbook/stylesheet/nwalsh/1.78.1/slides/slidy/graphics/unfold.bmp"; std::ifstream file (filename.c_str(), std::ios::binary|std::ios::in); // BMPFileHeader head; // if (file.good()) // file >> head; // BMPInfoHeader info; // if (file.good()) // file >> info; BMP bmp; if (file.good()) file >> bmp; // while (file.get(byte)) picmap.push_back(byte); return EXIT_SUCCESS; }Die structs habe ich einfach aus wp kopiert und alles überflüssige gelöscht bzw. Kommentare eingefügt.
Ob die Lese-Routine mit den vielen reads jetz gut ist weiß ich nicht (auf die Performance bezogen)...
cu
-
biHeightals Höhe der Bitmap wird ja korrekt in Pixel ausgegeben.Nur wenn bei mir irgendwo ein mir nicht nachvollziehbarer Fehler auftaucht, klappt gleich gar nichts mehr. Wollte jetzt casten, um zu schauen, ob ohne Vorzeichen bei
biWidthder Wert auch korrekt ist, aber bekomme wieder irgendwelche Fehlermeldungen wegen fehlenden Semikolon und son Kram ... nerv
-
@ nochmal dirkski
Uh, danke für die Mühe
Auf den ersten Blick sieht das in etwa so aus, wie ich es auch mal vor Augen hatte, nur wie das ausgeschrieben wird, war mir unklar. Aber ich müsste mich in das Beispiel etwas einarbeiten, denn einiges ist mir nicht sofort bekannt.Aber im Moment habe ich ja noch Schwierigkeiten mit meinem eigenen Code, dessen Fehler ich erst mal verstehen muss, bevor ich mich an komplexere wage.
-
dirkski schrieb:
#include <string> #include <iostream> #include <fstream> #include <iomanip> #include <exception> [...] std::istream & operator>>(std::istream & is, BMPFileHeader & head) { std::cerr << __func__ << " (BMPFileHeader): "; if(is.good()) is.read(reinterpret_cast<char*>(&head.bfType), sizeof(uint16_t) ); if(is.good()) is.read(reinterpret_cast<char*>(&head.bfSize), sizeof(uint32_t)*3 ); // bfSize ... bfOffBits = 3* if(!is.good()) { std::cerr << "read error (BMPFileHeader)!\n"; return is; } std::cerr << " bfType = " << head.bfType << ", bfSize = " << head.bfSize << ", bfReserved = " << head.bfReserved << ", bfOffBits = " << head.bfOffBits << " (is.tellg() = " << is.tellg() << ")\n"; return is; } [...]Da wo jetzt die Ausgaben mit std::cerr sind kannst du bequem eine Plausibilitätsprüfung einfügen. Falls die fehlschlägt einfach das failbit vom stream setzen und mit return den inputstream zurückgeben... So gesehen braucht man nicht alle Prüfungen auf stream.good() zu machen (Eigentlich keine?). Geht also kürzer, mein ich...
-
Oh, das mit abload tut mir leid. Bei mir poppt trotz Akzeptanz aller scripte nichts auf.
Aber hier der Inhalt, wie es im Moment ausschaut:
_Head_ #0 bfType 42 4d 19778 #2 bfSize 36 40 2 0 147510 #6 bfReserved 0 0 0 0 0 #10 bfOffbits 36 4 0 0 1078 _Info_ #14 biSize 28 0 0 0 40 #18 biWidth ffffffa0 1 0 0 160 #22 biHeight 60 1 0 0 352 #26 biPlanes 1 0 1 #28 biBitCount 8 0 8 #30 biCompression 0 0 0 0 0 #34 biSizeImage 0 0 0 0 0 #38 biXPelsPerMeter 23 2e 0 0 11811 #42 biYPelsPerMeter 23 2e 0 0 11811 #46 biClrUsed 0 1 0 0 256 #50 biClrImportant 0 1 0 0 256 Process returned 0 (0x0) execution time : 0.026 s Press any key to continue.Die dritte Spalte sind jetzt die Dezimalwerte.
-
lemon03 schrieb:
@ nochmal dirkski
Uh, danke für die Mühe
Auf den ersten Blick sieht das in etwa so aus, wie ich es auch mal vor Augen hatte, nur wie das ausgeschrieben wird, war mir unklar. Aber ich müsste mich in das Beispiel etwas einarbeiten, denn einiges ist mir nicht sofort bekannt.Aber im Moment habe ich ja noch Schwierigkeiten mit meinem eigenen Code, dessen Fehler ich erst mal verstehen muss, bevor ich mich an komplexere wage.
Ok

Eigentlich brauchst du auch nur einen operator>> (oder einfach eine Funktion) überladen bzw. schreiben.
Das ich jetzt jeweils einen für Head und Info habe und dann einen für das gesamte kam dadurch das ich halt erst mit Head angefangen habe.
Falls du es noch nicht so hast mit operator-Überladung nehme doch einfach eine Funktion ala decodeBMP(istream);
Mach jetzt etwas Pause...
PS: das noexcept irgendwo bei mir im Code sollte wieder raus...
-
So erst mal sorry für das Durcheinander meiner Beträge hier ...

Habe jetzt ein anderes bmp genommen bzw dazu konvertiert und diesmal gibt es keine Ungereimtheiten bei den Werten. Passt alles, wie es auch in den Eigenschaften der Datei steht. Hatte ich wohl anfangs ein schlechtes Beispiel gewählt.
Nur mit dem Wert 'Auflösung des Zielausgabegerätes in Pixel pro Meter' kann ich noch nichts anfangen, aber ist wohl eher vernachlässigbar.
Mache jetzt erst mal mit der Formatierung der Ausgabe weiter bis ich das verdammt noch mal begriffen habe ...
Dann schaue ich mir den Code von dirkski an, und dann geht es weiter mit den Farbmasken, -tabellen und Bilddaten.
-
lemon03 schrieb:
Dann schaue ich mir den Code von dirkski an, und dann geht es weiter mit den Farbmasken, -tabellen und Bilddaten.
Ich schreib dir gerade eine Zusammenfassung wie ich vorgegangen bin, damit ich auch noch was lerne
kannst dir also noch etwas Zeit lassen...
-
Natürlich ... soll ja schließlich nicht in Arbeit ausarten

-
lemon03 schrieb:
Natürlich ... soll ja schließlich nicht in Arbeit ausarten

Nein nein, ist aber trotzdem was länger geworden

Also, ich bin so grob folgendermaßen vorgegangen:
Ich hab mir den Wikipedia-Artikel angeguckt und habe zuerst
gesehen das „Dateikopf“ und „Informationsblock“ keinerlei
dynamische Daten enthält (also alles fest). Wenn das so ist
kann man das normalerweise 1:1 in eine struct übernehmen.
In den Windows-Quellen wird es wahrscheinlich genau so eine struct
geben. Also hab ich mir mit Copy&Paste eine erstellt:struct BMPFileHeader { uint16_t bfType; // ASCII-Zeichenkette "BM" (Hex: 0x42 0x4D Dez: 19778). uint32_t bfSize; // Größe der BMP-Datei in Byte. (unzuverlässig) uint32_t bfReserved; // Reserviert, von der Software abhängig, standardmäßig 0 uint32_t bfOffBits; // Offset der Bilddaten in Byte vom Beginn der Datei an, bei Echtfarben fast immer 54 (manche Software ignoriert diese Angabe daher fehlerhafterweise). };Dann habe ich mir gedacht, jetzt wo du sie hast kannst du einfach mit
std::ifstream file ("file.bmp", std::ios::binary|std::ios::in); BMPFileHeader head; file.read(reinterpret_cast<char*>(&head), 14 ); // Dateikopf ist 14 Bytes großdie struct mit den ersten 14 Bytes füllen. Ergebnis war aber falsch:
bfType gab noch das richtige zurück (19778 = "BM"), der Rest war schrott...Das Problem: bfType ist nur 16Bit breit. Da das hier eine 64Bit-Maschine
ist fügt der Compiler nach BMPFileHeader.bfType noch 2 Bytes ein um die
nachfolgenden 32-Bit-Werte auf eine 4 Byte-Grenze auszurichten. Dumm gelaufen....Daher bin ich dann im nächsten Schritt anders vorgegangen:
// Die ersten 2 Bytes ab Adresse &head.bfType einlesen ( ist gleich &head) if(file.good()) file.read(reinterpret_cast<char*>(&head.bfType), sizeof(uint16_t) ); // die nächsten 3 uint32_t (oder int32_t) ab Adresse von bfSize schreiben if(file.good()) file.read(reinterpret_cast<char*>(&head.bfSize), sizeof(uint32_t)*3 ); // bfSize ... bfOffBits = 3*So, jetzt habe ich die einzelnen Werte in der struct wo sie stehen sollen
und ich kann bequem z.B. mit head.bfSize darauf zugreifen...
Anmerkungen:
1: Eigentlich müste man jeden member der struct einzeln einlesen, theoretisch
könnten auf 128Bit-Maschinen (gibt's die?) auch Padding-Bytes sein.
2: Das Byteweise einlesen und in einen short/int/long speichern
könnte Probleme mit big-/little-endian auf anderen Architekturen geben.Jetzt könnte man das in eine Funktion packen:
std::basic_ios::rdstate fillBMPFileHeader(std::istream & is, BMPFileHeader & head) { // Die ersten 2 Bytes ab Adresse &head.bfType einlesen ( ist gleich &head) if(is.good()) is.read(reinterpret_cast<char*>(&head.bfType), sizeof(uint16_t) ); // die nächsten 3 uint32_t (oder int32_t) ab Adresse von bfSize schreiben if(is.good()) is.read(reinterpret_cast<char*>(&head.bfSize), sizeof(uint32_t)*3 ); // bfSize ... bfOffBits = 3* // Hier jetzt noch Pausibilitätsprüfungen, z.B.: if( head.bfType != 19778) // != "BM" is.setstate(std::ios_base::failbit); return is.rdstate(); }und mit:
int main(int argc, char**argv) { std::ifstream file ("file.bmp", std::ios::binary|std::ios::in); BMPFileHeader head; if( ! fillBMPFileHeader(file, head) ) { std::cerr << "error\n"; return 1;} std::cout << "File size: " << head.bfSize << "\n"; return 0; }z.B. aufrufen. Oder gleich den operator>> von ifstream überladen:
std::istream & operator>>(std::istream & is, BMPFileHeader & head) { // Die good()-Abfragen kann man sich evtl. sparen, Im Fehlerfall werden // ein paar read() mehr aufgerufen, sonst dürfte aber nichts passieren (glaub). // Im Erfolgsfall wird minimal weniger Code ausgeführt... if(is.good()) is.read(reinterpret_cast<char*>(&head.bfType), sizeof(uint16_t) ); if(is.good()) is.read(reinterpret_cast<char*>(&head.bfSize), sizeof(uint32_t)*3 ); // bfSize ... bfOffBits = 3* if(is.good()) { // Pausibilitätsprüfungen, bei Fehler failbit des streams setzen. Z.B.: if( head.bfType != 19778) // != "BM" is.setstate(std::ios_base::failbit); } return is; }Weil mit dem überladenen Operator>> man jetzt sowas machen kann:
int main(int argc, char**argv) { std::ifstream file ("file.bmp", std::ios::binary|std::ios::in); BMPFileHeader head; file >> head; if( ! file.good() ) // oder *glaube* einfach if (file) { std::cerr << "error\n"; return 1;} std::cout << "File size: " << head.bfSize << "\n"; return 0; }Wenn du dann das selbe für den Info-Teil machst kannst du dann sowas wie:
BMPFileHeader head; BMPInfoHeader info; file >> head >> info;machen. So habe ich das dann in dem dritten überladenen operator>>
gemacht.Ich bin übrigens der Meinung das man die beiden structs (head & info)
in eine zusammen legen sollte. Dann geht die Plausibilitätsprüfung
einfacher, also ob das Format richtig ist usw...So genug geschrieben. die Sniplets sind entweder Copy&Paste aus
meinen Code oder ungetestet eingegeben. Siehe es also als Pseudocode an
Für die Farbwerte und die eigentlichen Bilddaten bist du dann aber mit
std::vector etc. richtig. Das müste dann auch in die (Haupt)-struct,
also z.B. struct BMP (oder class)...Hmm, so ala:
class BMP { BMPHeader head; // hier head und info zusammen [...] // Bitmasken, Farbtabellen und Bilddaten public: BMP(std::string filename); BMP(std::ifstream & file); }So, hab hunger.
Einen schönen Abend noch
-
dirkski schrieb:
Anmerkungen:
1: Eigentlich müste man jeden member der struct einzeln einlesen, theoretisch
könnten auf 128Bit-Maschinen (gibt's die?) auch Padding-Bytes sein.
2: Das Byteweise einlesen und in einen short/int/long speichern
könnte Probleme mit big-/little-endian auf anderen Architekturen geben.Bei allen Architekturen die ich kenne reicht es eigentlich wenn Variablen entsprechend ihrer eigenen Größe ausgerichtet sind. Also ein
uint32_tdürfte nur an Adressen stehen die durch 4 teilbar sind usw.. Man kann übrigens den Compiler durch diverse compilerabhängige Erweiterungen auch dazu bringen gar kein Padding einzubauen. Die meisten Architekturen (x86, neuere ARM) kommen damit auch klar, ist nur eventuell langsamer. Das ist nicht gerade die beste Lösung, wollte es aber der Vollständigkeit halber noch erwähnen.Endianness kann natürlich auch ein Problem sein. Zwar sind Big-Endian Maschienen so gut wie ausgestorben, vor allem bei diversen Netzwerkprotokollen wird es aber noch gerne verwendet. Für ein aktuelles Projekt (in C) habe ich mir diverse Funktionen (dtoh für Device to Host) gebastelt um die Member einzelnd lesen zu können. Sieht dann so aus:
const uint8_t* data = ...; obj->storageID = dtoh32(&data); obj->objectFormat = dtoh16(&data); obj->protectionStatus = dtoh16(&data); obj->objectSize = dtoh32(&data); obj->thumbFormat = dtoh16(&data); obj->thumbSize = dtoh32(&data); // usw...Wäre das Projekt ein C++ Projekt gewesen hätte ich dafür wohl irgendeine Klasse gebaut die binär Zeug lesen kann und den
operator>>überladen. Da hätte der gleiche Code danndata >> obj->storageID >> obj->objectFormat >> obj->protectionStatus >> obj->objectSize >> obj->thumbFormat >> obj->thumbSize >> ...oder so ausgesehen. Das angeben der richtigen Größe in C ist schon ziemlich nervig.
-
gelöscht - Doppelpost
-
Oho, na vielen Dank
und für die weiteren Anmerkungen von sebi707 
Werde ich auf jeden Fall mal durcharbeiten und ausprobieren.Wollte nur kurz anmerken, das durch das Casten inzwischen auch beim ersten Pic die grundlegenden Wert korrekt dargestellt werden. Bei neuen Bildern, die ich mit einem aktuellen Programm zu bmp konvertiere sind dann wirklich alle Werte (jedenfalls die Eigenschaften des Bild und entsprechende Anmerkungen in der Tabelle) übereinstimmend.
-
sebi707 schrieb:
Wäre das Projekt ein C++ Projekt gewesen hätte ich dafür wohl irgendeine Klasse gebaut die binär Zeug lesen kann und den
operator>>überladen. Da hätte der gleiche Code danndata >> obj->storageID >> obj->objectFormat >> obj->protectionStatus >> obj->objectSize >> obj->thumbFormat >> obj->thumbSize >> ...oder so ausgesehen. Das angeben der richtigen Größe in C ist schon ziemlich nervig.
Hallo sebi707,
wenn man die Klasse nur zum auslesen braucht, sollte sie dann von std::basic_ifstream abgeleitet sein?Und was wenn sie zum manipulieren von Dateiinhalten gedacht ist,
von std::basic_fstream für I/O?Bin selbst nicht so firm in solchen Fragen, würde mir aber so in den Sinn kommen.
Einen schönen Abend noch
-
dirkski schrieb:
sebi707 schrieb:
Wäre das Projekt ein C++ Projekt gewesen hätte ich dafür wohl irgendeine Klasse gebaut die binär Zeug lesen kann und den
operator>>überladen. Da hätte der gleiche Code danndata >> obj->storageID >> obj->objectFormat >> obj->protectionStatus >> obj->objectSize >> obj->thumbFormat >> obj->thumbSize >> ...oder so ausgesehen. Das angeben der richtigen Größe in C ist schon ziemlich nervig.
Hallo sebi707,
wenn man die Klasse nur zum auslesen braucht, sollte sie dann von std::basic_ifstream abgeleitet sein?Und was wenn sie zum manipulieren von Dateiinhalten gedacht ist,
von std::basic_fstream für I/O?Bin selbst nicht so firm in solchen Fragen, würde mir aber so in den Sinn kommen.
Einen schönen Abend noch
Hmm, ich denk mir gerade das es eigentlich Blödsinn ist, oder?
Mann will ja manipulieren? Hmm, ist ein z.B. PNG ein stream? Ja, auch.
Im Bildbearbeitungsprogramm ist es nur noch ein Bild. Im 3d-Renderer eine Textur im Grafikspeicher. Wie gesagt ich tu mich mit solchen Fragen immer etwas schwer
-
Ich hätte es wohl gar nicht von einer der Standard Stream Klassen abgeleitet sondern stattdessen eine Referenz oder Pointer auf eine solche gespeichert, weil ich mir die ganzen Standard Operatoren nicht reinholen will. Ich würde dann einen
operator>>haben der nur ints (signed und unsigned in allen Größen) lesen kann und die dann immer binär mit .read aus dem Stream ließt. Wenn man möchte kann man dann noch Endianness behandeln.Und zu
fstreamoderiostream: Irgendwie hatte ich bisher noch nie das Bedürfnis eine Datei gleichzeitig lesen und schreiben zu können.
-
sebi707 schrieb:
Ich hätte es wohl gar nicht von einer der Standard Stream Klassen abgeleitet sondern stattdessen eine Referenz oder Pointer auf eine solche gespeichert, weil ich mir die ganzen Standard Operatoren nicht reinholen will. Ich würde dann einen
operator>>haben der nur ints (signed und unsigned in allen Größen) lesen kann und die dann immer binär mit .read aus dem Stream ließt. Wenn man möchte kann man dann noch Endianness behandeln.Hört sich gut an, werde mal sowas zum testen basteln. Hab ja schon angefangen, dabei sind ein paar Fragen aufgekommen die ich heute oder morgen mal in einen neuen Thread posten werde. Habe gerade ncht so viel Zeit...
sebi707 schrieb:
Und zu
fstreamoderiostream: Irgendwie hatte ich bisher noch nie das Bedürfnis eine Datei gleichzeitig lesen und schreiben zu können.Ok, ich bis jetzt auch nicht
Ich dachte zum manipulieren, aber lesen > manipulieren > schreiben geht auch mit 2 streams... Es war aber nur so eine Idee wo ich mir nicht so viele Gedanken gemacht habe...Edit: Ich habe (hatte) eine Klasse BMP_ifstream abgeleitet von std::ifstream.
Damit klappte es ganz gut, operator>> hab ich für uint32_t etc. (template) überladen, dann für die beiden structs BMPFileHeader und BMPInfoHeader.Jetzt habe ich das versucht nach deinen Vorschlag zu ändern, also Klasse
nicht abgeleitet und stattdessen std::ifstream als member (Referenz). Nur wie überlade ich dann den operator>> korrekt. Hab da jetzt eine Schere im Kopf....
-
Damit klappte es ganz gut, operator>> hab ich für uint32_t etc. (template) überladen, dann für die beiden structs BMPFileHeader und BMPInfoHeader.
es macht bei einem Stream Sinn mehrfach einen int zu lesen
also
ifs >> x;
ifs >> y;
ifs >> z;weil man ja immer weiter lesen kann - und der Stream-Pointer sich ja auch dann weiterbewegt
aber fuer einen BMP-Header der Fix immer am Anfang der Datei steht macht das irgendwie wenig Sinn
ifs >> bmp_header;
ifs >> bmp_header;
ifs >> bmp_header;wird so niemals jemand schreiben wollen
da muss der Stream zwangslauefig am Anfang stehen oder dort hin gesetzt werden und danach wieder an seinen alten Platz - hört sich so gar nicht nach "Stream" an
ich wuerde das lassen - eher Teile der BMP als Stream abstrahieren - aber nicht das ganze
-
Gast3 schrieb:
Damit klappte es ganz gut, operator>> hab ich für uint32_t etc. (template) überladen, dann für die beiden structs BMPFileHeader und BMPInfoHeader.
es macht bei einem Stream Sinn mehrfach einen int zu lesen
also
ifs >> x;
ifs >> y;
ifs >> z;weil man ja immer weiter lesen kann - und der Stream-Pointer sich ja auch dann weiterbewegt
aber fuer einen BMP-Header der Fix immer am Anfang der Datei steht macht das irgendwie wenig Sinn
ifs >> bmp_header;
ifs >> bmp_header;
ifs >> bmp_header;wird so niemals jemand schreiben wollen
da muss der Stream zwangslauefig am Anfang stehen oder dort hin gesetzt werden und danach wieder an seinen alten Platz - hört sich so gar nicht nach "Stream" an
ich wuerde das lassen - eher Teile der BMP als Stream abstrahieren - aber nicht das ganze
Naja, ist ein erster Versuch zum einlesen, hab drauf los gebastelt.
Den operator>> kann ich ja eh nur innerhalb der Klasse verwenden. Zumindest wüste ich nicht wie man den für int, long etc außerhalb der Klasse überladen kann... Im Augenblick benutze ich die nur innerhalb des Konstruktors.Also sowas (gekürzt):
class BMP_ifstream : std::ifstream { BMPFileHeader head; BMPInfoHeader info; // Keine Ahnung ob das richtig ist, hab noch nie was mit std::move() gemacht. Müsste dann nicht der original-ifstream ungültig sein? Wäre schlecht BMP_ifstream(std::ifstream && is) : std::ifstream(std::move(is)) { std::cerr << __func__ << "(std::ifstream && is): \n"; *this >> head >> info; debug(); } BMP_ifstream(std::string filename) : BMP_ifstream(std::ifstream(filename)) { } BMP_ifstream & operator>>(BMPFileHeader & head) { return (*this >> head.bfType >> head.bfSize >> head.bfReserved >> head.bfOffBits); } BMP_ifstream & operator>>(BMPInfoHeader & info) { return (*this >> info.biSize >> info.biWidth >> info.biHeight >> info.biPlanes >> info.biBitCount >> info.biCompression >> info.biSizeImage >> info.biXPelsPerMeter >> info.biYPelsPerMeter >> info.biClrUsed >> info.biClrImportant); } template <typename T> // für uint16_t, uint32_t usw... BMP_ifstream & operator>>(T & t) { // std::istream::sentry sentry(*this); // if (sentry) this->read( reinterpret_cast<char*>(&t), sizeof(T) ); return *this; } };Edit:
Ich hab mal alle Konstruktoren rausgeschmissen und dann sowas gemacht:class BMP_ifstream : public std::ifstream { BMP_ifstream(const char* filename,ios_base::openmode mode = ios_base::in) : std::ifstream(filename, mode) { std::cerr << __func__ << "(std::ifstream & is): \n"; *this >> head >> info; debug(); } ... };solange ich keine Ahnung von std::move habe
