From 69c13b83eac2eabac55cfbae3cbc9b820303815b Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Wed, 1 May 2024 00:17:53 +0100 Subject: [PATCH] Read strip data --- src/tiff/tiffread.c | 99 ++++++++++++++++++++++++++++++++++++++------- src/tiff/tiffread.h | 20 ++++++++- 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index 249eefc..7ab390b 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -35,6 +35,7 @@ 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); +bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips); bool read_field(const TiffField *field, TiffImage *img, u32 *image_type_identifier); bool validate_image_type(const TiffImage *img, @@ -78,7 +79,29 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, arena); - read_fields(fp, &header, &ifd); + TiffImage img = read_fields(fp, &header, &ifd); + + Arena *temp = NULL; + if (!wapp_mem_arena_init(&temp, 1 * 1024 * 1024)) { + goto READ_BASELINE_FILE_CLEANUP; + } + + TiffStrip *strips = + wapp_mem_arena_alloc(temp, sizeof(TiffStrip) * img.strip_count); + if (!strips) { + goto READ_BASELINE_DESTROY_ARENA; + } + + if (!read_strip_data(fp, &img, strips)) { + goto READ_BASELINE_DESTROY_ARENA; + } + + for (u32 i = 0; i < img.strip_count; ++i) { + printf("%u, %u\n", strips[i].offset, strips[i].byte_count); + } + +READ_BASELINE_DESTROY_ARENA: + wapp_mem_arena_destroy(&temp); READ_BASELINE_FILE_CLEANUP: fclose(fp); @@ -92,10 +115,8 @@ TiffHdr read_tiff_header(FILE *fp) { return NULL_TIFF_HEADER; } - fseek(fp, 0, SEEK_SET); - TiffHdr header = NULL_TIFF_HEADER; - fread((void *)&header, sizeof(TiffHdr), 1, fp); + read_from_file_with_offset(fp, &header, sizeof(TiffHdr), 0); switch (header.order) { case TIFF_ORDER_LITTLE_ENDIAN: @@ -128,11 +149,8 @@ TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena) { return NULL_TIFF_IFD; } - fseek(fp, offset, SEEK_SET); - TiffIFD ifd = NULL_TIFF_IFD; - - fread(&(ifd.count), sizeof(ifd.count), 1, fp); + read_from_file_with_offset(fp, &(ifd.count), sizeof(ifd.count), offset); switch (header->order) { case TIFF_ORDER_LITTLE_ENDIAN: @@ -220,8 +238,8 @@ TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { 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, img_out.strip_offsets_offset); - printf("STRIP BYTES (byte count, is offset) : %u, %u\n", img_out.strip_byte_counts, img_out.strip_byte_counts_offset); + 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); // clang-format on #endif @@ -229,6 +247,47 @@ READ_FIELDS_RETURN_IMAGE: return img_out; } +bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { + if (!fp || !img || !strips) { + return false; + } + + u32 offsets_total_bytes = + img->strip_count * img->strip_offsets_type_byte_count; + u32 byte_count_total_bytes = + img->strip_count * img->strip_byte_count_type_byte_count; + + if ((!(img->strip_offsets_offset) && offsets_total_bytes > sizeof(u32)) || + (!(img->strip_byte_counts_offset) && + byte_count_total_bytes > sizeof(u32))) { + return false; + } + + for (u32 i = 0; i < img->strip_count; ++i) { + TiffStrip *strip = &(strips[i]); + + u16 offset_size = img->strip_offsets_type_byte_count; + u16 counts_size = 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); + } else { + memcpy(&(strip->offset), &(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); + } else { + memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), + counts_size); + } + } + + return true; +} + bool read_field(const TiffField *field, TiffImage *img, u32 *image_type_identifier) { switch (field->tag) { @@ -281,7 +340,13 @@ bool read_field(const TiffField *field, TiffImage *img, break; case TIFF_PUBLIC_TAG_STRIP_OFFSETS: - img->strip_offsets = field->value_offset; + img->strip_offsets_type_byte_count = field_types[field->type].byte_count; + + if (img->strip_offsets_type_byte_count == sizeof(u16)) { + img->strip_offsets.short_val = field->value_offset; + } else if (img->strip_offsets_type_byte_count == sizeof(u32)) { + img->strip_offsets.long_val = field->value_offset; + } if (img->strip_count == INVALID_STRIP_COUNT) { img->strip_count = field->count; @@ -290,7 +355,7 @@ bool read_field(const TiffField *field, TiffImage *img, } img->strip_offsets_offset = - img->strip_count * field_types[field->type].byte_count > 4; + img->strip_count * img->strip_offsets_type_byte_count > 4; break; case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL: @@ -320,7 +385,13 @@ bool read_field(const TiffField *field, TiffImage *img, break; case TIFF_PUBLIC_TAG_STRIP_BYTE_COUNTS: - img->strip_byte_counts = field->value_offset; + img->strip_byte_count_type_byte_count = field_types[field->type].byte_count; + + if (img->strip_byte_count_type_byte_count == sizeof(u16)) { + img->strip_byte_counts.short_val = field->value_offset; + } else if (img->strip_byte_count_type_byte_count == sizeof(u32)) { + img->strip_byte_counts.long_val = field->value_offset; + } if (img->strip_count == INVALID_STRIP_COUNT) { img->strip_count = field->count; @@ -329,7 +400,7 @@ bool read_field(const TiffField *field, TiffImage *img, } img->strip_byte_counts_offset = - img->strip_count * field_types[field->type].byte_count > 4; + img->strip_count * img->strip_byte_count_type_byte_count > 4; break; case TIFF_PUBLIC_TAG_COLOR_MAP: diff --git a/src/tiff/tiffread.h b/src/tiff/tiffread.h index 0123af0..7d629c4 100644 --- a/src/tiff/tiffread.h +++ b/src/tiff/tiffread.h @@ -12,6 +12,14 @@ extern "C" { #define TYPE_MAX_COUNT (UINT8_MAX * sizeof(const char *)) +typedef struct short_long_value ShortLongValue; +struct short_long_value { + union { + u16 short_val; + u32 long_val; + }; +}; + typedef struct hdr TiffHdr; struct hdr { u16 order; @@ -113,10 +121,12 @@ struct tiff_image { bool bits_per_sample_offset; u16 compression; u16 photometric_interpretation; - u32 strip_offsets; + u16 strip_offsets_type_byte_count; + ShortLongValue strip_offsets; bool strip_offsets_offset; u32 rows_per_strip; - u32 strip_byte_counts; + u16 strip_byte_count_type_byte_count; + ShortLongValue strip_byte_counts; bool strip_byte_counts_offset; u32 strip_count; u32 color_map; @@ -125,6 +135,12 @@ struct tiff_image { bool extra_samples_offset; }; +typedef struct tiff_strip TiffStrip; +struct tiff_strip { + u32 offset; + u32 byte_count; +}; + Image *read_baseline_tiff(const char *file, Arena *arena); #ifdef __cplusplus