Fragen zu Windows Bitmap einlesen #2
-
war bestimmt nur ein Tippfehler ...
Ok, danke für die Hinweise. Wenn ich richtig verstanden habe, müssten die drei Funktionen dann so aussehen?:
uint16_t make_uint16(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint16_t const u_val = bmp_data.at(pos + 0) + (static_cast<uint16_t>(bmp_data.at(pos + 1)) << 8); return u_val; } uint32_t make_uint32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint32_t const u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int32_t make_int32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint32_t const u_val = make_uint32 (bmp_data, pos); if ((u_val >> 31) & 1) { return -static_cast<int32_t>(~u_val) - 1; } else { return u_val; } }Nur das doppelt ausschreiben in Deinem letzten Beitrag habe ich nicht ganz verstanden?
---
Ich hoffe, das wird jetzt nicht zuviel, aber ich hätte noch ein anderes Anliegen. Und zwar bin ich mit meiner switch-Lösung nicht ganz zufrieden. Ich würde lieber einen Funktionszeiger nehmen, bekomme das aber nicht hin.
Vorgestellt habe ich mir, das hier der second-Wert das Argument für den Zeiger sein soll. Welcher Typ das sein muss, ist mir unklar.
struct Head //Kopf { static const auto Size = 4; std::array <std::pair <std::string, int>, Size> bType { { { "bfType", 1 }, //uint16_t { "bfSize", 2 }, //uint32_t { "bfReserved", 2 }, { "bfOffbits", 2 } } }; std::array <int, Size> data; } head; //int (*make_data)(std::vector <unsigned char>, std::size_t);Unklar ist mir auch, wie eine Funktion mit diesem Argument dann aufgerufen wird. Ich hatte bisher nur einmal mit Funktionszeigern zu tun, mir fehlt die Übung und ich kann den ersten Einsatz nicht für diesen Fall nachvollziehen.
-
wob schrieb:
Gleichheitszeichen zwischen
returnund der Variablen finde ich wiederum merkwürdig - mein Compiler auch...Danke, hab's korrigiert.
-
lemon03 schrieb:
(...)müssten die drei Funktionen dann so aussehen?:
uint16_t make_uint16(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint16_t const u_val = bmp_data.at(pos + 0) + (static_cast<uint16_t>(bmp_data.at(pos + 1)) << 8); return u_val; } uint32_t make_uint32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint32_t const u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int32_t make_int32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { uint32_t const u_val = make_uint32 (bmp_data, pos); if ((u_val >> 31) & 1) { return -static_cast<int32_t>(~u_val) - 1; } else { return u_val; } }Sieht gut aus würde ich sagen.
lemon03 schrieb:
Nur das doppelt ausschreiben in Deinem letzten Beitrag habe ich nicht ganz verstanden?
Keine ahnung was du meinst. Steh vermutlich grad auf dem Schlauch

