ppm in struct
-
Hi,
ich muss eine ppm datei in ein struct einlesen. Mit welcher Funktion mach ich das am besten? fscanf, fread?
-
Hi,
beide Funktionen sind geeignet je nachdem, ob es eine ASCII oder Binär PPM ist.
-
binär
-
Hab mir gerade mal die Spezifikation von ppm auf Wotsit durchgelesen. Mit einem einfachen Befehl der das Struct eins zu eins aus einem File einlesen soll ist es nicht getan. Das File kann Kommentare enthalten, Tabs, usw. Das würde dein Struct so nicht akzeptieren. Es sollte aber nicht schwer sein, einen Parser für diese Files zu programmieren.
Also das hier macht es. Aber es macht kein Error-Checking und geht davon aus, daß das File syntaktisch in Ordnung ist. Auf mehr hatte ich kein Bock um die Zeit
Verbesserungen wären:
- das File komplett buffern und dann im Memory auslesen
- Error-CheckingDie RGB-Werte habe ich zusammengezippt in ein dword. Das höchste Byte ist dabei frei.
EDIT: Das hier liest nur die Ascii-Format-Version ein.
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #define dword unsigned long #define byte unsigned char #define FILENAME "D:\\DATEN\\Development\\C\\BeginningC\\test.ppm" typedef struct { char filetype[2]; byte width; byte height; byte maxcolor; dword** data; } t_ppm; byte readnum(FILE* fp) { char c; int num; for(; !isdigit(c = fgetc(fp)); ) // skip whitespaces ; for(num = c - '0'; isdigit(c = fgetc(fp)); ) { num = num * 10 + (c - '0'); } return num; } dword** malloc_2d(int height, int width) { dword** buffer; buffer = (dword**)malloc(sizeof(dword*) * height); for(int i = 0; i < height; i++) *(buffer + i) = (dword*)malloc(sizeof(dword) * width); return buffer; } void free_2d(dword** buffer, int height, int width) { for(int i = 0; i < height; i++) free(*(buffer + i)); free(buffer); } int main(void) { FILE* fp; t_ppm pic; char c; byte red, green, blue; fp = fopen(FILENAME, "rb"); fread(pic.filetype, sizeof(char), 2, fp); pic.width = readnum(fp); pic.height = readnum(fp); pic.maxcolor = readnum(fp); pic.data = malloc_2d(pic.height, pic.width); for(int i = 0; i < pic.height; i++) { for(int j = 0; j < pic.width; j++) { red = readnum(fp); green = readnum(fp); blue = readnum(fp); *(*(pic.data + i) + j) = (red << 16) + (green << 8) + blue; } } fclose(fp); printf("filetype: %c%c\n", pic.filetype[0], pic.filetype[1]); printf("width: %d\n", pic.width); printf("height: %d\n", pic.height); printf("maxcolor: %d\n", pic.maxcolor); for(int i = 0; i < pic.height; i++) { for(int j = 0; j < pic.width; j++) { dword value = *(*(pic.data + i) + j); printf("%d %d %d ", (value & 0xff0000) >> 16, (value & 0x00ff00) >> 8, value & 0x0000ff); } printf("\n"); } free_2d(pic.data, pic.height, pic.width); system("pause"); return 0; }
-
c-daniel schrieb:
binär
fread
-
Hallo! Ich hab ebenfalls einen Aufgabe wo ich eine ppm Datei einlesen muss! Kann mir jemand erklären wie ich das angehen kann! Ich weiß code 2 Einträge vor mir kann ich verwenden möchte aber selber draufkommen auserdem stürtzt dieses ab einer gewissenstelle ab!
Wie ich den header auslies ist mir schon mal klar! Aber der Rest ist mir nicht ganz klar könnte mir jemand das erklären! Danke in vorraus!
mfg
-
Er stürzt bei dir ab?! Hmm kann nur daran liegen, daß ich den Typ Byte verwende, der die Farbinformationen auf den maximalen Farbwert 255 reduziert. Wenn in dein einzelnen Farbinformationen größere Werte stehen, kann es sein, daß es das nicht mehr macht. Ist aber leicht zu ändern.
Hier mal eine Beispieldatei. Ist Ascii. Es gibt wohl noch ein Binärformat, aber das sollte noch einfacher einzulesen sein, da man dann nicht mit den Farbwerten rumzuckeln muß.
P3 # feep.ppm 4 4 15 0 0 0 0 0 0 0 0 0 15 0 15 0 0 0 0 15 7 0 0 0 0 0 0 0 0 0 0 0 0 0 15 7 0 0 0 15 0 15 0 0 0 0 0 0 0 0 0
- P3 auslesen geht natürlich fix mit fread
- Kommentare beginnen mit '#' also muß diese Zeile gar nicht weiter beachtet werden. Einfach bis zum nächsten '\n' gehen und weiter machen.
- jetzt werden wir viele Zahlenwerte lesen, d.h. es bietet sich an, eine eigene Funktion dafür zu schreiben. Die Zahlen sind jeweils durch Whitespaces getrennt. Unsere Funktion soll also zunächst alle Whitespaces überspringen und sobald eine Zahl kommt mit seiner Arbeit anfangen. Um aus geschriebenen Zahlen tatsächliche Zahlen im Rechner zu machen, benutzt man solche Codes wie
while(isdigit(*buffer) && *buffer != '\0') { // solange wir zahlen lesen num = num * 10 + (*buffer - '0') // wandle die Zahl die ja als Ascii-Zeichen vorliegt in seinen wahren Zahlenwert // um und füge sie in die Zahl ein buffer++; // gehe zum nächsten zeichen }
Jetzt haben wir eine Zahl eingelesen. Somit können wir nun die Höhe und die Breite des Bildes auslesen. Den maximalen Farbwert ermitteln somit auch. All das Speichern wir am besten in einem Struct, damit die Werte auch beisammen sind.
Jetzt sollen wir die Farbwerte einlesen. Durch die Höhe und die Breite des Bildes wissen wir wieviele Zahlen nun folgen werden. Bei 3 Farbwerten pro Pixel folgen Breite x Höhe x 3 Zahlen. Diese können wir wieder mit unserer Funktoin einlesen. Das machen wir am besten Pixelweise. Und das heißt bei uns in 3er-Paketen. Die erste Zahl dieses Pakets ist der Rot-Wert dann folgt der Grün-Wert und dann der Blau-Wert. Diese 3er-Pakete lesen wir genau Höhe x Breite mal ein und dann wissen wir, daß wir fertig sind.
Zum Speichern der Geschichte, bietet sich natürlich ein Struct an. Nur die Farben machen "Probleme". Zunächst wissen wir im vorhinein nicht, wiviele Farbinformationen folgen werden, da wir Höhe und Breite erst zur Leufzeit erfahren und daher müssen wir das zwei dimensionale Array dynamisch erzeugen. Dafür gibt es malloc. Mit dem passenden Aufruf steht uns dann ein Array[Höhe][Breite] zur Verfügung wo wir die Farbwerte speichern können. Als Typ des Arrays habe ich DWORD gewählt, in dem 4 Bytes locker Platz finden. Wir nutzen aber nur 3, so ist das höchste Byte einfach 00000000. Da das bei dir zu problemen führt, nehmen wir lieber ein Struct, daß die Farbwerte nicht in ein DWORD pressen. Es bietet sich also sowas an:
typedef struct { int red; int green; int blue; } rgb_t;
Ist unser Array also von diesem Typ so finden alle Farbinformationen Platz und die Aufgabe ist gelöst.
Ich hoffe ich konnte die das ein wenig näher bringen. Ich hoffe auch ich hab dir jetzt nicht zuviel gesagt um dir den Spaß beim Lösen nicht zu nehmen.