#include #include #include #include "imageInput.h" #define FILE_HEADER_STRING "__info2_image_file_format__" /* ------------------------------------------------------------------------- * 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; } /* ------------------------------------------------------------------------- * 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) { 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; } /* ------------------------------------------------------------------------- * clearSeries: gibt alle Ressourcen einer Serie frei * - ist NULL-sicher * ------------------------------------------------------------------------- */ void clearSeries(GrayScaleImageSeries *series) { 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); }