diff --git a/imageInput.c b/imageInput.c index bb30de1..7ddd595 100644 --- a/imageInput.c +++ b/imageInput.c @@ -3,20 +3,172 @@ #include #include "imageInput.h" -#define BUFFER_SIZE 100 #define FILE_HEADER_STRING "__info2_image_file_format__" -// TODO Implementieren Sie geeignete Hilfsfunktionen für das Lesen der Bildserie aus einer Datei +/* ------------------------------------------------------------------------- + * Hilfsfunktion: liest ein unsigned short (16-bit) aus Datei + * Rückgabe: 1 bei Erfolg, 0 bei Fehler + * ------------------------------------------------------------------------- */ +static int readUInt16(FILE *f, unsigned short *out) +{ + return fread(out, sizeof(unsigned short), 1, f) == 1; +} -// TODO Vervollständigen Sie die Funktion readImages unter Benutzung Ihrer Hilfsfunktionen +/* ------------------------------------------------------------------------- + * Header prüfen: + * - Tests schreiben den Header exakt als strlen(FILE_HEADER_STRING) Bytes + * (OHNE Nullterminator). Deshalb lesen wir genau diese Anzahl Bytes und + * vergleichen mittels strncmp. + * ------------------------------------------------------------------------- */ +static int readHeader(FILE *f) +{ + size_t len = strlen(FILE_HEADER_STRING); + char buf[64]; /* genügend groß für unseren Header */ + + if (len >= sizeof(buf)) + return 0; + + if (fread(buf, 1, len, f) != len) + return 0; + + /* selbst terminieren, damit strcmp / strncmp sauber arbeiten können */ + buf[len] = '\0'; + + return strcmp(buf, FILE_HEADER_STRING) == 0; +} + +/* ------------------------------------------------------------------------- + * readImages: + * Liest das Format wie in den Tests erzeugt: + * + * [header bytes (strlen(FILE_HEADER_STRING))] + * uint16_t numberOfImages + * uint16_t width + * uint16_t height + * + * für jedes Bild: + * width*height bytes pixel + * uint8_t label + * ------------------------------------------------------------------------- */ GrayScaleImageSeries *readImages(const char *path) { - GrayScaleImageSeries *series = NULL; - + if (!path) + return NULL; + + FILE *f = fopen(path, "rb"); + if (!f) + return NULL; + + /* Header prüfen */ + if (!readHeader(f)) + { + fclose(f); + return NULL; + } + + /* Anzahl der Bilder (unsigned short in den Tests) */ + unsigned short count16; + if (!readUInt16(f, &count16)) + { + fclose(f); + return NULL; + } + + /* Breite und Höhe (ebenfalls unsigned short in den Tests) */ + unsigned short width16, height16; + if (!readUInt16(f, &width16) || !readUInt16(f, &height16)) + { + fclose(f); + return NULL; + } + + /* Sicherheitscheck: keine extremen Werte */ + if (count16 == 0 || width16 == 0 || height16 == 0) + { + /* ungültige/metadaten -> als Fehler behandeln */ + fclose(f); + return NULL; + } + + /* Serie allokieren */ + GrayScaleImageSeries *series = malloc(sizeof(GrayScaleImageSeries)); + if (!series) + { + fclose(f); + return NULL; + } + + series->count = (unsigned int)count16; + series->images = calloc(series->count, sizeof(GrayScaleImage)); + series->labels = calloc(series->count, sizeof(unsigned char)); + if (!series->images || !series->labels) + { + clearSeries(series); + fclose(f); + return NULL; + } + + /* Für alle Bilder: Breite / Höhe sind gleich (wie im Test geschrieben) */ + for (unsigned int i = 0; i < series->count; ++i) + { + series->images[i].width = (unsigned int)width16; + series->images[i].height = (unsigned int)height16; + + /* Größe berechnen und Puffer allokieren */ + unsigned int size = series->images[i].width * series->images[i].height; + + series->images[i].buffer = malloc(size * sizeof(GrayScalePixelType)); + if (!series->images[i].buffer) + { + clearSeries(series); + fclose(f); + return NULL; + } + + /* Pixeldaten einlesen */ + size_t readPixels = fread(series->images[i].buffer, sizeof(GrayScalePixelType), size, f); + if (readPixels != size) + { + clearSeries(series); + fclose(f); + return NULL; + } + + /* Label einlesen (1 Byte) */ + if (fread(&series->labels[i], sizeof(unsigned char), 1, f) != 1) + { + clearSeries(series); + fclose(f); + return NULL; + } + } + + fclose(f); return series; } -// TODO Vervollständigen Sie die Funktion clearSeries, welche eine Bildserie vollständig aus dem Speicher freigibt +/* ------------------------------------------------------------------------- + * clearSeries: gibt alle Ressourcen einer Serie frei + * - ist NULL-sicher + * ------------------------------------------------------------------------- */ void clearSeries(GrayScaleImageSeries *series) { -} \ No newline at end of file + if (!series) + return; + + if (series->images) + { + for (unsigned int i = 0; i < series->count; ++i) + { + free(series->images[i].buffer); + series->images[i].buffer = NULL; + } + free(series->images); + series->images = NULL; + } + + free(series->labels); + series->labels = NULL; + + free(series); +} diff --git a/imageInput.h b/imageInput.h index 656e213..47f4753 100644 --- a/imageInput.h +++ b/imageInput.h @@ -1,23 +1,47 @@ #ifndef IMAGEINPUT_H #define IMAGEINPUT_H +#include // für size_t + +// Datentyp für ein einzelnes Pixel (0–255) typedef unsigned char GrayScalePixelType; +// Struktur eines einzelnen Graustufenbildes typedef struct { - GrayScalePixelType *buffer; - unsigned int width; - unsigned int height; + GrayScalePixelType *buffer; // Zeiger auf Pixel-Daten (width * height) + unsigned int width; // Bildbreite + unsigned int height; // Bildhöhe } GrayScaleImage; +// Eine Serie von Bildern inklusive Labels typedef struct { - GrayScaleImage *images; - unsigned char *labels; - unsigned int count; + GrayScaleImage *images; // Array von Bildern + unsigned char *labels; // Array von Labels (0–255) + unsigned int count; // Anzahl der Bilder } GrayScaleImageSeries; +/** + * Liest eine Bilderserie aus einer Datei. + * Erwartetes Format: + * uint32 count + * für jedes Bild: + * uint32 width + * uint32 height + * width*height Bytes Bilddaten + * uint8 label + * + * @param path Pfad zur Datei + * @return Pointer auf GrayScaleImageSeries oder NULL bei Fehler + */ GrayScaleImageSeries *readImages(const char *path); + +/** + * Gibt den Speicher einer Serie wieder frei. + * + * @param series Pointer auf die Serie, darf auch NULL sein + */ void clearSeries(GrayScaleImageSeries *series); -#endif +#endif // IMAGEINPUT_H