Initial implementation of the reader
This commit is contained in:
		
							
								
								
									
										56
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								src/main.c
									
									
									
									
									
								
							| @@ -1,44 +1,54 @@ | |||||||
| #include "aliases.h" | #include "aliases.h" | ||||||
|  | #include "mem_allocator.h" | ||||||
|  | #include "mem_ctx.h" | ||||||
| #include "tiffread.h" | #include "tiffread.h" | ||||||
| #include <netinet/in.h> | #include <netinet/in.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) { | int main(int argc, char *argv[]) { | ||||||
|  |   wapp_mem_ctx_init(10 * 1024 * 1024, 2 * 1024 * 1024); | ||||||
|  |   Allocator ctx_main_allocator = wapp_mem_ctx_allocator(CTX_DEST_BUFFER_MAIN); | ||||||
|  |   Allocator ctx_temp_allocator = wapp_mem_ctx_allocator(CTX_DEST_BUFFER_TEMP); | ||||||
|  |   (void)(ctx_temp_allocator); | ||||||
|  |  | ||||||
|   const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif"; |   const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif"; | ||||||
|  |  | ||||||
|   FILE *fp = fopen(file_to_open, "r"); |   read_baseline_tiff(file_to_open, &ctx_main_allocator); | ||||||
|  |  | ||||||
|   TiffHdr header; |   // FILE *fp = fopen(file_to_open, "rb"); | ||||||
|   TiffIFD ifd = {0}; |  | ||||||
|  |  | ||||||
|   fread(&header, sizeof(TiffHdr), 1, fp); |   // TiffHdr header; | ||||||
|  |   // fread(&header, sizeof(header), 1, fp); | ||||||
|  |  | ||||||
|   printf("ORDER: %04x\n", header.order); |   // TiffIFD ifd = {0}; | ||||||
|   printf("MAGIC: %04x\n", header.magic); |  | ||||||
|  |  | ||||||
|   fseek(fp, header.first_ifd_offset, SEEK_SET); |   // printf("ORDER: %04x\n", header.order); | ||||||
|  |   // printf("MAGIC: %04x\n", header.magic); | ||||||
|  |  | ||||||
|   fread(&(ifd.count), sizeof(ifd.count), 1, fp); |   // fseek(fp, header.first_ifd_offset, SEEK_SET); | ||||||
|  |  | ||||||
|   printf("COUNT: %u\n", ifd.count); |   // fread(&(ifd.count), sizeof(ifd.count), 1, fp); | ||||||
|  |  | ||||||
|   TiffField fields[ifd.count]; |   // printf("COUNT: %u\n", ifd.count); | ||||||
|   memset(fields, 0, sizeof(TiffField) * ifd.count); |  | ||||||
|  |  | ||||||
|   for (u32 i = 0; i < ifd.count; ++i) { |   // TiffField fields[ifd.count]; | ||||||
|     fread(fields + i, sizeof(TiffField), 1, fp); |   // memset(fields, 0, sizeof(TiffField) * ifd.count); | ||||||
|     printf("ENTRY %02u\n", i); |  | ||||||
|     printf("\t    TAG: %04u (%s)\n", fields[i].tag, |  | ||||||
|            tag_names[fields[i].tag] ? tag_names[fields[i].tag] : "UNKNOWN"); |  | ||||||
|     printf("\t   TYPE: 0x%04x (%s)\n", fields[i].type, |  | ||||||
|            filed_types[fields[i].type].name ? filed_types[fields[i].type].name |  | ||||||
|                                             : "UNKNOWN"); |  | ||||||
|     printf("\t  COUNT: %04u\n", fields[i].count); |  | ||||||
|     printf("\tVAL/OFF: %04u\n", fields[i].value_offset); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   fclose(fp); |   // for (u32 i = 0; i < ifd.count; ++i) { | ||||||
|  |   //   fread(fields + i, sizeof(TiffField), 1, fp); | ||||||
|  |   //   printf("ENTRY %02u (%lu)\n", i, ftell(fp)); | ||||||
|  |   //   printf("\t    TAG: %04u (%s)\n", fields[i].tag, | ||||||
|  |   //          tag_names[fields[i].tag] ? tag_names[fields[i].tag] : "UNKNOWN"); | ||||||
|  |   //   printf("\t   TYPE: 0x%04x (%s)\n", fields[i].type, | ||||||
|  |   //          field_types[fields[i].type].name ? | ||||||
|  |   //          field_types[fields[i].type].name | ||||||
|  |   //                                           : "UNKNOWN"); | ||||||
|  |   //   printf("\t  COUNT: %04u\n", fields[i].count); | ||||||
|  |   //   printf("\tVAL/OFF: %04u\n", fields[i].value_offset); | ||||||
|  |   // } | ||||||
|  |  | ||||||
|  |   wapp_mem_ctx_free(); | ||||||
|  |  | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										455
									
								
								src/tiffread.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								src/tiffread.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,455 @@ | |||||||
|  | #include "tiffread.h" | ||||||
|  | #include "aliases.h" | ||||||
|  | #include "endianness.h" | ||||||
|  | #include "image.h" | ||||||
|  | #include "mem_allocator.h" | ||||||
|  | #include "mem_ctx.h" | ||||||
|  | #include "mem_libc.h" | ||||||
|  | #include <math.h> | ||||||
|  | #include <netinet/in.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) | ||||||
|  |  | ||||||
|  | enum tiff_image_types { | ||||||
|  |   TIFF_IMAGE_BILEVEL, | ||||||
|  |   TIFF_IMAGE_GRAYSCALE, | ||||||
|  |   TIFF_IMAGE_PALETTE, | ||||||
|  |   TIFF_IMAGE_RGB, | ||||||
|  |  | ||||||
|  |   COUNT_TIFF_IMAGE, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // clang-format off | ||||||
|  | internal u16 tiff_image_identifiers[COUNT_TIFF_IMAGE] = { | ||||||
|  |   [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, | ||||||
|  | }; | ||||||
|  | // 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 RETURN_IMG; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   u64 name_length = strlen(file); | ||||||
|  |   if (name_length < TIFF_FILENAME_MIN_LENGTH) { | ||||||
|  |     goto 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 RETURN_IMG; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FILE *fp = fopen(file, "rb"); | ||||||
|  |   if (!fp) { | ||||||
|  |     goto RETURN_IMG; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   TiffHdr header = read_tiff_header(fp); | ||||||
|  |   if (IS_NULL_HEADER(header)) { | ||||||
|  |     goto 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); | ||||||
|  |   read_fields(fp, &header, &ifd, &alloc); | ||||||
|  |  | ||||||
|  | FILE_CLEANUP: | ||||||
|  |   fclose(fp); | ||||||
|  |  | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |   u32 strip_count = 1; | ||||||
|  |   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[strip_offsets_type].byte_count; | ||||||
|  |       u32 total_byte_count = field->count * field_type_byte_count; | ||||||
|  |       strip_count = field->count; | ||||||
|  |  | ||||||
|  |       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[strip_offsets_type].byte_count; | ||||||
|  |       u32 total_byte_count = field->count * field_type_byte_count; | ||||||
|  |       strip_count = field->count; | ||||||
|  |  | ||||||
|  |       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; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (identifier == tiff_image_identifiers[TIFF_IMAGE_BILEVEL]) { | ||||||
|  |     printf("BILEVEL\n"); | ||||||
|  |   } else if (identifier == tiff_image_identifiers[TIFF_IMAGE_GRAYSCALE]) { | ||||||
|  |     printf("GRAYSCALE\n"); | ||||||
|  |   } else if (identifier == tiff_image_identifiers[TIFF_IMAGE_PALETTE]) { | ||||||
|  |     printf("PALETTE\n"); | ||||||
|  |   } else if (identifier == tiff_image_identifiers[TIFF_IMAGE_RGB]) { | ||||||
|  |     printf("RGB\n"); | ||||||
|  |   } else { | ||||||
|  |     printf("UNKNOWN\n"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   printf("WIDTH: %lu, HEIGHT: %lu\n", width, height); | ||||||
|  |   printf("SAMPLES: %u\n", samples_per_pixel); | ||||||
|  |   printf("STRIPS: %u\n", strip_count); | ||||||
|  |   printf("PHOTOMETRIC INTERPRETATION: %u\n", photometric_interpretation); | ||||||
|  |   for (u64 i = 0; i < samples_per_pixel; ++i) { | ||||||
|  |     printf("%u\n", bits_per_sample[i]); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   printf("OFFSETS: "); | ||||||
|  |   for (u64 i = 0; i < strip_count; ++i) { | ||||||
|  |     if (strip_offsets_type == TIFF_FIELD_TYPE_LONG) { | ||||||
|  |       printf("%u ", ((u32 *)strip_offsets)[i]); | ||||||
|  |     } else { | ||||||
|  |       printf("%u ", ((u16 *)strip_offsets)[i]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   printf("\n"); | ||||||
|  |  | ||||||
|  |   printf("COUNTS: "); | ||||||
|  |   for (u64 i = 0; i < strip_count; ++i) { | ||||||
|  |     if (strip_byte_counts_type == TIFF_FIELD_TYPE_LONG) { | ||||||
|  |       printf("%u ", ((u32 *)strip_byte_counts)[i]); | ||||||
|  |     } else { | ||||||
|  |       printf("%u ", ((u16 *)strip_byte_counts)[i]); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   printf("\n"); | ||||||
|  |  | ||||||
|  |   return NULL; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | 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); | ||||||
|  | } | ||||||
| @@ -6,6 +6,7 @@ extern "C" { | |||||||
| #endif // __cplusplus | #endif // __cplusplus | ||||||
|  |  | ||||||
| #include "aliases.h" | #include "aliases.h" | ||||||
|  | #include "image.h" | ||||||
|  |  | ||||||
| #define TAG_MAX_COUNT (UINT16_MAX * sizeof(const char *)) | #define TAG_MAX_COUNT (UINT16_MAX * sizeof(const char *)) | ||||||
| // Technically, the type parameter is 2-bytes long, but there aren't so many | // Technically, the type parameter is 2-bytes long, but there aren't so many | ||||||
| @@ -13,7 +14,7 @@ extern "C" { | |||||||
| #define TYPE_MAX_COUNT (UINT8_MAX * sizeof(const char *)) | #define TYPE_MAX_COUNT (UINT8_MAX * sizeof(const char *)) | ||||||
|  |  | ||||||
| // clang-format off | // clang-format off | ||||||
| enum { | enum tiff_byte_order { | ||||||
|   TIFF_ORDER_LITTLE_ENDIAN = 0x4949, |   TIFF_ORDER_LITTLE_ENDIAN = 0x4949, | ||||||
|   TIFF_ORDER_BIG_ENDIAN    = 0x4d4d, |   TIFF_ORDER_BIG_ENDIAN    = 0x4d4d, | ||||||
| }; | }; | ||||||
| @@ -31,7 +32,7 @@ enum tiff_public_tags { | |||||||
|   #include "tiff_public_tags.inc" |   #include "tiff_public_tags.inc" | ||||||
| }; | }; | ||||||
|  |  | ||||||
| const char *tag_names[TAG_MAX_COUNT] = { | internal const char *tag_names[TAG_MAX_COUNT] = { | ||||||
|   #define TIFF_TAG_LOOKUP |   #define TIFF_TAG_LOOKUP | ||||||
|   #include "tiff_public_tags.inc" |   #include "tiff_public_tags.inc" | ||||||
|   #undef TIFF_TAG_LOOKUP |   #undef TIFF_TAG_LOOKUP | ||||||
| @@ -43,11 +44,11 @@ enum tiff_field_types { | |||||||
|  |  | ||||||
| typedef struct field_type TiffFieldType; | typedef struct field_type TiffFieldType; | ||||||
| struct field_type { | struct field_type { | ||||||
| 	const char *name; |   const char *name; | ||||||
| 	u16 byte_count; |   u16 byte_count; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| TiffFieldType filed_types[TYPE_MAX_COUNT] = { | internal TiffFieldType field_types[TYPE_MAX_COUNT] = { | ||||||
|   #define TIFF_TYPE_LOOKUP |   #define TIFF_TYPE_LOOKUP | ||||||
|   #include "tiff_field_types.inc" |   #include "tiff_field_types.inc" | ||||||
|   #undef TIFF_TYPE_LOOKUP |   #undef TIFF_TYPE_LOOKUP | ||||||
| @@ -79,9 +80,7 @@ enum tiff_compression { | |||||||
|   TIFF_COMPRESSION_JPEG         = 0x0006, |   TIFF_COMPRESSION_JPEG         = 0x0006, | ||||||
|   TIFF_COMPRESSION_PACK_BITS    = 0x8005, |   TIFF_COMPRESSION_PACK_BITS    = 0x8005, | ||||||
| }; | }; | ||||||
| // clang-format on |  | ||||||
|  |  | ||||||
| // clang-format off |  | ||||||
| enum tiff_photometric_interpretation { | enum tiff_photometric_interpretation { | ||||||
|   TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO     = 0x0000, |   TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO     = 0x0000, | ||||||
|   TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO     = 0x0001, |   TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO     = 0x0001, | ||||||
| @@ -91,9 +90,18 @@ enum tiff_photometric_interpretation { | |||||||
|   TIFF_PHOTOMETRIC_INTERPRETATION_CMYK              = 0x0005, |   TIFF_PHOTOMETRIC_INTERPRETATION_CMYK              = 0x0005, | ||||||
|   TIFF_PHOTOMETRIC_INTERPRETATION_YCbCr             = 0x0006, |   TIFF_PHOTOMETRIC_INTERPRETATION_YCbCr             = 0x0006, | ||||||
|   TIFF_PHOTOMETRIC_INTERPRETATION_CIELab            = 0x0008, |   TIFF_PHOTOMETRIC_INTERPRETATION_CIELab            = 0x0008, | ||||||
|  |  | ||||||
|  |   TIFF_PHOTOMETRIC_INTERPRETATION_INVALID, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum tiff_planar_configuration { | ||||||
|  |   TIFF_PLANAR_CONFIG_CHUNKY = 0x0001, | ||||||
|  |   TIFF_PLANAR_CONFIG_PLANAR = 0x0002, | ||||||
| }; | }; | ||||||
| // clang-format on | // clang-format on | ||||||
|  |  | ||||||
|  | Image *read_baseline_tiff(const char *file, const Allocator *allocator); | ||||||
|  |  | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif // __cplusplus | #endif // __cplusplus | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user