From 9fdee24672e1dcec4af6e5928478bd319a50958f Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 4 May 2024 22:01:24 +0100 Subject: [PATCH] Refactor loading image data --- src/tiff/tiffread.c | 105 +++++++++++++++++++++++++------------------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index 5e28602..d224e30 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -33,16 +33,18 @@ #define INVALID_ALPHA_OFFSET -1 +#define TEMP_ARENA_CAPACITY (20 * 1024 * 1024) + TiffHdr read_tiff_header(FILE *fp); TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd); +Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img, + Arena *arena); bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, Arena *arena); void read_strips(FILE *fp, const TiffImage *img, Pixel *buf); -bool read_field(const TiffField *field, TiffImage *img, - u32 *image_type_identifier); -bool validate_image_type(const TiffImage *img, - const u32 *image_type_identifier); +bool read_field(const TiffField *field, TiffImage *img); +bool validate_image_type(const TiffImage *img); void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); Image *read_baseline_tiff(const char *file, Arena *arena) { @@ -75,44 +77,38 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { goto READ_BASELINE_RETURN_IMG; } + Arena *temp_arena = NULL; + if (!wapp_mem_arena_init(&temp_arena, TEMP_ARENA_CAPACITY)) { + goto READ_BASELINE_FILE_CLEANUP; + } + TiffHdr header = read_tiff_header(fp); if (IS_NULL_HEADER(header)) { - goto READ_BASELINE_FILE_CLEANUP; - } - - TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, arena); - - TiffImage img = read_fields(fp, &header, &ifd); - assert((img.type == TIFF_IMAGE_TYPE_RGB) && - "Currently, only RGB images are supported"); - - u64 img_byte_count = sizeof(Pixel) * img.image_width * img.image_length; - - Arena *temp = NULL; - u64 temp_size = 1 * 1024 * 1024 + img_byte_count; - if (!wapp_mem_arena_init(&temp, temp_size)) { - goto READ_BASELINE_FILE_CLEANUP; - } - - if (!read_strip_data(fp, &header, &img, temp)) { goto READ_BASELINE_DESTROY_ARENA; } - for (u32 i = 0; i < img.strip_count; ++i) { - printf("%u, %u\n", img.strips[i].offset, img.strips[i].byte_count); + TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, temp_arena); + if (IS_NULL_IFD(ifd)) { + goto READ_BASELINE_DESTROY_ARENA; } - Pixel *buf = wapp_mem_arena_alloc(temp, img_byte_count); + TiffImage img = read_fields(fp, &header, &ifd); + if (IS_NULL_IMAGE(img)) { + goto READ_BASELINE_DESTROY_ARENA; + } + + assert((img.type == TIFF_IMAGE_TYPE_RGB) && + "Currently, only RGB images are supported"); + + Pixel *buf = load_image_pixels(fp, &header, &img, temp_arena); if (!buf) { goto READ_BASELINE_DESTROY_ARENA; } - read_strips(fp, &img, buf); - img_out = create_image(img.image_width, img.image_length, buf, arena); READ_BASELINE_DESTROY_ARENA: - wapp_mem_arena_destroy(&temp); + wapp_mem_arena_destroy(&temp_arena); READ_BASELINE_FILE_CLEANUP: fclose(fp); @@ -192,7 +188,7 @@ TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena) { TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { TiffImage img_out = NULL_TIFF_IMAGE; - u32 image_type_identifier = TIFF_IMAGE_TYPE_BILEVEL; + img_out.type = TIFF_IMAGE_TYPE_BILEVEL; for (u64 i = 0; i < ifd->count; ++i) { TiffField *field = &(ifd->fields[i]); @@ -228,20 +224,18 @@ TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { break; } - if (!read_field(field, &img_out, &image_type_identifier)) { + if (!read_field(field, &img_out)) { img_out = NULL_TIFF_IMAGE; goto READ_FIELDS_RETURN_IMAGE; } } - if (!validate_image_type(&img_out, &image_type_identifier)) { + if (!validate_image_type(&img_out)) { img_out = NULL_TIFF_IMAGE; goto READ_FIELDS_RETURN_IMAGE; } - img_out.type = image_type_identifier; - -#if 1 +#ifdef DEBUG // clang-format off printf("SIZE (width, height) : %u, %u\n", img_out.image_width, img_out.image_length); printf("SAMPLES (bits per sample, count, is offset) : %u, %u, %u\n", img_out.bits_per_sample, img_out.sample_count, img_out.bits_per_sample_offset); @@ -258,6 +252,32 @@ READ_FIELDS_RETURN_IMAGE: return img_out; } +Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img, + Arena *arena) { + Pixel *buf = NULL; + u64 img_byte_count = sizeof(Pixel) * img->image_width * img->image_length; + + if (!read_strip_data(fp, header, img, arena)) { + goto LOAD_IMAGE_PIXELS_RETURN; + } + +#ifdef DEBUG + for (u32 i = 0; i < img->strip_count; ++i) { + printf("%u, %u\n", img->strips[i].offset, img->strips[i].byte_count); + } +#endif + + buf = wapp_mem_arena_alloc(arena, img_byte_count); + if (!buf) { + goto LOAD_IMAGE_PIXELS_RETURN; + } + + read_strips(fp, img, buf); + +LOAD_IMAGE_PIXELS_RETURN: + return buf; +} + bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, Arena *arena) { if (!fp || !img || !arena) { @@ -358,8 +378,7 @@ void read_strips(FILE *fp, const TiffImage *img, Pixel *buf) { } } -bool read_field(const TiffField *field, TiffImage *img, - u32 *image_type_identifier) { +bool read_field(const TiffField *field, TiffImage *img) { switch (field->tag) { case TIFF_PUBLIC_TAG_IMAGE_WIDTH: if (field->count > 1) { @@ -378,7 +397,7 @@ bool read_field(const TiffField *field, TiffImage *img, break; case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE: - *image_type_identifier |= field->tag; + img->type |= field->tag; if (img->sample_count == INVALID_SAMPLE_COUNT) { img->sample_count = field->count; @@ -429,7 +448,7 @@ bool read_field(const TiffField *field, TiffImage *img, break; case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL: - *image_type_identifier |= field->tag; + img->type |= field->tag; if (field->count > 1) { return false; @@ -474,7 +493,7 @@ bool read_field(const TiffField *field, TiffImage *img, break; case TIFF_PUBLIC_TAG_COLOR_MAP: - *image_type_identifier |= field->tag; + img->type |= field->tag; break; case TIFF_PUBLIC_TAG_EXTRA_SAMPLES: img->extra_samples_count = field->count; @@ -496,14 +515,12 @@ bool read_field(const TiffField *field, TiffImage *img, return true; } -bool validate_image_type(const TiffImage *img, - const u32 *image_type_identifier) { - if (*image_type_identifier < TIFF_IMAGE_TYPE_BILEVEL || - *image_type_identifier > TIFF_IMAGE_TYPE_RGB) { +bool validate_image_type(const TiffImage *img) { + if (img->type < TIFF_IMAGE_TYPE_BILEVEL || img->type > TIFF_IMAGE_TYPE_RGB) { return false; } - switch (*image_type_identifier) { + switch (img->type) { case TIFF_IMAGE_TYPE_BILEVEL: case TIFF_IMAGE_TYPE_GRAYSCALE: if (img->photometric_interpretation >