-
Danke. Meinte dies:
int32_t int32_from_uint32(uint32_t u_val) { if ((u_val >> 31) & 1) return -static_cast<int32_t>(~u_val) - 1; else return u_val; } int32_t make_int32(std::vector <unsigned char> const& bmp_data, std::size_t pos) { return int32_from_uint32(make_uint32(bmp_data, pos)); }Mir scheint das da zwei Funktionsteile genommen und daraus zwei Funktionen gemacht wurden?
-
Ja, genau. Und?
-
Dann würde aus
uint32_t make_uint32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint32_t u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int32_t make_int32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint32_t u_val = make_uint32(bmp_data, pos); if ((u_val >> 31) & 1) { return -static_cast<int32_t>(~u_val) - 1; } else { return u_val; } }-->
uint32_t make_uint32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint32_t u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int32_t int32_from_uint32(uint32_t u_val) { if ((u_val >> 31) & 1) return -static_cast<int32_t>(~u_val) - 1; else return u_val; } int32_t make_int32(std::vector <unsigned char> const& bmp_data, std::size_t pos) { return int32_from_uint32(make_uint32(bmp_data, pos)); }Die Aufsplittung auf zwei Funktionen verstehe ich vom Nutzen her nicht. Da die einzelnen Teile nirgendwo als in dieser Funktion gebraucht werden, finde ich das irgendwie überflüssig?
-
lemon03 schrieb:
Die Aufsplittung auf zwei Funktionen verstehe ich vom Nutzen her nicht. Da die einzelnen Teile nirgendwo als in dieser Funktion gebraucht werden, finde ich das irgendwie überflüssig?
Der Code wird übersichtlicher und du kannst die einzelnen Funktionen einfacher testen. Eine Funktion sollte für genau eine Sache verantwortlich sein, diese darf gerne klein sein.
-
Das mag allgemein so stimmen, aber doch im obigen Fall nicht?
Der erst Block mit zwei Funktionen ist doch leichter auf einen Blick zu erfassen, als der untere mit drei verschachtelten Funktionen?
Und im Programm werden drei Werte durch drei ganz einfache Funktionen bestimmt, warum sollte man diese drei einfachen Funktionen auf vier aufsplitten?
-
wob schrieb:
und du kannst die einzelnen Funktionen einfacher testen.
Da die oberen Funktionen alle voneinander abhängig sind, kann man doch gar nicht die einzelnen Funktionen testen, ohne auch die anderen zu testen?
Also warum nicht nur eine Funktion testen, statt zwei?
-
Also sorry, wollte nicht aufmüpfig erscheinen. Bin ja froh, wenn man mir hilft und erklärt.
Ich würde gerne noch mal auf den Funktionszeiger zurück kommen, ob das hier möglich und sinnvoll ist. Vorgestellt habe ich mir das mit sozusagen Pseudocode etwa so:
int (*make_dec)(std::vector <unsigned char> const, std::size_t); //hier const richtig? uint16_t m_uint16(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint16_t u_val = bmp_data.at(pos + 0) + (static_cast<uint16_t>(bmp_data.at(pos + 1)) << 8); return u_val; } uint32_t m_uint32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint32_t u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int32_t m_int32(std::vector <unsigned char> const &bmp_data, std::size_t pos) { const uint32_t u_val = make_uint32(bmp_data, pos); if ((u_val >> 31) & 1) { return -static_cast<int32_t>(~u_val) - 1; } else { return u_val; } } struct Head //Kopf { static const auto Size = 4; std::array <std::pair <std::string, |Typ?|>, Size> bType { { { "bfType", m_uint16 }, //uint16_t { "bfSize", m_uint32 }, //uint32_t { "bfReserved", m_uint32 }, { "bfOffbits", m_uint32 } } }; std::array <int, Size> data; } head; head.data.at(i) = Funktionsaufruf mit <head.bType.at(i).second>;Ich weiß leider nicht, wie ich das korrekt ausformuliere.
-
lemon03 schrieb:
Da die oberen Funktionen alle voneinander abhängig sind, kann man doch gar nicht die einzelnen Funktionen testen, ohne auch die anderen zu testen?
Naja die sind eben nicht voneinander abhängig. (Also schon die eine von der anderen, aber nicht die andere von der einen.)
Wie man aus einem uint32_t mit nem 2s complement Bitmuster eines signed Wertes einen int32_t (mit diesem signed Wert) macht, und zwar plattformunabhängig und so dass per C++ Standard garantiert das Ergebnis passt, ist nicht davon abhängig wo man dieses Bitmuster her hat.
D.h. die uint -> int Funktion kann man super testen.Weiters könnte man sie in ein Template umbauen, so dass sie für alle Bitbreiten funktioniert. Dann kann man sie in anderen
make_intXXFunktionen wiederverwenden. Bzw. allgemein könnte es Stellen geben wo man die selbe Funktion braucht.Und es wird leichter dadurch zu lesen. z.B. schonmal dadurch dass die Funktion jetzt einen Namen hat. Wenn man diesen gut wählt (und nicht so wie du kryptische Abkürzungen wie "m_uint32" verwendet ;)), dann sagt alleine der Name schon was die Funktion macht. Wenn ich nur verstehen will was der Code macht brauche ich mir also nichtmal ansehen wie die Funktion implementiert ist. (Das müsste ich nur, wenn ich überprüfen will ob die Implementierung korrekt ist. Und auch da ist es besser viele kleinere Teile zu haben, da man die Funktion einer Funktion oder Klasse viel leichter überprüfen kann wenn diese klein ist und nur wenig tut.)
ps:
lemon03 schrieb:
Ich würde gerne noch mal auf den Funktionszeiger zurück kommen,
Jo, sorry. Dafür brauch ich ne ruhige Minute (die ich jetzt nicht habe und auch gestern nicht hatte)

