Add TiffReader struct
This commit is contained in:
		| @@ -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; | ||||
|       } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user