From c98802542dca893cf9a4fd3f5dada3cb8e7f5f9e Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 4 May 2024 22:35:12 +0100 Subject: [PATCH] Add TiffReader struct --- src/tiff/tiffread.c | 181 +++++++++++++++++++++++++------------------- 1 file changed, 105 insertions(+), 76 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index d224e30..d9e0289 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -35,14 +35,21 @@ #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); +typedef struct tiff_reader TiffReader; +struct tiff_reader { + FILE *fp; + TiffHdr header; + TiffIFD ifd; + TiffImage img; + Pixel *pixels; +}; + +TiffHdr read_tiff_header(const TiffReader *reader); +TiffIFD read_ifd(const TiffReader *reader, Arena *arena); +TiffImage read_fields(const TiffReader *reader); +Pixel *load_image_pixels(TiffReader *reader, Arena *arena); +bool read_strip_data(TiffReader *reader, Arena *arena); +void read_strips(const TiffReader *reader, Pixel *buf); 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); @@ -50,7 +57,7 @@ void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); Image *read_baseline_tiff(const char *file, Arena *arena) { Image *img_out = NULL; - if (!file) { + if (!file || !arena) { goto READ_BASELINE_RETURN_IMG; } @@ -82,30 +89,33 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { goto READ_BASELINE_FILE_CLEANUP; } - TiffHdr header = read_tiff_header(fp); - if (IS_NULL_HEADER(header)) { + TiffReader reader = {.fp = fp}; + + reader.header = read_tiff_header(&reader); + if (IS_NULL_HEADER(reader.header)) { goto READ_BASELINE_DESTROY_ARENA; } - TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, temp_arena); - if (IS_NULL_IFD(ifd)) { + reader.ifd = read_ifd(&reader, temp_arena); + if (IS_NULL_IFD(reader.ifd)) { goto READ_BASELINE_DESTROY_ARENA; } - TiffImage img = read_fields(fp, &header, &ifd); - if (IS_NULL_IMAGE(img)) { + reader.img = read_fields(&reader); + if (IS_NULL_IMAGE(reader.img)) { goto READ_BASELINE_DESTROY_ARENA; } - assert((img.type == TIFF_IMAGE_TYPE_RGB) && + assert((reader.img.type == TIFF_IMAGE_TYPE_RGB) && "Currently, only RGB images are supported"); - Pixel *buf = load_image_pixels(fp, &header, &img, temp_arena); - if (!buf) { + reader.pixels = load_image_pixels(&reader, temp_arena); + if (!reader.pixels) { goto READ_BASELINE_DESTROY_ARENA; } - img_out = create_image(img.image_width, img.image_length, buf, arena); + img_out = create_image(reader.img.image_width, reader.img.image_length, + reader.pixels, arena); READ_BASELINE_DESTROY_ARENA: wapp_mem_arena_destroy(&temp_arena); @@ -117,13 +127,9 @@ READ_BASELINE_RETURN_IMG: return img_out; } -TiffHdr read_tiff_header(FILE *fp) { - if (!fp) { - return NULL_TIFF_HEADER; - } - +TiffHdr read_tiff_header(const TiffReader *reader) { TiffHdr header = NULL_TIFF_HEADER; - read_from_file_with_offset(fp, &header, sizeof(TiffHdr), 0); + read_from_file_with_offset(reader->fp, &header, sizeof(TiffHdr), 0); switch (header.order) { case TIFF_ORDER_LITTLE_ENDIAN: @@ -151,15 +157,12 @@ TiffHdr read_tiff_header(FILE *fp) { return header; } -TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena) { - if (!fp || !header) { - return NULL_TIFF_IFD; - } - +TiffIFD read_ifd(const TiffReader *reader, Arena *arena) { TiffIFD ifd = NULL_TIFF_IFD; - read_from_file_with_offset(fp, &(ifd.count), sizeof(ifd.count), offset); + read_from_file_with_offset(reader->fp, &(ifd.count), sizeof(ifd.count), + reader->header.first_ifd_offset); - switch (header->order) { + switch (reader->header.order) { case TIFF_ORDER_LITTLE_ENDIAN: if (IS_BIG_ENDIAN) { ifd.count = htons(ifd.count); @@ -180,20 +183,20 @@ TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena) { return NULL_TIFF_IFD; } - fread(ifd.fields, field_byte_count, 1, fp); - fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, fp); + fread(ifd.fields, field_byte_count, 1, reader->fp); + fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, reader->fp); return ifd; } -TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { +TiffImage read_fields(const TiffReader *reader) { TiffImage img_out = NULL_TIFF_IMAGE; img_out.type = TIFF_IMAGE_TYPE_BILEVEL; - for (u64 i = 0; i < ifd->count; ++i) { - TiffField *field = &(ifd->fields[i]); + for (u64 i = 0; i < reader->ifd.count; ++i) { + TiffField *field = &(reader->ifd.fields[i]); - switch (header->order) { + switch (reader->header.order) { case TIFF_ORDER_BIG_ENDIAN: if (IS_LITTLE_ENDIAN) { field->tag = ntohs(field->tag); @@ -252,18 +255,19 @@ READ_FIELDS_RETURN_IMAGE: return img_out; } -Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img, - Arena *arena) { +Pixel *load_image_pixels(TiffReader *reader, Arena *arena) { Pixel *buf = NULL; - u64 img_byte_count = sizeof(Pixel) * img->image_width * img->image_length; + u64 img_byte_count = + sizeof(Pixel) * reader->img.image_width * reader->img.image_length; - if (!read_strip_data(fp, header, img, arena)) { + if (!read_strip_data(reader, 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); + for (u32 i = 0; i < reader->img.strip_count; ++i) { + printf("%u, %u\n", reader->img.strips[i].offset, + reader->img.strips[i].byte_count); } #endif @@ -272,46 +276,69 @@ Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img, goto LOAD_IMAGE_PIXELS_RETURN; } - read_strips(fp, img, buf); + read_strips(reader, buf); LOAD_IMAGE_PIXELS_RETURN: return buf; } -bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, - Arena *arena) { - if (!fp || !img || !arena) { - return false; - } +#if 0 +void read_strip_field(FILE *fp, const TiffHdr *header, const TiffImage *img, TiffStrip *strip) { + if (offsets_total_bytes > sizeof(u32)) { + u32 offset = img->strip_offsets.long_val + offset_size * i; + read_from_file_with_offset(fp, &(strip->offset), offset_size, offset); - img->strips = - wapp_mem_arena_alloc(arena, sizeof(TiffStrip) * img->strip_count); - if (!img->strips) { + switch (header->order) { + case TIFF_ORDER_BIG_ENDIAN: + if (IS_LITTLE_ENDIAN) { + strip->offset = offset_size > sizeof(u16) ? ntohl(strip->offset) + : ntohs(strip->offset); + } + break; + case TIFF_ORDER_LITTLE_ENDIAN: + if (IS_BIG_ENDIAN) { + strip->offset = offset_size > sizeof(u16) ? htonl(strip->offset) + : htons(strip->offset); + } + break; + } + } else { + memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size); + } +} +#endif + +bool read_strip_data(TiffReader *reader, Arena *arena) { + reader->img.strips = + wapp_mem_arena_alloc(arena, sizeof(TiffStrip) * reader->img.strip_count); + if (!(reader->img.strips)) { return false; } u32 offsets_total_bytes = - img->strip_count * img->strip_offsets_type_byte_count; + reader->img.strip_count * reader->img.strip_offsets_type_byte_count; u32 byte_count_total_bytes = - img->strip_count * img->strip_byte_count_type_byte_count; + reader->img.strip_count * reader->img.strip_byte_count_type_byte_count; - if ((!(img->strip_offsets_offset) && offsets_total_bytes > sizeof(u32)) || - (!(img->strip_byte_counts_offset) && + if ((!(reader->img.strip_offsets_offset) && + offsets_total_bytes > sizeof(u32)) || + (!(reader->img.strip_byte_counts_offset) && byte_count_total_bytes > sizeof(u32))) { return false; } - for (u32 i = 0; i < img->strip_count; ++i) { - TiffStrip *strip = &(img->strips[i]); + for (u32 i = 0; i < reader->img.strip_count; ++i) { + TiffStrip *strip = &(reader->img.strips[i]); - u16 offset_size = img->strip_offsets_type_byte_count; - u16 counts_size = img->strip_byte_count_type_byte_count; + u16 offset_size = reader->img.strip_offsets_type_byte_count; + u16 counts_size = reader->img.strip_byte_count_type_byte_count; if (offsets_total_bytes > sizeof(u32)) { - u32 offset = img->strip_offsets.long_val + offset_size * i; - read_from_file_with_offset(fp, &(strip->offset), offset_size, offset); + u32 offset = reader->img.strip_offsets.long_val + offset_size * i; + read_from_file_with_offset(reader->fp, &(strip->offset), offset_size, + offset); - switch (header->order) { + switch (reader->header.order) { case TIFF_ORDER_BIG_ENDIAN: if (IS_LITTLE_ENDIAN) { strip->offset = offset_size > sizeof(u16) ? ntohl(strip->offset) @@ -326,14 +353,16 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, break; } } else { - memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size); + memcpy(&(strip->offset), &(reader->img.strip_offsets.long_val), + offset_size); } if (byte_count_total_bytes > sizeof(u32)) { - u32 offset = img->strip_byte_counts.long_val + counts_size * i; - read_from_file_with_offset(fp, &(strip->byte_count), counts_size, offset); + u32 offset = reader->img.strip_byte_counts.long_val + counts_size * i; + read_from_file_with_offset(reader->fp, &(strip->byte_count), counts_size, + offset); - switch (header->order) { + switch (reader->header.order) { case TIFF_ORDER_BIG_ENDIAN: if (IS_LITTLE_ENDIAN) { strip->byte_count = counts_size > sizeof(u16) @@ -350,7 +379,7 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, break; } } else { - memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), + memcpy(&(strip->byte_count), &(reader->img.strip_byte_counts.long_val), counts_size); } } @@ -358,18 +387,18 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, return true; } -void read_strips(FILE *fp, const TiffImage *img, Pixel *buf) { +void read_strips(const TiffReader *reader, Pixel *buf) { u64 position = 0; - for (u64 i = 0; i < img->strip_count; ++i) { - const TiffStrip *strip = &(img->strips[i]); + for (u64 i = 0; i < reader->img.strip_count; ++i) { + const TiffStrip *strip = &(reader->img.strips[i]); - for (u64 j = 0; j < strip->byte_count / img->sample_count; ++j) { + for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { Pixel *p = &(buf[position]); - read_from_file_with_offset(fp, p, img->sample_count, - strip->offset + j * img->sample_count); + read_from_file_with_offset(reader->fp, p, reader->img.sample_count, + strip->offset + j * reader->img.sample_count); - if (img->sample_count == 3) { + if (reader->img.sample_count == 3) { p->a = 255; }