From ba21bcb2f47001cc3d0cd57d3986efb1065981fa Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 5 May 2024 22:46:13 +0100 Subject: [PATCH] Switch internal reading functions to directly manipulate reader object --- src/tiff/tiffread.c | 251 ++++++++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 115 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index e7a5271..c976c2b 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -40,7 +40,7 @@ #define TIFF_LONG_BYTE_COUNT field_types[TIFF_FIELD_TYPE_LONG].byte_count #define RGB_SAMPLE_COUNT 3 -#define MINIMUM_BITS_PER_SAMPLE 8 +#define MIN_BITS_PER_SAMPLE 8 #define TEMP_ARENA_CAPACITY (20 * 1024 * 1024) @@ -62,15 +62,14 @@ struct strip_data_field { u16 type_byte_count; }; -internal TiffHdr read_tiff_header(const TiffReader *reader); -internal TiffIFD read_ifd(const TiffReader *reader, Arena *arena); -internal TiffImage read_ifd_fields(const TiffReader *reader); -internal TiffAlpha read_alpha(const TiffReader *reader, TiffImage *img); -internal TiffSampleBits read_bits_per_sample(const TiffReader *reader, - TiffImage *img); -internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena); +internal void read_tiff_header(TiffReader *reader); +internal void read_ifd(TiffReader *reader, Arena *arena); +internal void read_ifd_fields(TiffReader *reader); +internal void read_alpha(TiffReader *reader); +internal void read_bits_per_sample(TiffReader *reader); +internal void load_image_pixels(TiffReader *reader, Arena *arena); internal bool read_strip_data(TiffReader *reader, Arena *arena); -internal void read_strips(const TiffReader *reader, Pixel *buf); +internal void read_strips(TiffReader *reader); internal void read_strip_data_field(const TiffReader *reader, StripDataField *field); internal bool read_field(const TiffField *field, TiffImage *img); @@ -115,30 +114,30 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { goto READ_BASELINE_FILE_CLEANUP; } - reader.header = read_tiff_header(&reader); + read_tiff_header(&reader); if (IS_NULL_HEADER(reader.header)) { goto READ_BASELINE_DESTROY_ARENA; } - reader.ifd = read_ifd(&reader, temp_arena); + read_ifd(&reader, temp_arena); if (IS_NULL_IFD(reader.ifd)) { goto READ_BASELINE_DESTROY_ARENA; } - reader.img = read_ifd_fields(&reader); + read_ifd_fields(&reader); if (IS_NULL_IMAGE(reader.img)) { goto READ_BASELINE_DESTROY_ARENA; } assert((reader.img.type == TIFF_IMAGE_TYPE_RGB) && "Currently, only RGB images are supported"); - assert((reader.img.rgba_bits_per_sample.r == MINIMUM_BITS_PER_SAMPLE && - reader.img.rgba_bits_per_sample.g == MINIMUM_BITS_PER_SAMPLE && - reader.img.rgba_bits_per_sample.b == MINIMUM_BITS_PER_SAMPLE && - reader.img.rgba_bits_per_sample.a == MINIMUM_BITS_PER_SAMPLE) && + assert((reader.img.rgba_bits_per_sample.r == MIN_BITS_PER_SAMPLE && + reader.img.rgba_bits_per_sample.g == MIN_BITS_PER_SAMPLE && + reader.img.rgba_bits_per_sample.b == MIN_BITS_PER_SAMPLE && + reader.img.rgba_bits_per_sample.a == MIN_BITS_PER_SAMPLE) && "Currently, only 8-bit images are supported"); - reader.pixels = load_image_pixels(&reader, temp_arena); + load_image_pixels(&reader, temp_arena); if (!reader.pixels) { goto READ_BASELINE_DESTROY_ARENA; } @@ -156,71 +155,69 @@ READ_BASELINE_RETURN_IMG: return img_out; } -internal TiffHdr read_tiff_header(const TiffReader *reader) { - TiffHdr header = NULL_TIFF_HEADER; - read_from_file_with_offset(reader->fp, &header, sizeof(TiffHdr), 0); +internal void read_tiff_header(TiffReader *reader) { + reader->header = NULL_TIFF_HEADER; + read_from_file_with_offset(reader->fp, &(reader->header), sizeof(TiffHdr), 0); - switch (header.order) { + switch (reader->header.order) { case TIFF_ORDER_LITTLE_ENDIAN: if (IS_BIG_ENDIAN) { - header.magic = htons(header.magic); - header.first_ifd_offset = htonl(header.first_ifd_offset); + reader->header.magic = htons(reader->header.magic); + reader->header.first_ifd_offset = htonl(reader->header.first_ifd_offset); } break; case TIFF_ORDER_BIG_ENDIAN: if (IS_LITTLE_ENDIAN) { - header.magic = ntohs(header.magic); - header.first_ifd_offset = ntohl(header.first_ifd_offset); + reader->header.magic = ntohs(reader->header.magic); + reader->header.first_ifd_offset = ntohl(reader->header.first_ifd_offset); } break; default: - return NULL_TIFF_HEADER; + reader->header = NULL_TIFF_HEADER; } - if (header.magic != TIFF_MAGIC) { - return NULL_TIFF_HEADER; + if (reader->header.magic != TIFF_MAGIC) { + reader->header = NULL_TIFF_HEADER; } - - return header; } -internal TiffIFD read_ifd(const TiffReader *reader, Arena *arena) { - TiffIFD ifd = NULL_TIFF_IFD; - read_from_file_with_offset(reader->fp, &(ifd.count), sizeof(ifd.count), +internal void read_ifd(TiffReader *reader, Arena *arena) { + reader->ifd = NULL_TIFF_IFD; + read_from_file_with_offset(reader->fp, &(reader->ifd.count), + sizeof(reader->ifd.count), reader->header.first_ifd_offset); switch (reader->header.order) { case TIFF_ORDER_LITTLE_ENDIAN: if (IS_BIG_ENDIAN) { - ifd.count = htons(ifd.count); + reader->ifd.count = htons(reader->ifd.count); } break; case TIFF_ORDER_BIG_ENDIAN: if (IS_LITTLE_ENDIAN) { - ifd.count = ntohs(ifd.count); + reader->ifd.count = ntohs(reader->ifd.count); } break; } - u64 field_byte_count = sizeof(TiffField) * ifd.count; - ifd.fields = (TiffField *)wapp_mem_arena_alloc(arena, field_byte_count); - if (!(ifd.fields)) { - return NULL_TIFF_IFD; + u64 field_byte_count = sizeof(TiffField) * reader->ifd.count; + reader->ifd.fields = + (TiffField *)wapp_mem_arena_alloc(arena, field_byte_count); + if (!(reader->ifd.fields)) { + reader->ifd = NULL_TIFF_IFD; } - fread(ifd.fields, field_byte_count, 1, reader->fp); - fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, reader->fp); - - return ifd; + fread(reader->ifd.fields, field_byte_count, 1, reader->fp); + fread(&(reader->ifd.next_ifd), sizeof(reader->ifd.next_ifd), 1, reader->fp); } -internal TiffImage read_ifd_fields(const TiffReader *reader) { - TiffImage img_out = NULL_TIFF_IMAGE; - img_out.type = TIFF_IMAGE_TYPE_BILEVEL; +internal void read_ifd_fields(TiffReader *reader) { + reader->img = NULL_TIFF_IMAGE; + reader->img.type = TIFF_IMAGE_TYPE_BILEVEL; for (u64 i = 0; i < reader->ifd.count; ++i) { TiffField *field = &(reader->ifd.fields[i]); @@ -256,122 +253,149 @@ internal TiffImage read_ifd_fields(const TiffReader *reader) { break; } - if (!read_field(field, &img_out)) { - img_out = NULL_TIFF_IMAGE; - goto READ_FIELDS_RETURN_IMAGE; + if (!read_field(field, &(reader->img))) { + reader->img = NULL_TIFF_IMAGE; + return; } } - if (!validate_image_type(&img_out)) { - img_out = NULL_TIFF_IMAGE; - goto READ_FIELDS_RETURN_IMAGE; + if (!validate_image_type(&(reader->img))) { + reader->img = NULL_TIFF_IMAGE; + return; } - img_out.alpha = read_alpha(reader, &img_out); - img_out.rgba_bits_per_sample = read_bits_per_sample(reader, &img_out); + read_alpha(reader); + read_bits_per_sample(reader); #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); - printf("EXTRA SAMPLES (samples, count, is offset) : %u, %u, %u\n", img_out.extra_samples, img_out.extra_samples_count, img_out.extra_samples_offset); - printf("ALPHA (type, offset) : %u, %u\n", img_out.alpha.type, img_out.alpha.sample_offset); - printf("SAMPLES PER PIXEL : %u\n", img_out.sample_count); - printf("PHOTOMETRIC INTERPRETATION : %u\n", img_out.photometric_interpretation); - printf("ROWS PER STRIP (rows, strip count) : %u, %u\n", img_out.rows_per_strip, img_out.strip_count); - printf("STRIP OFFSETS (offsets, is offset) : %u, %u\n", img_out.strip_offsets.long_val, img_out.strip_offsets_offset); - printf("STRIP BYTES (byte count, is offset) : %u, %u\n", img_out.strip_byte_counts.long_val, img_out.strip_byte_counts_offset); + printf("SIZE (width, height) : %u, %u\n", reader->img.image_width, reader->img.image_length); + printf("SAMPLES (bits per sample, count, is offset) : %u, %u, %u\n", reader->img.bits_per_sample, reader->img.sample_count, reader->img.bits_per_sample_offset); + printf("EXTRA SAMPLES (samples, count, is offset) : %u, %u, %u\n", reader->img.extra_samples, reader->img.extra_samples_count, reader->img.extra_samples_offset); + printf("ALPHA (type, offset) : %u, %u\n", reader->img.alpha.type, reader->img.alpha.sample_offset); + printf("SAMPLES PER PIXEL : %u\n", reader->img.sample_count); + printf("PHOTOMETRIC INTERPRETATION : %u\n", reader->img.photometric_interpretation); + printf("ROWS PER STRIP (rows, strip count) : %u, %u\n", reader->img.rows_per_strip, reader->img.strip_count); + printf("STRIP OFFSETS (offsets, is offset) : %u, %u\n", reader->img.strip_offsets.long_val, reader->img.strip_offsets_offset); + printf("STRIP BYTES (byte count, is offset) : %u, %u\n", reader->img.strip_byte_counts.long_val, reader->img.strip_byte_counts_offset); // clang-format on #endif - -READ_FIELDS_RETURN_IMAGE: - return img_out; } -internal TiffAlpha read_alpha(const TiffReader *reader, TiffImage *img) { - TiffAlpha alpha = NULL_TIFF_ALPHA; - u16 samples[img->extra_samples_count]; +internal void read_alpha(TiffReader *reader) { + reader->img.alpha = NULL_TIFF_ALPHA; + u16 samples[reader->img.extra_samples_count]; - if (img->extra_samples_count == 0) { - goto READ_ALPHA_RETURN; + if (reader->img.extra_samples_count == 0) { + reader->img.alpha = NULL_TIFF_ALPHA; + return; } - u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->extra_samples_count; + u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.extra_samples_count; memset(samples, 0, byte_count); - if (img->extra_samples_offset) { + if (reader->img.extra_samples_offset) { read_from_file_with_offset(reader->fp, samples, byte_count, - img->extra_samples); + reader->img.extra_samples); + + switch (reader->header.order) { + case TIFF_ORDER_BIG_ENDIAN: + if (IS_LITTLE_ENDIAN) { + for (u64 i = 0; i < reader->img.extra_samples_count; ++i) { + samples[i] = ntohs(samples[i]); + } + } + break; + case TIFF_ORDER_LITTLE_ENDIAN: + if (IS_BIG_ENDIAN) { + for (u64 i = 0; i < reader->img.extra_samples_count; ++i) { + samples[i] = htons(samples[i]); + } + } + break; + } } else { - memcpy(samples, &(img->extra_samples), byte_count); + memcpy(samples, &(reader->img.extra_samples), byte_count); } - for (u32 i = 0; i < img->extra_samples_count; ++i) { + for (u32 i = 0; i < reader->img.extra_samples_count; ++i) { u16 *sample = &(samples[i]); if (*sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA || *sample == TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA) { - alpha.type = *sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA - ? ALPHA_TYPE_ASSOCIATED - : ALPHA_TYPE_UNASSOCIATED; - alpha.sample_offset = i; + reader->img.alpha.type = *sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA + ? ALPHA_TYPE_ASSOCIATED + : ALPHA_TYPE_UNASSOCIATED; + reader->img.alpha.sample_offset = i; break; } } - -READ_ALPHA_RETURN: - return alpha; } -internal TiffSampleBits read_bits_per_sample(const TiffReader *reader, - TiffImage *img) { - TiffAlpha alpha = img->alpha; - u64 main_samples = img->sample_count - img->extra_samples_count; +internal void read_bits_per_sample(TiffReader *reader) { + TiffAlpha alpha = reader->img.alpha; + u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count; - u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->sample_count; - u16 bits_per_sample[img->sample_count]; + u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.sample_count; + u16 bits_per_sample[reader->img.sample_count]; memset(bits_per_sample, 0, byte_count); - if (img->bits_per_sample_offset) { + if (reader->img.bits_per_sample_offset) { read_from_file_with_offset(reader->fp, bits_per_sample, byte_count, - img->bits_per_sample); + reader->img.bits_per_sample); + + switch (reader->header.order) { + case TIFF_ORDER_BIG_ENDIAN: + if (IS_LITTLE_ENDIAN) { + for (u64 i = 0; i < reader->img.sample_count; ++i) { + bits_per_sample[i] = ntohs(bits_per_sample[i]); + } + } + break; + case TIFF_ORDER_LITTLE_ENDIAN: + if (IS_BIG_ENDIAN) { + for (u64 i = 0; i < reader->img.sample_count; ++i) { + bits_per_sample[i] = htons(bits_per_sample[i]); + } + } + break; + } } else { - memcpy(bits_per_sample, &(img->bits_per_sample), byte_count); + memcpy(bits_per_sample, &(reader->img.bits_per_sample), byte_count); } - TiffSampleBits bits = {0}; - memcpy(&bits, bits_per_sample, TIFF_SHORT_BYTE_COUNT * main_samples); + TiffSampleBits *bits = &(reader->img.rgba_bits_per_sample); + *bits = (TiffSampleBits){0}; + memcpy(bits, bits_per_sample, TIFF_SHORT_BYTE_COUNT * main_samples); // Set missing samples if image doesn't have all RGB samples if (main_samples < RGB_SAMPLE_COUNT) { u64 count = RGB_SAMPLE_COUNT - main_samples; for (u64 i = 0; i < count; ++i) { u16 *value = &(((u16 *)(&bits))[main_samples + i]); - *value = MINIMUM_BITS_PER_SAMPLE; + *value = MIN_BITS_PER_SAMPLE; } } if (alpha.type == ALPHA_TYPE_UNDEFINED) { - bits.a = MINIMUM_BITS_PER_SAMPLE; + bits->a = MIN_BITS_PER_SAMPLE; } else { void *alpha_sample = &(bits_per_sample[main_samples + alpha.sample_offset]); - memcpy(&(bits.a), alpha_sample, TIFF_SHORT_BYTE_COUNT); + memcpy(&(bits->a), alpha_sample, TIFF_SHORT_BYTE_COUNT); } - bits.r = bits.r < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.r; - bits.g = bits.g < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.g; - bits.b = bits.b < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.b; - bits.a = bits.a < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.a; - - return bits; + bits->r = bits->r < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->r; + bits->g = bits->g < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->g; + bits->b = bits->b < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->b; + bits->a = bits->a < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->a; } -internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) { - Pixel *buf = NULL; +internal void load_image_pixels(TiffReader *reader, Arena *arena) { + reader->pixels = NULL; u64 img_byte_count = sizeof(Pixel) * reader->img.image_width * reader->img.image_length; if (!read_strip_data(reader, arena)) { - goto LOAD_IMAGE_PIXELS_RETURN; + return; } #ifdef DEBUG @@ -381,15 +405,12 @@ internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) { } #endif - buf = wapp_mem_arena_alloc(arena, img_byte_count); - if (!buf) { - goto LOAD_IMAGE_PIXELS_RETURN; + reader->pixels = wapp_mem_arena_alloc(arena, img_byte_count); + if (!reader->pixels) { + return; } - read_strips(reader, buf); - -LOAD_IMAGE_PIXELS_RETURN: - return buf; + read_strips(reader); } internal bool read_strip_data(TiffReader *reader, Arena *arena) { @@ -438,7 +459,7 @@ internal bool read_strip_data(TiffReader *reader, Arena *arena) { return true; } -internal void read_strips(const TiffReader *reader, Pixel *buf) { +internal void read_strips(TiffReader *reader) { u64 position = 0; u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count; TiffAlpha alpha = reader->img.alpha; @@ -451,7 +472,7 @@ internal void read_strips(const TiffReader *reader, Pixel *buf) { const TiffStrip *strip = &(reader->img.strips[i]); for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { - p = &(buf[position]); + p = &(reader->pixels[position]); start_offset = strip->offset + j * reader->img.sample_count; alpha_offset = start_offset + main_samples + alpha.sample_offset;