Refactor loading image data
This commit is contained in:
		| @@ -33,16 +33,18 @@ | |||||||
|  |  | ||||||
| #define INVALID_ALPHA_OFFSET -1 | #define INVALID_ALPHA_OFFSET -1 | ||||||
|  |  | ||||||
|  | #define TEMP_ARENA_CAPACITY (20 * 1024 * 1024) | ||||||
|  |  | ||||||
| TiffHdr read_tiff_header(FILE *fp); | TiffHdr read_tiff_header(FILE *fp); | ||||||
| TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); | TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); | ||||||
| TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd); | 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, | bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, | ||||||
|                      Arena *arena); |                      Arena *arena); | ||||||
| void read_strips(FILE *fp, const TiffImage *img, Pixel *buf); | void read_strips(FILE *fp, const TiffImage *img, Pixel *buf); | ||||||
| bool read_field(const TiffField *field, TiffImage *img, | bool read_field(const TiffField *field, TiffImage *img); | ||||||
|                 u32 *image_type_identifier); | bool validate_image_type(const TiffImage *img); | ||||||
| bool validate_image_type(const TiffImage *img, |  | ||||||
|                          const u32 *image_type_identifier); |  | ||||||
| void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); | void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); | ||||||
|  |  | ||||||
| Image *read_baseline_tiff(const char *file, Arena *arena) { | 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; |     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); |   TiffHdr header = read_tiff_header(fp); | ||||||
|   if (IS_NULL_HEADER(header)) { |   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; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   for (u32 i = 0; i < img.strip_count; ++i) { |   TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, temp_arena); | ||||||
|     printf("%u, %u\n", img.strips[i].offset, img.strips[i].byte_count); |   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) { |   if (!buf) { | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   read_strips(fp, &img, buf); |  | ||||||
|  |  | ||||||
|   img_out = create_image(img.image_width, img.image_length, buf, arena); |   img_out = create_image(img.image_width, img.image_length, buf, arena); | ||||||
|  |  | ||||||
| READ_BASELINE_DESTROY_ARENA: | READ_BASELINE_DESTROY_ARENA: | ||||||
|   wapp_mem_arena_destroy(&temp); |   wapp_mem_arena_destroy(&temp_arena); | ||||||
|  |  | ||||||
| READ_BASELINE_FILE_CLEANUP: | READ_BASELINE_FILE_CLEANUP: | ||||||
|   fclose(fp); |   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 read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { | ||||||
|   TiffImage img_out = NULL_TIFF_IMAGE; |   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) { |   for (u64 i = 0; i < ifd->count; ++i) { | ||||||
|     TiffField *field = &(ifd->fields[i]); |     TiffField *field = &(ifd->fields[i]); | ||||||
| @@ -228,20 +224,18 @@ TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd) { | |||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (!read_field(field, &img_out, &image_type_identifier)) { |     if (!read_field(field, &img_out)) { | ||||||
|       img_out = NULL_TIFF_IMAGE; |       img_out = NULL_TIFF_IMAGE; | ||||||
|       goto READ_FIELDS_RETURN_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; |     img_out = NULL_TIFF_IMAGE; | ||||||
|     goto READ_FIELDS_RETURN_IMAGE; |     goto READ_FIELDS_RETURN_IMAGE; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   img_out.type = image_type_identifier; | #ifdef DEBUG | ||||||
|  |  | ||||||
| #if 1 |  | ||||||
|   // clang-format off |   // clang-format off | ||||||
|   printf("SIZE (width, height)                          :   %u, %u\n", img_out.image_width, img_out.image_length); |   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("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; |   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, | bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img, | ||||||
|                      Arena *arena) { |                      Arena *arena) { | ||||||
|   if (!fp || !img || !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, | bool read_field(const TiffField *field, TiffImage *img) { | ||||||
|                 u32 *image_type_identifier) { |  | ||||||
|   switch (field->tag) { |   switch (field->tag) { | ||||||
|   case TIFF_PUBLIC_TAG_IMAGE_WIDTH: |   case TIFF_PUBLIC_TAG_IMAGE_WIDTH: | ||||||
|     if (field->count > 1) { |     if (field->count > 1) { | ||||||
| @@ -378,7 +397,7 @@ bool read_field(const TiffField *field, TiffImage *img, | |||||||
|  |  | ||||||
|     break; |     break; | ||||||
|   case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE: |   case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE: | ||||||
|     *image_type_identifier |= field->tag; |     img->type |= field->tag; | ||||||
|  |  | ||||||
|     if (img->sample_count == INVALID_SAMPLE_COUNT) { |     if (img->sample_count == INVALID_SAMPLE_COUNT) { | ||||||
|       img->sample_count = field->count; |       img->sample_count = field->count; | ||||||
| @@ -429,7 +448,7 @@ bool read_field(const TiffField *field, TiffImage *img, | |||||||
|  |  | ||||||
|     break; |     break; | ||||||
|   case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL: |   case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL: | ||||||
|     *image_type_identifier |= field->tag; |     img->type |= field->tag; | ||||||
|  |  | ||||||
|     if (field->count > 1) { |     if (field->count > 1) { | ||||||
|       return false; |       return false; | ||||||
| @@ -474,7 +493,7 @@ bool read_field(const TiffField *field, TiffImage *img, | |||||||
|  |  | ||||||
|     break; |     break; | ||||||
|   case TIFF_PUBLIC_TAG_COLOR_MAP: |   case TIFF_PUBLIC_TAG_COLOR_MAP: | ||||||
|     *image_type_identifier |= field->tag; |     img->type |= field->tag; | ||||||
|     break; |     break; | ||||||
|   case TIFF_PUBLIC_TAG_EXTRA_SAMPLES: |   case TIFF_PUBLIC_TAG_EXTRA_SAMPLES: | ||||||
|     img->extra_samples_count = field->count; |     img->extra_samples_count = field->count; | ||||||
| @@ -496,14 +515,12 @@ bool read_field(const TiffField *field, TiffImage *img, | |||||||
|   return true; |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool validate_image_type(const TiffImage *img, | bool validate_image_type(const TiffImage *img) { | ||||||
|                          const u32 *image_type_identifier) { |   if (img->type < TIFF_IMAGE_TYPE_BILEVEL || img->type > TIFF_IMAGE_TYPE_RGB) { | ||||||
|   if (*image_type_identifier < TIFF_IMAGE_TYPE_BILEVEL || |  | ||||||
|       *image_type_identifier > TIFF_IMAGE_TYPE_RGB) { |  | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   switch (*image_type_identifier) { |   switch (img->type) { | ||||||
|   case TIFF_IMAGE_TYPE_BILEVEL: |   case TIFF_IMAGE_TYPE_BILEVEL: | ||||||
|   case TIFF_IMAGE_TYPE_GRAYSCALE: |   case TIFF_IMAGE_TYPE_GRAYSCALE: | ||||||
|     if (img->photometric_interpretation > |     if (img->photometric_interpretation > | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user