-
hustbaer schrieb:
Jo, sorry. Dafür brauch ich ne ruhige Minute (die ich jetzt nicht habe und auch gestern nicht hatte)

Kein Ding
Und danke nochmals für die Erklärung.
-
lemon03 schrieb:
Also sorry, wollte nicht aufmüpfig erscheinen.
Tust du nicht! Höchstens eigenwillig, aber das ist bis zu einem bestimmten Grad würd' ich mal sagen sogar was gutes. Alles ohne nachzufragen einfach zu akzeptieren wäre nicht unbedingt ein Zeichen von Intelligenz

lemon03 schrieb:
Ich würde gerne noch mal auf den Funktionszeiger zurück kommen, ob das hier möglich und sinnvoll ist. Vorgestellt habe ich mir das mit sozusagen Pseudocode etwa so:
int (*make_dec)(std::vector <unsigned char> const, std::size_t); //hier const richtig? uint16_t m_uint16(std::vector <unsigned char> const &bmp_data, std::size_t pos) ...Das
constist schon richtig, aber das "&" fehlt noch - das gehört ja schliesslich mit zum Typ. Weswegen ich es auch immerType& nameschreibe und nichtType &namewie du
=>
int (*make_dec)(std::vector <unsigned char> const&, std::size_t);Nur bringt dir das nicht viel. Damit deklarierst du eine Variable namens "make_dec" die den Typ hat: Zeiger auf: Funktion mit Signatur:
int fun(std::vector <unsigned char> const&, std::size_t);Du brauchst aber nicht eine solche Variable, du brauchst den Typ. Damit du ihn später in dem
pair<>verwenden kannst. Also z.B. einfach:typedef int (*make_int_function_ptr)(std::vector <unsigned char> const&, std::size_t);lemon03 schrieb:
struct Head //Kopf { static const auto Size = 4; std::array <std::pair <std::string, |Typ?|>, Size> bType { { { "bfType", m_uint16 }, //uint16_t { "bfSize", m_uint32 }, //uint32_t { "bfReserved", m_uint32 }, { "bfOffbits", m_uint32 } } }; std::array <int, Size> data; } head;Also |Typ?| hier ist einfach:
make_int_function_ptr.
Allerdings stimmt der Typ von&m_uint16etc. nicht mitmake_int_function_ptrüberein (unterschiedlicher Returnwert).
Also Hilfsfunktionen.
Oder evtl. mit Lambdas:struct Head //Kopf { static const auto Size = 4; std::array<std::pair<std::string, make_int_function_ptr>, Size> bType = { { { "bfType", [](std::vector<unsigned char> const& d, size_t p) -> int { return m_uint16(d, p); } }, { "bfSize", [](std::vector<unsigned char> const& d, size_t p) -> int { return m_uint32(d, p); } }, { "bfReserved", [](std::vector<unsigned char> const& d, size_t p) -> int { return m_uint32(d, p); } }, { "bfOffbits", [](std::vector<unsigned char> const& d, size_t p) -> int { return m_uint32(d, p); } }, } }; std::array <int, Size> data; } head;lemon03 schrieb:
head.data.at(i) = Funktionsaufruf mit <head.bType.at(i).second>;Das wäre dann
head.data.at(i) = head.bType[i].second(theVectorWithTheData, theOffsetInThatVector);Aber merkst du 'was? Woher willst du
theOffsetInThatVectornehmen?Also vielleicht doch nicht so der optimale Ansatz.
Natürlich kann man das auch lösen - gibt mehrere Varianten wie man das ohne all zu grosse Änderungen umbauen kann so dass der Offset verfügbar ist.Die Frage ist aber, ob das den ganzen Aufwand wert ist?
Wieso nicht einfach eine Funktion der du nen
vectoroder auch einfach nen Zeiger auf dieunsigned chars übergibst, und die dir neBitmapHeaderstruct zurückgibt? Und einfach die ganzenmake_this,make_thatFunktionen der Reihe nach aufruft um das zu machen. Wäre vermutlich viel einfacher.
-
ps:
Einfacher Trick wenn man die Function-Pointer Syntax nicht mag:typedef int make_int_function(std::vector <unsigned char> const&, std::size_t); typedef make_int_function* make_int_function_ptr;(Oder alternativ zum 2. typedef dann einfach überall
make_int_function*stattmake_int_function_ptrschreiben.)
-
Aye, na klasse für die ausführlichen Anmerkungen.
Zum
const&, dies war auch mein erster Impuls, weil mir das in dem Sinn logisch erschien, wollte dann aber nachfragen. Ich schreibe das sonst immer so, weil ich den Operator(?) sonst nur von Referenzen kannte. Also beivoid func(int &val) { val ++; }wäre es doch der Wert und nicht der Typ, der per Referenz übergeben wird?
Zu dem Problem mit dem
offsetals Übergabe musste ich mir schon Gedanken machen, weil es noch mehrere Notwendigkeiten im Code geben wird, den aktuellen offset zu kennen.
Dies wollte ich durch einenstd::tuplelösen. Nur habe ich noch Probleme dieses in ein array zu packen. Vorgestellt hatte ich mir das so:struct Head //Kopf { static const auto Size = 4; std::array <std::tuple <std::string, |Typ?|, int>, Size> bType; std::make_tuple //?? { { { "bfType", m_uint16, 2 }, //uint16_t //anzahl bytes { "bfSize", m_uint32, 4 }, //uint32_t { "bfReserved", m_uint32, 4 }, { "bfOffbits", m_uint32, 4 } } }; std::array <int, Size> data; } head;Der aktuelle offset wäre dann die vorherigen addierten Werte. Oder gleich so:
struct Head //Kopf { static const auto Size = 4; std::array <std::tuple <std::size_t, std::string, |Typ?|>, Size> bType; std::make_tuple //?? { { { 0, "bfType", m_uint16 }, //offset//name//uint16_t { 2, "bfSize", m_uint32 }, //uint32_t { 6, "bfReserved", m_uint32 }, { 10, "bfOffbits", m_uint32 } } }; std::array <int, Size> data; } head;Das zweite wäre natürlich einfacher.
Zu dem Funktionszeiger selbst, den muss ich erst mal sacken lassen
Allerdings scheint Deine letzte Idee mitund die dir ne BitmapHeader struct zurückgibt?
ganz interessant. Kannst Du mir zeigen, wie in etwas Du dies gemeint hast?
-
lemon03 schrieb:
Aye, na klasse für die ausführlichen Anmerkungen.
Zum
const&, dies war auch mein erster Impuls, weil mir das in dem Sinn logisch erschien, wollte dann aber nachfragen. Ich schreibe das sonst immer so, weil ich den Operator(?)Ui, frag mich nicht wie das "&" an der Stelle heisst, aber vermutlich mal nicht Operator. Weil es da nicht als Operator verwendet wird, sondern als Teil des Typs.
lemon03 schrieb:
sonst nur von Referenzen kannte.
Ja eh. Der "&" an der Stelle gibt ja auch an dass der Typ des Parameters "Referenz auf T" ist. Also "
T&".lemon03 schrieb:
Also bei
void func(int &val) { val ++; }wäre es doch der Wert und nicht der Typ, der per Referenz übergeben wird?
Natürlich wird der Wert per Referenz übergeben.
valist in diesem Beispiel eine Referenz auf einenint.
Und daher ist der Typ vonvaleben nicht "int", sondern "int&".lemon03 schrieb:
Zu dem Problem mit dem
offsetals Übergabe musste ich mir schon Gedanken machen, weil es noch mehrere Notwendigkeiten im Code geben wird, den aktuellen offset zu kennen.
Dies wollte ich durch einenstd::tuplelösen. Nur habe ich noch Probleme dieses in ein array zu packen. Vorgestellt hatte ich mir das so:struct Head //Kopf { static const auto Size = 4; std::array <std::tuple <std::string, |Typ?|, int>, Size> bType; std::make_tuple //?? { { { "bfType", m_uint16, 2 }, //uint16_t //anzahl bytes { "bfSize", m_uint32, 4 }, //uint32_t { "bfReserved", m_uint32, 4 }, { "bfOffbits", m_uint32, 4 } } }; std::array <int, Size> data; } head;Erm. Probier es doch einfach mal aus. Wie es mit pair geht hab ich dir gezeigt (nicht so, weil du die m_uintXX Funktionen hier nicht einfach so übergeben kannst - hab ich auch schon geschrieben). Mit Tuple wird es nicht viel anders sein, nen?
lemon03 schrieb:
Der aktuelle offset wäre dann die vorherigen addierten Werte. Oder gleich so:
struct Head //Kopf { static const auto Size = 4; std::array <std::tuple <std::size_t, std::string, |Typ?|>, Size> bType; std::make_tuple //?? { { { 0, "bfType", m_uint16 }, //offset//name//uint16_t { 2, "bfSize", m_uint32 }, //uint32_t { 6, "bfReserved", m_uint32 }, { 10, "bfOffbits", m_uint32 } } }; std::array <int, Size> data; } head;Das zweite wäre natürlich einfacher.
Oder z.B.
uint32_t read_uint32(std::vector<unsigned char> const& data, size_t& inout_offset) { uint32_t const result = ... wie gehabt inout_offset += 4; // Offset um so viele Bytes weiterschieben wie wir "konsumiert" haben return result; }lemon03 schrieb:
Allerdings scheint Deine letzte Idee mit
und die dir ne BitmapHeader struct zurückgibt?
ganz interessant. Kannst Du mir zeigen, wie in etwas Du dies gemeint hast?
Naja... nix spezielles, die naive, triviale Implementierung für sowas halt:
header read_header(std::vector<unsigned char> const& data, size_t& inout_offset) { header resut; resut.first_field = read_uint32(data, inout_offset); resut.second_field = read_uint16(data, inout_offset); resut.third_field = read_double(data, inout_offset); return resut; }Bzw. kannst du das natürlich auch wieder mit "manuellen" Offsets machen. Finde ich aber ... umständlicher.
-
Joh, danke. Lauter hübsche Gedankenanstöße. Mal schauen, was ich daraus mache

-
... 5 Jahre später ...
Hallo,
auf Deinen letzten Vorschlag konnte ich erst mal nicht näher eingehen, ich wollte es versuchen, wie ich es mir vorgestellt hatte. Ich habe einige Dinge vereinfacht (die Funktionen zb einfach zu
intgemacht), ich weiß nicht, ob man jetzt denkt, "meine Güte, der hat ja gar nichts verstanden"?Vielleicht kann man mich ja noch beraten, was nicht so gut ist/aussieht. Habe versucht Kommentare zu setzen, wo ich noch Fragen habe. Die Funktion
out_inFile()habe ich entfernt, weil sie ziemlich lang ist und hier nichts zu suchen hat. Hätte aber später noch ein, zwei Fragen dazu.Bin aber wie schon damals nur bis zur Farbtabelle. Wenn das alles korrekt ist, mache ich dann den Rest.
LG
//#include "output.h" #include <iostream> #include <fstream> #include <string> #include <vector> #include <iomanip> //#include <array> //#include <tuple> #include <cmath> typedef int(*make_dec)(std::vector <unsigned char> const&, std::size_t); //bildbyte, offset int uint16(std::vector<unsigned char> const& bmp_data, std::size_t pos); int uint32(std::vector<unsigned char> const& bmp_data, std::size_t pos); int int32(std::vector<unsigned char> const& bmp_data, std::size_t pos); typedef std::tuple<std::size_t, std::string, make_dec> bfTuple; //offset, bezeichnung, "typ" typedef std::tuple<unsigned char, unsigned char, unsigned char, unsigned char> tblTuple; //Farbtabelleneinträge B/G/R/0 struct Head //Kopf { static const auto Size = 4; std::array<bfTuple, Size> bfType { { std::make_tuple( 0, "bfType", uint16), //offset, bezeichnung, "typ" (hier uint16_t) std::make_tuple( 2, "bfSize", uint32), //uint32_t std::make_tuple( 6, "bfReserved", uint32), std::make_tuple(10, "bfOffbits", uint32) } }; std::array <int, Size> data; } head; struct Info //Eigenschaften { static const auto Size = 11; std::array<bfTuple, Size> bfType { { std::make_tuple( 14, "biSize", uint32), //uint32_t std::make_tuple( 18, "biWidth", int32), //int32_t std::make_tuple( 22, "biHeight", int32), std::make_tuple( 26, "biPlanes", uint16), //uint16_t std::make_tuple( 28, "biBitCount", uint16), std::make_tuple( 30, "biCompression", uint32), std::make_tuple( 34, "biSizeImage", uint32), std::make_tuple( 38, "biXPelsPerMeter", int32), std::make_tuple( 42, "biYPelsPerMeter", int32), std::make_tuple( 46, "biClrUsed", uint32), std::make_tuple( 50, "biClrImportant", uint32) } }; std::array <int, Size> data; } info; /* struct ColMask //Farbmaske { bool is_ = true; std::vector<char> entry; } colMsk; */ struct ColTable //Farbtabelle { bool is_ = true; //existiert Farbtabelle int size_ = 0; //Größe std::vector<tblTuple> entry; //Einträge } colTbl; //////////////////////////////////////////////////////////////////////////////////////// int uint16(std::vector <unsigned char> const& bmp_data, std::size_t pos) { const int u_val = bmp_data.at(pos + 0) + (static_cast<uint16_t>(bmp_data.at(pos + 1)) << 8); return u_val; } int uint32(std::vector <unsigned char> const& bmp_data, std::size_t pos) { const int u_val = bmp_data.at(pos + 0) + (static_cast<uint32_t>(bmp_data.at(pos + 1)) << 8) + (static_cast<uint32_t>(bmp_data.at(pos + 2)) << 16) + (static_cast<uint32_t>(bmp_data.at(pos + 3)) << 24); return u_val; } int int32(std::vector <unsigned char> const& bmp_data, std::size_t pos) { const int u_val = uint32(bmp_data, pos); if ((u_val >> 31) & 1) { return -static_cast<int32_t>(~u_val) - 1; } else { return u_val; } } ///////////////////////////////////////////////////////////////////////////////////// int make_colTbl_size(int biClrUsed, int biBitCount, bool& is_ ) { int colTbl_size = 0; if (biClrUsed == 0) { if (biBitCount == 1 || biBitCount == 4 || biBitCount == 8) colTbl_size = pow(2, biBitCount); else colTbl.is_ = false; } else colTbl_size = biClrUsed; return colTbl_size; } ///////////////////////////////////////////////////////////////////////////////////// void read_bmpData(std::string file_, std::vector <unsigned char>& bmp_data) { const std::string file_name = file_ + ".bmp"; char s_char; std::ifstream file (file_name.c_str(), std::ios::binary); if (!file) { std::string err_str = "!Fehler bei " + file_name; throw err_str; } while (file.get(s_char)) bmp_data.push_back(s_char); std::cout << "_File: " << file_name << '\n'; } //void out_inFile(std::string file_, std::vector<unsigned char> const& bmp_data, // std::array<int, head.Size>, std::array<int, info.Size>, int) ////////////////////////////////////////////////////////////////////////////////// int main() { std::string file_ = "test_me"; //std::string file_ = "WOLKEN"; //std::string file_ = "046"; //std::string file_ = "Cubis"; //std::string file_ = "example_topdown"; //std::string file_ = "topdown_2"; //std::string file_ = "gl_xs"; try { std::vector<unsigned char> bmp_data; read_bmpData(file_, bmp_data); //head for (auto i=0; i<head.Size; i++) head.data.at(i) = std::get<2>(head.bfType.at(i))(bmp_data, std::get<0>(head.bfType.at(i))); //info for (auto i=0; i<info.Size; i++) info.data.at(i) = std::get<2>(info.bfType.at(i))(bmp_data, std::get<0>(info.bfType.at(i))); //Kodierung int biCompression = info.data.at(5); if (biCompression != 0) //biCompression !=0 Bilddaten sind kodiert - Abbruch { std::string str_err = "Bilddaten sind kodiert\nkann im Moment nicht verarbeitet werden"; out_inFile(file_, bmp_data, head.data, info.data, colTbl.size_); throw str_err; } /*sollte ich hier wie bei biCompression extra neue Variablen deklarieren?*/ //int biClrUsed = info.data.at(9); //int biBitCount = info.data.at(4); //colTbl.size_ = make_colTbl_size(biClrUsed, biBitCount, colTbl.is_); //Farbtabelle colTbl.size_ = make_colTbl_size(info.data.at(9), info.data.at(4), colTbl.is_); std::size_t offset = 54; //magic number? for (auto i=0; i<colTbl.size_*4; i+=4) { colTbl.entry.push_back(std::make_tuple(bmp_data.at(offset+i+0), bmp_data.at(offset+i+1), bmp_data.at(offset+i+2), bmp_data.at(offset+i+3))); } out_inFile(file_, bmp_data, head.data, info.data, colTbl.size_); } catch(std::string str_err) { std::cerr << str_err << '\n'; } }
-
Ich hätte da noch ne kurze Zwischenfrage. Diese Übung soll ja kein Selbstzweck sein, sondern ich will später die Daten des Bild weiterverarbeiten.
Gebraucht werden nur die Farbtabelle, die Bilddaten und evtl die Farbmasken. Ich dachte mir, um dann darauf zuzugreifen, speichere ich die Daten in ein File. Hexadezimal zweistellig.
Wenn man dann die Datei in zB notepad++ öffnet, gibt es eine Riesenzeile voller Zeichen entsprechend der Größe. Geht das?
Oder gibt es da Grenzen bezüglich eines File, wie lang solche Zeichenketten ohne Umbruch sein können?
-
lemon03 schrieb:
Oder gibt es da Grenzen bezüglich eines File, wie lang solche Zeichenketten ohne Umbruch sein können?
Dateien sind Zeichenfolgen und haben sonst keine Struktur, Zeilenumbrüche sind auch nur Zeichen ohne jede Sonderbedeutung auf Dateiebene.