Implement reading RGB and RGBA images
This commit is contained in:
		| @@ -3,6 +3,7 @@ | |||||||
| #include "endianness.h" | #include "endianness.h" | ||||||
| #include "image.h" | #include "image.h" | ||||||
| #include "mem_arena.h" | #include "mem_arena.h" | ||||||
|  | #include <assert.h> | ||||||
| #include <math.h> | #include <math.h> | ||||||
| #include <netinet/in.h> | #include <netinet/in.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| @@ -35,7 +36,8 @@ | |||||||
| 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); | ||||||
| bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips); | bool read_strip_data(FILE *fp, const TiffHdr *header, const TiffImage *img, | ||||||
|  |                      TiffStrip *strips); | ||||||
| void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, | void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, | ||||||
|                  Pixel *buf); |                  Pixel *buf); | ||||||
| bool read_field(const TiffField *field, TiffImage *img, | bool read_field(const TiffField *field, TiffImage *img, | ||||||
| @@ -96,7 +98,7 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { | |||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (!read_strip_data(fp, &img, strips)) { |   if (!read_strip_data(fp, &header, &img, strips)) { | ||||||
|     goto READ_BASELINE_DESTROY_ARENA; |     goto READ_BASELINE_DESTROY_ARENA; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -260,7 +262,8 @@ READ_FIELDS_RETURN_IMAGE: | |||||||
|   return img_out; |   return img_out; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { | bool read_strip_data(FILE *fp, const TiffHdr *header, const TiffImage *img, | ||||||
|  |                      TiffStrip *strips) { | ||||||
|   if (!fp || !img || !strips) { |   if (!fp || !img || !strips) { | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| @@ -285,6 +288,21 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { | |||||||
|     if (offsets_total_bytes > sizeof(u32)) { |     if (offsets_total_bytes > sizeof(u32)) { | ||||||
|       u32 offset = img->strip_offsets.long_val + offset_size * i; |       u32 offset = img->strip_offsets.long_val + offset_size * i; | ||||||
|       read_from_file_with_offset(fp, &(strip->offset), offset_size, offset); |       read_from_file_with_offset(fp, &(strip->offset), offset_size, offset); | ||||||
|  |  | ||||||
|  |       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 { |     } else { | ||||||
|       memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size); |       memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size); | ||||||
|     } |     } | ||||||
| @@ -292,6 +310,23 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { | |||||||
|     if (byte_count_total_bytes > sizeof(u32)) { |     if (byte_count_total_bytes > sizeof(u32)) { | ||||||
|       u32 offset = img->strip_byte_counts.long_val + counts_size * i; |       u32 offset = img->strip_byte_counts.long_val + counts_size * i; | ||||||
|       read_from_file_with_offset(fp, &(strip->byte_count), counts_size, offset); |       read_from_file_with_offset(fp, &(strip->byte_count), counts_size, offset); | ||||||
|  |  | ||||||
|  |       switch (header->order) { | ||||||
|  |       case TIFF_ORDER_BIG_ENDIAN: | ||||||
|  |         if (IS_LITTLE_ENDIAN) { | ||||||
|  |           strip->byte_count = counts_size > sizeof(u16) | ||||||
|  |                                   ? ntohl(strip->byte_count) | ||||||
|  |                                   : ntohs(strip->byte_count); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       case TIFF_ORDER_LITTLE_ENDIAN: | ||||||
|  |         if (IS_BIG_ENDIAN) { | ||||||
|  |           strip->byte_count = counts_size > sizeof(u16) | ||||||
|  |                                   ? htonl(strip->byte_count) | ||||||
|  |                                   : htons(strip->byte_count); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|     } else { |     } else { | ||||||
|       memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), |       memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), | ||||||
|              counts_size); |              counts_size); | ||||||
| @@ -303,15 +338,24 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { | |||||||
|  |  | ||||||
| void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, | void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, | ||||||
|                  Pixel *buf) { |                  Pixel *buf) { | ||||||
|  |   assert((img->sample_count == 3 || img->sample_count == 4) && | ||||||
|  |          "Only RGB or RGBA images supported"); | ||||||
|  |  | ||||||
|  |   u64 position = 0; | ||||||
|   for (u64 i = 0; i < img->strip_count; ++i) { |   for (u64 i = 0; i < img->strip_count; ++i) { | ||||||
|     const TiffStrip *strip = &(strips[i]); |     const TiffStrip *strip = &(strips[i]); | ||||||
|  |  | ||||||
|     for (u64 j = 0; j < img->image_width * img->image_length; ++j) { |     for (u64 j = 0; j < strip->byte_count / img->sample_count; ++j) { | ||||||
|       Pixel *p = &(buf[j]); |       Pixel *p = &(buf[position]); | ||||||
|  |  | ||||||
|       read_from_file_with_offset(fp, p, 3, strip->offset + j * 3); |       read_from_file_with_offset(fp, p, img->sample_count, | ||||||
|  |                                  strip->offset + j * img->sample_count); | ||||||
|  |  | ||||||
|       p->a = 255; |       if (img->sample_count == 3) { | ||||||
|  |         p->a = 255; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ++position; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user