Add TiffReader struct
This commit is contained in:
parent
9fdee24672
commit
c98802542d
@ -35,14 +35,21 @@
|
|||||||
|
|
||||||
#define TEMP_ARENA_CAPACITY (20 * 1024 * 1024)
|
#define TEMP_ARENA_CAPACITY (20 * 1024 * 1024)
|
||||||
|
|
||||||
TiffHdr read_tiff_header(FILE *fp);
|
typedef struct tiff_reader TiffReader;
|
||||||
TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena);
|
struct tiff_reader {
|
||||||
TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd);
|
FILE *fp;
|
||||||
Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img,
|
TiffHdr header;
|
||||||
Arena *arena);
|
TiffIFD ifd;
|
||||||
bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img,
|
TiffImage img;
|
||||||
Arena *arena);
|
Pixel *pixels;
|
||||||
void read_strips(FILE *fp, const TiffImage *img, Pixel *buf);
|
};
|
||||||
|
|
||||||
|
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 read_field(const TiffField *field, TiffImage *img);
|
||||||
bool validate_image_type(const TiffImage *img);
|
bool validate_image_type(const TiffImage *img);
|
||||||
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);
|
||||||
@ -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 *read_baseline_tiff(const char *file, Arena *arena) {
|
||||||
Image *img_out = NULL;
|
Image *img_out = NULL;
|
||||||
|
|
||||||
if (!file) {
|
if (!file || !arena) {
|
||||||
goto READ_BASELINE_RETURN_IMG;
|
goto READ_BASELINE_RETURN_IMG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,30 +89,33 @@ Image *read_baseline_tiff(const char *file, Arena *arena) {
|
|||||||
goto READ_BASELINE_FILE_CLEANUP;
|
goto READ_BASELINE_FILE_CLEANUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
TiffHdr header = read_tiff_header(fp);
|
TiffReader reader = {.fp = fp};
|
||||||
if (IS_NULL_HEADER(header)) {
|
|
||||||
|
reader.header = read_tiff_header(&reader);
|
||||||
|
if (IS_NULL_HEADER(reader.header)) {
|
||||||
goto READ_BASELINE_DESTROY_ARENA;
|
goto READ_BASELINE_DESTROY_ARENA;
|
||||||
}
|
}
|
||||||
|
|
||||||
TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, temp_arena);
|
reader.ifd = read_ifd(&reader, temp_arena);
|
||||||
if (IS_NULL_IFD(ifd)) {
|
if (IS_NULL_IFD(reader.ifd)) {
|
||||||
goto READ_BASELINE_DESTROY_ARENA;
|
goto READ_BASELINE_DESTROY_ARENA;
|
||||||
}
|
}
|
||||||
|
|
||||||
TiffImage img = read_fields(fp, &header, &ifd);
|
reader.img = read_fields(&reader);
|
||||||
if (IS_NULL_IMAGE(img)) {
|
if (IS_NULL_IMAGE(reader.img)) {
|
||||||
goto READ_BASELINE_DESTROY_ARENA;
|
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");
|
"Currently, only RGB images are supported");
|
||||||
|
|
||||||
Pixel *buf = load_image_pixels(fp, &header, &img, temp_arena);
|
reader.pixels = load_image_pixels(&reader, temp_arena);
|
||||||
if (!buf) {
|
if (!reader.pixels) {
|
||||||
goto READ_BASELINE_DESTROY_ARENA;
|
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:
|
READ_BASELINE_DESTROY_ARENA:
|
||||||
wapp_mem_arena_destroy(&temp_arena);
|
wapp_mem_arena_destroy(&temp_arena);
|
||||||
@ -117,13 +127,9 @@ READ_BASELINE_RETURN_IMG:
|
|||||||
return img_out;
|
return img_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
TiffHdr read_tiff_header(FILE *fp) {
|
TiffHdr read_tiff_header(const TiffReader *reader) {
|
||||||
if (!fp) {
|
|
||||||
return NULL_TIFF_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
TiffHdr header = NULL_TIFF_HEADER;
|
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) {
|
switch (header.order) {
|
||||||
case TIFF_ORDER_LITTLE_ENDIAN:
|
case TIFF_ORDER_LITTLE_ENDIAN:
|
||||||
@ -151,15 +157,12 @@ TiffHdr read_tiff_header(FILE *fp) {
|
|||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena) {
|
TiffIFD read_ifd(const TiffReader *reader, Arena *arena) {
|
||||||
if (!fp || !header) {
|
|
||||||
return NULL_TIFF_IFD;
|
|
||||||
}
|
|
||||||
|
|
||||||
TiffIFD ifd = NULL_TIFF_IFD;
|
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:
|
case TIFF_ORDER_LITTLE_ENDIAN:
|
||||||
if (IS_BIG_ENDIAN) {
|
if (IS_BIG_ENDIAN) {
|
||||||
ifd.count = htons(ifd.count);
|
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;
|
return NULL_TIFF_IFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
fread(ifd.fields, field_byte_count, 1, fp);
|
fread(ifd.fields, field_byte_count, 1, reader->fp);
|
||||||
fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, fp);
|
fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, reader->fp);
|
||||||
|
|
||||||
return ifd;
|
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;
|
TiffImage img_out = NULL_TIFF_IMAGE;
|
||||||
img_out.type = TIFF_IMAGE_TYPE_BILEVEL;
|
img_out.type = TIFF_IMAGE_TYPE_BILEVEL;
|
||||||
|
|
||||||
for (u64 i = 0; i < ifd->count; ++i) {
|
for (u64 i = 0; i < reader->ifd.count; ++i) {
|
||||||
TiffField *field = &(ifd->fields[i]);
|
TiffField *field = &(reader->ifd.fields[i]);
|
||||||
|
|
||||||
switch (header->order) {
|
switch (reader->header.order) {
|
||||||
case TIFF_ORDER_BIG_ENDIAN:
|
case TIFF_ORDER_BIG_ENDIAN:
|
||||||
if (IS_LITTLE_ENDIAN) {
|
if (IS_LITTLE_ENDIAN) {
|
||||||
field->tag = ntohs(field->tag);
|
field->tag = ntohs(field->tag);
|
||||||
@ -252,18 +255,19 @@ READ_FIELDS_RETURN_IMAGE:
|
|||||||
return img_out;
|
return img_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img,
|
Pixel *load_image_pixels(TiffReader *reader, Arena *arena) {
|
||||||
Arena *arena) {
|
|
||||||
Pixel *buf = NULL;
|
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;
|
goto LOAD_IMAGE_PIXELS_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
for (u32 i = 0; i < img->strip_count; ++i) {
|
for (u32 i = 0; i < reader->img.strip_count; ++i) {
|
||||||
printf("%u, %u\n", img->strips[i].offset, img->strips[i].byte_count);
|
printf("%u, %u\n", reader->img.strips[i].offset,
|
||||||
|
reader->img.strips[i].byte_count);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -272,41 +276,14 @@ Pixel *load_image_pixels(FILE *fp, const TiffHdr *header, TiffImage *img,
|
|||||||
goto LOAD_IMAGE_PIXELS_RETURN;
|
goto LOAD_IMAGE_PIXELS_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_strips(fp, img, buf);
|
read_strips(reader, buf);
|
||||||
|
|
||||||
LOAD_IMAGE_PIXELS_RETURN:
|
LOAD_IMAGE_PIXELS_RETURN:
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img,
|
#if 0
|
||||||
Arena *arena) {
|
void read_strip_field(FILE *fp, const TiffHdr *header, const TiffImage *img, TiffStrip *strip) {
|
||||||
if (!fp || !img || !arena) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
img->strips =
|
|
||||||
wapp_mem_arena_alloc(arena, sizeof(TiffStrip) * img->strip_count);
|
|
||||||
if (!img->strips) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 offsets_total_bytes =
|
|
||||||
img->strip_count * img->strip_offsets_type_byte_count;
|
|
||||||
u32 byte_count_total_bytes =
|
|
||||||
img->strip_count * img->strip_byte_count_type_byte_count;
|
|
||||||
|
|
||||||
if ((!(img->strip_offsets_offset) && offsets_total_bytes > sizeof(u32)) ||
|
|
||||||
(!(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]);
|
|
||||||
|
|
||||||
u16 offset_size = img->strip_offsets_type_byte_count;
|
|
||||||
u16 counts_size = img->strip_byte_count_type_byte_count;
|
|
||||||
|
|
||||||
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);
|
||||||
@ -328,12 +305,64 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img,
|
|||||||
} else {
|
} else {
|
||||||
memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size);
|
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 =
|
||||||
|
reader->img.strip_count * reader->img.strip_offsets_type_byte_count;
|
||||||
|
u32 byte_count_total_bytes =
|
||||||
|
reader->img.strip_count * reader->img.strip_byte_count_type_byte_count;
|
||||||
|
|
||||||
|
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 < reader->img.strip_count; ++i) {
|
||||||
|
TiffStrip *strip = &(reader->img.strips[i]);
|
||||||
|
|
||||||
|
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 = reader->img.strip_offsets.long_val + offset_size * i;
|
||||||
|
read_from_file_with_offset(reader->fp, &(strip->offset), offset_size,
|
||||||
|
offset);
|
||||||
|
|
||||||
|
switch (reader->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), &(reader->img.strip_offsets.long_val),
|
||||||
|
offset_size);
|
||||||
|
}
|
||||||
|
|
||||||
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 = reader->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(reader->fp, &(strip->byte_count), counts_size,
|
||||||
|
offset);
|
||||||
|
|
||||||
switch (header->order) {
|
switch (reader->header.order) {
|
||||||
case TIFF_ORDER_BIG_ENDIAN:
|
case TIFF_ORDER_BIG_ENDIAN:
|
||||||
if (IS_LITTLE_ENDIAN) {
|
if (IS_LITTLE_ENDIAN) {
|
||||||
strip->byte_count = counts_size > sizeof(u16)
|
strip->byte_count = counts_size > sizeof(u16)
|
||||||
@ -350,7 +379,7 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val),
|
memcpy(&(strip->byte_count), &(reader->img.strip_byte_counts.long_val),
|
||||||
counts_size);
|
counts_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,18 +387,18 @@ bool read_strip_data(FILE *fp, const TiffHdr *header, TiffImage *img,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_strips(FILE *fp, const TiffImage *img, Pixel *buf) {
|
void read_strips(const TiffReader *reader, Pixel *buf) {
|
||||||
u64 position = 0;
|
u64 position = 0;
|
||||||
for (u64 i = 0; i < img->strip_count; ++i) {
|
for (u64 i = 0; i < reader->img.strip_count; ++i) {
|
||||||
const TiffStrip *strip = &(img->strips[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]);
|
Pixel *p = &(buf[position]);
|
||||||
|
|
||||||
read_from_file_with_offset(fp, p, img->sample_count,
|
read_from_file_with_offset(reader->fp, p, reader->img.sample_count,
|
||||||
strip->offset + j * img->sample_count);
|
strip->offset + j * reader->img.sample_count);
|
||||||
|
|
||||||
if (img->sample_count == 3) {
|
if (reader->img.sample_count == 3) {
|
||||||
p->a = 255;
|
p->a = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user