First botched attempt at reading image data :D
This commit is contained in:
		
							
								
								
									
										627
									
								
								src/tiff/tiffread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								src/tiff/tiffread.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,627 @@ | ||||
| #include "tiffread.h" | ||||
| #include "aliases.h" | ||||
| #include "endianness.h" | ||||
| #include "image.h" | ||||
| #include "mem_allocator.h" | ||||
| #include "mem_arena.h" | ||||
| #include "mem_ctx.h" | ||||
| #include "mem_libc.h" | ||||
| #include <math.h> | ||||
| #include <netinet/in.h> | ||||
| #include <stdbool.h> | ||||
| #include <stddef.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
|  | ||||
| #define TIFF_MAGIC 0x002a | ||||
|  | ||||
| #define TIFF_FILENAME_MIN_LENGTH 6 | ||||
| #define TIFF_EXT_MAX_LENGTH 5 | ||||
| #define IS_TIFF_EXTENSION(EXT)                                                 \ | ||||
|   (strncmp(EXT, ".tif", 4) == 0 || strncmp(EXT, ".tiff", 5) == 0) | ||||
|  | ||||
| #define NULL_TIFF_HEADER ((TiffHdr){0}) | ||||
| #define IS_NULL_HEADER(HDR) (HDR.order == 0) | ||||
|  | ||||
| #define NULL_TIFF_IFD ((TiffIFD){0}) | ||||
| #define IS_NULL_IFD(IFD) (IFD.count == 0) | ||||
|  | ||||
| #define INVALID_STRIP_COUNT 0 | ||||
|  | ||||
| #define INVALID_ALPHA_OFFSET -1 | ||||
|  | ||||
| // clang-format off | ||||
| enum tiff_image_identifiers { | ||||
|   TIFF_IMAGE_BILEVEL   = 0, | ||||
|   TIFF_IMAGE_GRAYSCALE = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE, | ||||
|   TIFF_IMAGE_PALETTE   = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_COLOR_MAP, | ||||
|   TIFF_IMAGE_RGB       = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL, | ||||
| }; | ||||
|  | ||||
| enum tiff_extra_samples { | ||||
|   TIFF_EXTRA_SAMPLE_UNSPECIFIED        = 0x0000, | ||||
|   TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA   = 0x0001, | ||||
|   TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA = 0x0002, | ||||
| }; | ||||
| // clang-format on | ||||
|  | ||||
| TiffHdr read_tiff_header(FILE *fp); | ||||
| TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, | ||||
|                  const Allocator *allocator); | ||||
| Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd, | ||||
|                    const Allocator *allocator); | ||||
| void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset); | ||||
|  | ||||
| Image *read_baseline_tiff(const char *file, const Allocator *allocator) { | ||||
|   Image *img_out = NULL; | ||||
|  | ||||
|   if (!file) { | ||||
|     goto READ_BASELINE_RETURN_IMG; | ||||
|   } | ||||
|  | ||||
|   u64 name_length = strlen(file); | ||||
|   if (name_length < TIFF_FILENAME_MIN_LENGTH) { | ||||
|     goto READ_BASELINE_RETURN_IMG; | ||||
|   } | ||||
|  | ||||
|   const char *ext = NULL; | ||||
|   for (u32 i = name_length - 1; i >= name_length - TIFF_FILENAME_MIN_LENGTH; | ||||
|        --i) { | ||||
|     if (file[i] == '.') { | ||||
|       ext = &(file[i]); | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (!ext || !IS_TIFF_EXTENSION(ext)) { | ||||
|     goto READ_BASELINE_RETURN_IMG; | ||||
|   } | ||||
|  | ||||
|   FILE *fp = fopen(file, "rb"); | ||||
|   if (!fp) { | ||||
|     goto READ_BASELINE_RETURN_IMG; | ||||
|   } | ||||
|  | ||||
|   TiffHdr header = read_tiff_header(fp); | ||||
|   if (IS_NULL_HEADER(header)) { | ||||
|     goto READ_BASELINE_FILE_CLEANUP; | ||||
|   } | ||||
|  | ||||
|   Allocator alloc; | ||||
|   if (!allocator) { | ||||
|     alloc = wapp_mem_libc_allocator(); | ||||
|   } else { | ||||
|     alloc = *allocator; | ||||
|   } | ||||
|  | ||||
|   TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, &alloc); | ||||
|   img_out = read_fields(fp, &header, &ifd, &alloc); | ||||
|  | ||||
| READ_BASELINE_FILE_CLEANUP: | ||||
|   fclose(fp); | ||||
|  | ||||
| READ_BASELINE_RETURN_IMG: | ||||
|   return img_out; | ||||
| } | ||||
|  | ||||
| TiffHdr read_tiff_header(FILE *fp) { | ||||
|   if (!fp) { | ||||
|     return NULL_TIFF_HEADER; | ||||
|   } | ||||
|  | ||||
|   fseek(fp, 0, SEEK_SET); | ||||
|  | ||||
|   TiffHdr header = NULL_TIFF_HEADER; | ||||
|   fread((void *)&header, sizeof(TiffHdr), 1, fp); | ||||
|  | ||||
|   switch (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); | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   case TIFF_ORDER_BIG_ENDIAN: | ||||
|     if (IS_LITTLE_ENDIAN) { | ||||
|       header.magic = ntohs(header.magic); | ||||
|       header.first_ifd_offset = ntohl(header.first_ifd_offset); | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   default: | ||||
|     return NULL_TIFF_HEADER; | ||||
|   } | ||||
|  | ||||
|   if (header.magic != TIFF_MAGIC) { | ||||
|     return NULL_TIFF_HEADER; | ||||
|   } | ||||
|  | ||||
|   return header; | ||||
| } | ||||
|  | ||||
| TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, | ||||
|                  const Allocator *allocator) { | ||||
|   if (!fp || !header) { | ||||
|     return NULL_TIFF_IFD; | ||||
|   } | ||||
|  | ||||
|   fseek(fp, offset, SEEK_SET); | ||||
|  | ||||
|   TiffIFD ifd = NULL_TIFF_IFD; | ||||
|  | ||||
|   fread(&(ifd.count), sizeof(ifd.count), 1, fp); | ||||
|  | ||||
|   switch (header->order) { | ||||
|   case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|     if (IS_BIG_ENDIAN) { | ||||
|       ifd.count = htons(ifd.count); | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   case TIFF_ORDER_BIG_ENDIAN: | ||||
|     if (IS_LITTLE_ENDIAN) { | ||||
|       ifd.count = ntohs(ifd.count); | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   u64 field_byte_count = sizeof(TiffField) * ifd.count; | ||||
|   ifd.fields = | ||||
|       (TiffField *)wapp_mem_allocator_alloc(allocator, field_byte_count); | ||||
|  | ||||
|   fread(ifd.fields, field_byte_count, 1, fp); | ||||
|   fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, fp); | ||||
|  | ||||
|   return ifd; | ||||
| } | ||||
|  | ||||
| Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd, | ||||
|                    const Allocator *allocator) { | ||||
|   if (!fp || !header || !ifd) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   u16 identifier = 0; | ||||
|  | ||||
|   u16 photometric_interpretation = TIFF_PHOTOMETRIC_INTERPRETATION_INVALID; | ||||
|  | ||||
|   u16 samples_per_pixel = 1; | ||||
|   u16 *bits_per_sample = NULL; | ||||
|   u16 extra_samples = 0; | ||||
|   bool has_alpha = false; | ||||
|   bool associated_alpha = false; | ||||
|   i32 alpha_offset = | ||||
|       INVALID_ALPHA_OFFSET; // Alpha offset following colour samples | ||||
|  | ||||
|   u32 strip_count = INVALID_STRIP_COUNT; | ||||
|   u8 *strip_offsets = NULL; | ||||
|   u16 strip_offsets_type = TIFF_FIELD_TYPE_LONG; | ||||
|   u8 *strip_byte_counts = NULL; | ||||
|   u16 strip_byte_counts_type = TIFF_FIELD_TYPE_LONG; | ||||
|  | ||||
|   u64 width = 0; | ||||
|   u64 height = 0; | ||||
|  | ||||
|   for (u64 i = 0; i < ifd->count; ++i) { | ||||
|     TiffField *field = &(ifd->fields[i]); | ||||
|     switch (header->order) { | ||||
|     case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|       if (IS_BIG_ENDIAN) { | ||||
|         field->tag = htons(field->tag); | ||||
|         field->type = htons(field->type); | ||||
|         field->count = htonl(field->count); | ||||
|         field->value_offset = htonl(field->value_offset); | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     case TIFF_ORDER_BIG_ENDIAN: | ||||
|       if (IS_LITTLE_ENDIAN) { | ||||
|         field->tag = ntohs(field->tag); | ||||
|         field->type = ntohs(field->type); | ||||
|         field->count = ntohl(field->count); | ||||
|         field->value_offset = ntohl(field->value_offset); | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     switch (field->tag) { | ||||
|     case TIFF_PUBLIC_TAG_IMAGE_WIDTH: | ||||
|       if (field->count != 1) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       width = field->value_offset; | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_IMAGE_LENGTH: | ||||
|       if (field->count != 1) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       height = field->value_offset; | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_BITS_PER_SAMPLE: | ||||
|       identifier |= field->tag; | ||||
|  | ||||
|       u64 byte_count = field->count * sizeof(u16); | ||||
|       bits_per_sample = wapp_mem_ctx_alloc(CTX_DEST_BUFFER_TEMP, byte_count); | ||||
|       if (!bits_per_sample) { | ||||
|         break; | ||||
|       } | ||||
|  | ||||
|       if (byte_count <= 4) { | ||||
|         bits_per_sample = (u16 *)&(field->value_offset); | ||||
|       } else { | ||||
|         read_from_file_with_offset(fp, bits_per_sample, byte_count, | ||||
|                                    field->value_offset); | ||||
|  | ||||
|         for (u64 i = 0; i < field->count; ++i) { | ||||
|           switch (header->order) { | ||||
|           case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|             if (IS_BIG_ENDIAN) { | ||||
|               bits_per_sample[i] = htons(bits_per_sample[i]); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|           case TIFF_ORDER_BIG_ENDIAN: | ||||
|             if (IS_LITTLE_ENDIAN) { | ||||
|               bits_per_sample[i] = ntohs(bits_per_sample[i]); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_COMPRESSION: | ||||
|       if (field->count != 1) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       switch (field->value_offset) { | ||||
|       case TIFF_COMPRESSION_UNCOMPRESSED: | ||||
|         break; | ||||
|       case TIFF_COMPRESSION_CCITT_1D: | ||||
|       case TIFF_COMPRESSION_GROUP_3_FAX: | ||||
|       case TIFF_COMPRESSION_GROUP_4_FAX: | ||||
|       case TIFF_COMPRESSION_LZW: | ||||
|       case TIFF_COMPRESSION_JPEG: | ||||
|       case TIFF_COMPRESSION_PACK_BITS: | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_PHOTOMETRIC_INTERPRETATION: | ||||
|       photometric_interpretation = field->value_offset; | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_STRIP_OFFSETS: { | ||||
|       strip_offsets_type = field->type; | ||||
|       u16 field_type_byte_count = field_types[field->type].byte_count; | ||||
|       u32 total_byte_count = field->count * field_type_byte_count; | ||||
|  | ||||
|       if (strip_count == INVALID_STRIP_COUNT) { | ||||
|         strip_count = field->count; | ||||
|       } else { | ||||
|         if (strip_count != field->count) { | ||||
|           return NULL; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       strip_offsets = | ||||
|           (u8 *)wapp_mem_ctx_alloc(CTX_DEST_BUFFER_TEMP, total_byte_count); | ||||
|       if (!strip_offsets) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       if (total_byte_count <= 4) { | ||||
|         memcpy(strip_offsets, &(field->value_offset), 4); | ||||
|  | ||||
|         switch (header->order) { | ||||
|         case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|           if (IS_BIG_ENDIAN) { | ||||
|             u32 val = htonl(*(u32 *)strip_offsets); | ||||
|             strip_offsets = (u8 *)&val; | ||||
|           } | ||||
|  | ||||
|           break; | ||||
|         case TIFF_ORDER_BIG_ENDIAN: | ||||
|           if (IS_LITTLE_ENDIAN) { | ||||
|             u32 val = ntohl(*(u32 *)strip_offsets); | ||||
|             strip_offsets = (u8 *)&val; | ||||
|           } | ||||
|  | ||||
|           break; | ||||
|         } | ||||
|       } else { | ||||
|         read_from_file_with_offset(fp, strip_offsets, total_byte_count, | ||||
|                                    field->value_offset); | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     case TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL: | ||||
|       if (field->count != 1) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       identifier |= field->tag; | ||||
|       samples_per_pixel = field->value_offset; | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_ROWS_PER_STRIP: | ||||
|       if (field->count != 1 || height == 0) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       strip_count = | ||||
|           floor((f64)(height + field->value_offset - 1) / field->value_offset); | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_STRIP_BYTE_COUNTS: { | ||||
|       strip_byte_counts_type = field->type; | ||||
|       u16 field_type_byte_count = field_types[field->type].byte_count; | ||||
|       u32 total_byte_count = field->count * field_type_byte_count; | ||||
|  | ||||
|       if (strip_count == INVALID_STRIP_COUNT) { | ||||
|         strip_count = field->count; | ||||
|       } else { | ||||
|         if (strip_count != field->count) { | ||||
|           return NULL; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       strip_byte_counts = | ||||
|           (u8 *)wapp_mem_ctx_alloc(CTX_DEST_BUFFER_TEMP, total_byte_count); | ||||
|       if (!strip_byte_counts) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       if (total_byte_count <= 4) { | ||||
|         memcpy(strip_byte_counts, &(field->value_offset), 4); | ||||
|  | ||||
|         switch (header->order) { | ||||
|         case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|           if (IS_BIG_ENDIAN) { | ||||
|             u32 val = htonl(*(u32 *)strip_byte_counts); | ||||
|             strip_byte_counts = (u8 *)&val; | ||||
|           } | ||||
|  | ||||
|           break; | ||||
|         case TIFF_ORDER_BIG_ENDIAN: | ||||
|           if (IS_LITTLE_ENDIAN) { | ||||
|             u32 val = ntohl(*(u32 *)strip_byte_counts); | ||||
|             strip_byte_counts = (u8 *)&val; | ||||
|           } | ||||
|  | ||||
|           break; | ||||
|         } | ||||
|       } else { | ||||
|         read_from_file_with_offset(fp, strip_byte_counts, total_byte_count, | ||||
|                                    field->value_offset); | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|     case TIFF_PUBLIC_TAG_PLANAR_CONFIGURATION: | ||||
|       if (field->count != 1 || | ||||
|           field->value_offset != TIFF_PLANAR_CONFIG_CHUNKY) { | ||||
|         return NULL; | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_COLOR_MAP: | ||||
|       identifier |= field->tag; | ||||
|       break; | ||||
|     case TIFF_PUBLIC_TAG_EXTRA_SAMPLES: { | ||||
|       extra_samples = field->count; | ||||
|       u64 byte_count = field->count * sizeof(u16); | ||||
|  | ||||
|       u8 data_buf[byte_count]; | ||||
|  | ||||
|       if (byte_count <= 4) { | ||||
|         memcpy(data_buf, (void *)&(field->value_offset), byte_count); | ||||
|       } else { | ||||
|         read_from_file_with_offset(fp, data_buf, byte_count, | ||||
|                                    field->value_offset); | ||||
|       } | ||||
|  | ||||
|       for (u32 i = 0; i < field->count; ++i) { | ||||
|         u16 sample = ((u16 *)&(field->value_offset))[i]; | ||||
|  | ||||
|         if (byte_count > 4) { | ||||
|           switch (header->order) { | ||||
|           case TIFF_ORDER_LITTLE_ENDIAN: | ||||
|             if (IS_BIG_ENDIAN) { | ||||
|               sample = htons(sample); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|           case TIFF_ORDER_BIG_ENDIAN: | ||||
|             if (IS_LITTLE_ENDIAN) { | ||||
|               sample = ntohs(sample); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (sample > TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA) { | ||||
|           return NULL; | ||||
|         } | ||||
|  | ||||
|         if (sample > TIFF_EXTRA_SAMPLE_UNSPECIFIED) { | ||||
|           if (has_alpha) { | ||||
|             return NULL; | ||||
|           } | ||||
|  | ||||
|           has_alpha = true; | ||||
|           associated_alpha = | ||||
|               sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA ? true : false; | ||||
|           alpha_offset = i; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       break; | ||||
|     } | ||||
|     default: | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   switch (identifier) { | ||||
|   case TIFF_IMAGE_BILEVEL: | ||||
|   case TIFF_IMAGE_GRAYSCALE: | ||||
|     if (photometric_interpretation > | ||||
|         TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO) { | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   case TIFF_IMAGE_PALETTE: | ||||
|     if (photometric_interpretation != | ||||
|         TIFF_PHOTOMETRIC_INTERPRETATION_RGB_PALETTE) { | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   case TIFF_IMAGE_RGB: | ||||
|     if (photometric_interpretation != TIFF_PHOTOMETRIC_INTERPRETATION_RGB) { | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|     break; | ||||
|   default: | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   printf("WIDTH: %lu, HEIGHT: %lu\n", width, height); | ||||
|   printf("SAMPLES: %u\n", samples_per_pixel); | ||||
|   printf("EXTRA SAMPLES: %u\n", extra_samples); | ||||
|   printf("ALPHA: %s, %s, %d\n", has_alpha ? "HAS ALPHA" : "NO ALPHA", | ||||
|          has_alpha && associated_alpha ? "ASSOCIATED" | ||||
|          : has_alpha                   ? "UNASSOCIATED" | ||||
|                                        : "N/A", | ||||
|          alpha_offset); | ||||
|   printf("STRIPS: %u\n", strip_count); | ||||
|   printf("PHOTOMETRIC INTERPRETATION: %u\n", photometric_interpretation); | ||||
|   printf("BITS PER SAMPLE: "); | ||||
|   for (u64 i = 0; i < samples_per_pixel; ++i) { | ||||
|     printf("%u ", bits_per_sample[i]); | ||||
|   } | ||||
|   printf("\n"); | ||||
|  | ||||
|   if (has_alpha && alpha_offset == INVALID_ALPHA_OFFSET) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   Image *img_out = NULL; | ||||
|  | ||||
|   Arena *temp_arena; | ||||
|   u64 img_buf_size = width * height * sizeof(Pixel); | ||||
|   wapp_mem_arena_init(&temp_arena, img_buf_size * 4); | ||||
|  | ||||
|   u8 *temp_img_buf = wapp_mem_arena_alloc(temp_arena, img_buf_size); | ||||
|   if (!temp_img_buf) { | ||||
|     return NULL; | ||||
|   } | ||||
|  | ||||
|   u64 position = 0; | ||||
|   for (u64 i = 0; i < strip_count; ++i) { | ||||
|     u64 offset; | ||||
|     u64 count; | ||||
|  | ||||
|     if (strip_offsets_type == TIFF_FIELD_TYPE_LONG) { | ||||
|       offset = ((u32 *)strip_offsets)[i]; | ||||
|     } else { | ||||
|       offset = ((u16 *)strip_offsets)[i]; | ||||
|     } | ||||
|  | ||||
|     if (strip_byte_counts_type == TIFF_FIELD_TYPE_LONG) { | ||||
|       count = ((u32 *)strip_byte_counts)[i]; | ||||
|     } else { | ||||
|       count = ((u16 *)strip_byte_counts)[i]; | ||||
|     } | ||||
|  | ||||
|     u8 *strip_data = wapp_mem_arena_alloc(temp_arena, count); | ||||
|     read_from_file_with_offset(fp, strip_data, count, offset); | ||||
|  | ||||
|     if (samples_per_pixel == 4 && has_alpha) { | ||||
|       memcpy(&(temp_img_buf[position]), strip_data, count); | ||||
|       position += count; | ||||
|     } else if (samples_per_pixel > 4) { | ||||
|       for (u64 j = 0; j < count; ++j) { | ||||
|         memcpy(&(temp_img_buf[position]), &(strip_data[j]), 3); | ||||
|         j += 3; | ||||
|  | ||||
|         if (has_alpha) { | ||||
|           memcpy(&(temp_img_buf[position]), &(strip_data[j + alpha_offset]), 1); | ||||
|           j += 1; | ||||
|         } else { | ||||
|           temp_img_buf[position] = 255; | ||||
|         } | ||||
|  | ||||
|         j += samples_per_pixel - 4; | ||||
|         position += 1; | ||||
|       } | ||||
|     } else if (samples_per_pixel == 3) { | ||||
|       if (identifier == TIFF_IMAGE_RGB) { | ||||
|         for (u64 j = 0; j < count; ++j) { | ||||
|           memcpy(&(temp_img_buf[position]), &(strip_data[j]), 3); | ||||
|           j += 3; | ||||
|           position += 3; | ||||
|  | ||||
|           temp_img_buf[position++] = 255; | ||||
|         } | ||||
|       } else { | ||||
|         goto READ_FIELDS_FREE_ARENA; | ||||
|       } | ||||
|     } else if (samples_per_pixel == 1) { | ||||
|       if (identifier == TIFF_IMAGE_RGB) { | ||||
|         goto READ_FIELDS_FREE_ARENA; | ||||
|       } | ||||
|  | ||||
|       for (u64 j = 0; j < count; ++j) { | ||||
|         for (u64 k = 0; k < 3; ++k) { | ||||
|           memcpy(&(temp_img_buf[position]), &(strip_data[j]), 1); | ||||
|         } | ||||
|  | ||||
|         j += 1; | ||||
|         position += 3; | ||||
|  | ||||
|         if (has_alpha) { | ||||
|           memcpy(&(temp_img_buf[position]), &(strip_data[j + alpha_offset]), 1); | ||||
|           j += 1; | ||||
|         } else { | ||||
|           temp_img_buf[position] = 255; | ||||
|         } | ||||
|  | ||||
|         position += 1; | ||||
|       } | ||||
|     } else { | ||||
|       goto READ_FIELDS_FREE_ARENA; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   img_out = create_image(width, height, (Pixel *)temp_img_buf, allocator); | ||||
|  | ||||
| READ_FIELDS_FREE_ARENA: | ||||
|   wapp_mem_arena_free(&temp_arena); | ||||
|  | ||||
|   return img_out; | ||||
| } | ||||
|  | ||||
| void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset) { | ||||
|   if (!fp || !dst) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   fseek(fp, offset, SEEK_SET); | ||||
|  | ||||
|   fread(dst, count, 1, fp); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user