Switch internal reading functions to directly manipulate reader object
This commit is contained in:
parent
5bf78d3e01
commit
ba21bcb2f4
@ -40,7 +40,7 @@
|
||||
#define TIFF_LONG_BYTE_COUNT field_types[TIFF_FIELD_TYPE_LONG].byte_count
|
||||
|
||||
#define RGB_SAMPLE_COUNT 3
|
||||
#define MINIMUM_BITS_PER_SAMPLE 8
|
||||
#define MIN_BITS_PER_SAMPLE 8
|
||||
|
||||
#define TEMP_ARENA_CAPACITY (20 * 1024 * 1024)
|
||||
|
||||
@ -62,15 +62,14 @@ struct strip_data_field {
|
||||
u16 type_byte_count;
|
||||
};
|
||||
|
||||
internal TiffHdr read_tiff_header(const TiffReader *reader);
|
||||
internal TiffIFD read_ifd(const TiffReader *reader, Arena *arena);
|
||||
internal TiffImage read_ifd_fields(const TiffReader *reader);
|
||||
internal TiffAlpha read_alpha(const TiffReader *reader, TiffImage *img);
|
||||
internal TiffSampleBits read_bits_per_sample(const TiffReader *reader,
|
||||
TiffImage *img);
|
||||
internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena);
|
||||
internal void read_tiff_header(TiffReader *reader);
|
||||
internal void read_ifd(TiffReader *reader, Arena *arena);
|
||||
internal void read_ifd_fields(TiffReader *reader);
|
||||
internal void read_alpha(TiffReader *reader);
|
||||
internal void read_bits_per_sample(TiffReader *reader);
|
||||
internal void load_image_pixels(TiffReader *reader, Arena *arena);
|
||||
internal bool read_strip_data(TiffReader *reader, Arena *arena);
|
||||
internal void read_strips(const TiffReader *reader, Pixel *buf);
|
||||
internal void read_strips(TiffReader *reader);
|
||||
internal void read_strip_data_field(const TiffReader *reader,
|
||||
StripDataField *field);
|
||||
internal bool read_field(const TiffField *field, TiffImage *img);
|
||||
@ -115,30 +114,30 @@ Image *read_baseline_tiff(const char *file, Arena *arena) {
|
||||
goto READ_BASELINE_FILE_CLEANUP;
|
||||
}
|
||||
|
||||
reader.header = read_tiff_header(&reader);
|
||||
read_tiff_header(&reader);
|
||||
if (IS_NULL_HEADER(reader.header)) {
|
||||
goto READ_BASELINE_DESTROY_ARENA;
|
||||
}
|
||||
|
||||
reader.ifd = read_ifd(&reader, temp_arena);
|
||||
read_ifd(&reader, temp_arena);
|
||||
if (IS_NULL_IFD(reader.ifd)) {
|
||||
goto READ_BASELINE_DESTROY_ARENA;
|
||||
}
|
||||
|
||||
reader.img = read_ifd_fields(&reader);
|
||||
read_ifd_fields(&reader);
|
||||
if (IS_NULL_IMAGE(reader.img)) {
|
||||
goto READ_BASELINE_DESTROY_ARENA;
|
||||
}
|
||||
|
||||
assert((reader.img.type == TIFF_IMAGE_TYPE_RGB) &&
|
||||
"Currently, only RGB images are supported");
|
||||
assert((reader.img.rgba_bits_per_sample.r == MINIMUM_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.g == MINIMUM_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.b == MINIMUM_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.a == MINIMUM_BITS_PER_SAMPLE) &&
|
||||
assert((reader.img.rgba_bits_per_sample.r == MIN_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.g == MIN_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.b == MIN_BITS_PER_SAMPLE &&
|
||||
reader.img.rgba_bits_per_sample.a == MIN_BITS_PER_SAMPLE) &&
|
||||
"Currently, only 8-bit images are supported");
|
||||
|
||||
reader.pixels = load_image_pixels(&reader, temp_arena);
|
||||
load_image_pixels(&reader, temp_arena);
|
||||
if (!reader.pixels) {
|
||||
goto READ_BASELINE_DESTROY_ARENA;
|
||||
}
|
||||
@ -156,71 +155,69 @@ READ_BASELINE_RETURN_IMG:
|
||||
return img_out;
|
||||
}
|
||||
|
||||
internal TiffHdr read_tiff_header(const TiffReader *reader) {
|
||||
TiffHdr header = NULL_TIFF_HEADER;
|
||||
read_from_file_with_offset(reader->fp, &header, sizeof(TiffHdr), 0);
|
||||
internal void read_tiff_header(TiffReader *reader) {
|
||||
reader->header = NULL_TIFF_HEADER;
|
||||
read_from_file_with_offset(reader->fp, &(reader->header), sizeof(TiffHdr), 0);
|
||||
|
||||
switch (header.order) {
|
||||
switch (reader->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);
|
||||
reader->header.magic = htons(reader->header.magic);
|
||||
reader->header.first_ifd_offset = htonl(reader->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);
|
||||
reader->header.magic = ntohs(reader->header.magic);
|
||||
reader->header.first_ifd_offset = ntohl(reader->header.first_ifd_offset);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return NULL_TIFF_HEADER;
|
||||
reader->header = NULL_TIFF_HEADER;
|
||||
}
|
||||
|
||||
if (header.magic != TIFF_MAGIC) {
|
||||
return NULL_TIFF_HEADER;
|
||||
if (reader->header.magic != TIFF_MAGIC) {
|
||||
reader->header = NULL_TIFF_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
internal TiffIFD read_ifd(const TiffReader *reader, Arena *arena) {
|
||||
TiffIFD ifd = NULL_TIFF_IFD;
|
||||
read_from_file_with_offset(reader->fp, &(ifd.count), sizeof(ifd.count),
|
||||
internal void read_ifd(TiffReader *reader, Arena *arena) {
|
||||
reader->ifd = NULL_TIFF_IFD;
|
||||
read_from_file_with_offset(reader->fp, &(reader->ifd.count),
|
||||
sizeof(reader->ifd.count),
|
||||
reader->header.first_ifd_offset);
|
||||
|
||||
switch (reader->header.order) {
|
||||
case TIFF_ORDER_LITTLE_ENDIAN:
|
||||
if (IS_BIG_ENDIAN) {
|
||||
ifd.count = htons(ifd.count);
|
||||
reader->ifd.count = htons(reader->ifd.count);
|
||||
}
|
||||
|
||||
break;
|
||||
case TIFF_ORDER_BIG_ENDIAN:
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
ifd.count = ntohs(ifd.count);
|
||||
reader->ifd.count = ntohs(reader->ifd.count);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
u64 field_byte_count = sizeof(TiffField) * ifd.count;
|
||||
ifd.fields = (TiffField *)wapp_mem_arena_alloc(arena, field_byte_count);
|
||||
if (!(ifd.fields)) {
|
||||
return NULL_TIFF_IFD;
|
||||
u64 field_byte_count = sizeof(TiffField) * reader->ifd.count;
|
||||
reader->ifd.fields =
|
||||
(TiffField *)wapp_mem_arena_alloc(arena, field_byte_count);
|
||||
if (!(reader->ifd.fields)) {
|
||||
reader->ifd = NULL_TIFF_IFD;
|
||||
}
|
||||
|
||||
fread(ifd.fields, field_byte_count, 1, reader->fp);
|
||||
fread(&(ifd.next_ifd), sizeof(ifd.next_ifd), 1, reader->fp);
|
||||
|
||||
return ifd;
|
||||
fread(reader->ifd.fields, field_byte_count, 1, reader->fp);
|
||||
fread(&(reader->ifd.next_ifd), sizeof(reader->ifd.next_ifd), 1, reader->fp);
|
||||
}
|
||||
|
||||
internal TiffImage read_ifd_fields(const TiffReader *reader) {
|
||||
TiffImage img_out = NULL_TIFF_IMAGE;
|
||||
img_out.type = TIFF_IMAGE_TYPE_BILEVEL;
|
||||
internal void read_ifd_fields(TiffReader *reader) {
|
||||
reader->img = NULL_TIFF_IMAGE;
|
||||
reader->img.type = TIFF_IMAGE_TYPE_BILEVEL;
|
||||
|
||||
for (u64 i = 0; i < reader->ifd.count; ++i) {
|
||||
TiffField *field = &(reader->ifd.fields[i]);
|
||||
@ -256,122 +253,149 @@ internal TiffImage read_ifd_fields(const TiffReader *reader) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!read_field(field, &img_out)) {
|
||||
img_out = NULL_TIFF_IMAGE;
|
||||
goto READ_FIELDS_RETURN_IMAGE;
|
||||
if (!read_field(field, &(reader->img))) {
|
||||
reader->img = NULL_TIFF_IMAGE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!validate_image_type(&img_out)) {
|
||||
img_out = NULL_TIFF_IMAGE;
|
||||
goto READ_FIELDS_RETURN_IMAGE;
|
||||
if (!validate_image_type(&(reader->img))) {
|
||||
reader->img = NULL_TIFF_IMAGE;
|
||||
return;
|
||||
}
|
||||
|
||||
img_out.alpha = read_alpha(reader, &img_out);
|
||||
img_out.rgba_bits_per_sample = read_bits_per_sample(reader, &img_out);
|
||||
read_alpha(reader);
|
||||
read_bits_per_sample(reader);
|
||||
|
||||
#ifdef DEBUG
|
||||
// clang-format off
|
||||
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("EXTRA SAMPLES (samples, count, is offset) : %u, %u, %u\n", img_out.extra_samples, img_out.extra_samples_count, img_out.extra_samples_offset);
|
||||
printf("ALPHA (type, offset) : %u, %u\n", img_out.alpha.type, img_out.alpha.sample_offset);
|
||||
printf("SAMPLES PER PIXEL : %u\n", img_out.sample_count);
|
||||
printf("PHOTOMETRIC INTERPRETATION : %u\n", img_out.photometric_interpretation);
|
||||
printf("ROWS PER STRIP (rows, strip count) : %u, %u\n", img_out.rows_per_strip, img_out.strip_count);
|
||||
printf("STRIP OFFSETS (offsets, is offset) : %u, %u\n", img_out.strip_offsets.long_val, img_out.strip_offsets_offset);
|
||||
printf("STRIP BYTES (byte count, is offset) : %u, %u\n", img_out.strip_byte_counts.long_val, img_out.strip_byte_counts_offset);
|
||||
printf("SIZE (width, height) : %u, %u\n", reader->img.image_width, reader->img.image_length);
|
||||
printf("SAMPLES (bits per sample, count, is offset) : %u, %u, %u\n", reader->img.bits_per_sample, reader->img.sample_count, reader->img.bits_per_sample_offset);
|
||||
printf("EXTRA SAMPLES (samples, count, is offset) : %u, %u, %u\n", reader->img.extra_samples, reader->img.extra_samples_count, reader->img.extra_samples_offset);
|
||||
printf("ALPHA (type, offset) : %u, %u\n", reader->img.alpha.type, reader->img.alpha.sample_offset);
|
||||
printf("SAMPLES PER PIXEL : %u\n", reader->img.sample_count);
|
||||
printf("PHOTOMETRIC INTERPRETATION : %u\n", reader->img.photometric_interpretation);
|
||||
printf("ROWS PER STRIP (rows, strip count) : %u, %u\n", reader->img.rows_per_strip, reader->img.strip_count);
|
||||
printf("STRIP OFFSETS (offsets, is offset) : %u, %u\n", reader->img.strip_offsets.long_val, reader->img.strip_offsets_offset);
|
||||
printf("STRIP BYTES (byte count, is offset) : %u, %u\n", reader->img.strip_byte_counts.long_val, reader->img.strip_byte_counts_offset);
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
READ_FIELDS_RETURN_IMAGE:
|
||||
return img_out;
|
||||
}
|
||||
|
||||
internal TiffAlpha read_alpha(const TiffReader *reader, TiffImage *img) {
|
||||
TiffAlpha alpha = NULL_TIFF_ALPHA;
|
||||
u16 samples[img->extra_samples_count];
|
||||
internal void read_alpha(TiffReader *reader) {
|
||||
reader->img.alpha = NULL_TIFF_ALPHA;
|
||||
u16 samples[reader->img.extra_samples_count];
|
||||
|
||||
if (img->extra_samples_count == 0) {
|
||||
goto READ_ALPHA_RETURN;
|
||||
if (reader->img.extra_samples_count == 0) {
|
||||
reader->img.alpha = NULL_TIFF_ALPHA;
|
||||
return;
|
||||
}
|
||||
|
||||
u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->extra_samples_count;
|
||||
u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.extra_samples_count;
|
||||
memset(samples, 0, byte_count);
|
||||
|
||||
if (img->extra_samples_offset) {
|
||||
if (reader->img.extra_samples_offset) {
|
||||
read_from_file_with_offset(reader->fp, samples, byte_count,
|
||||
img->extra_samples);
|
||||
reader->img.extra_samples);
|
||||
|
||||
switch (reader->header.order) {
|
||||
case TIFF_ORDER_BIG_ENDIAN:
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
for (u64 i = 0; i < reader->img.extra_samples_count; ++i) {
|
||||
samples[i] = ntohs(samples[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIFF_ORDER_LITTLE_ENDIAN:
|
||||
if (IS_BIG_ENDIAN) {
|
||||
for (u64 i = 0; i < reader->img.extra_samples_count; ++i) {
|
||||
samples[i] = htons(samples[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
memcpy(samples, &(img->extra_samples), byte_count);
|
||||
memcpy(samples, &(reader->img.extra_samples), byte_count);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < img->extra_samples_count; ++i) {
|
||||
for (u32 i = 0; i < reader->img.extra_samples_count; ++i) {
|
||||
u16 *sample = &(samples[i]);
|
||||
if (*sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA ||
|
||||
*sample == TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA) {
|
||||
alpha.type = *sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA
|
||||
reader->img.alpha.type = *sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA
|
||||
? ALPHA_TYPE_ASSOCIATED
|
||||
: ALPHA_TYPE_UNASSOCIATED;
|
||||
alpha.sample_offset = i;
|
||||
reader->img.alpha.sample_offset = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
READ_ALPHA_RETURN:
|
||||
return alpha;
|
||||
}
|
||||
|
||||
internal TiffSampleBits read_bits_per_sample(const TiffReader *reader,
|
||||
TiffImage *img) {
|
||||
TiffAlpha alpha = img->alpha;
|
||||
u64 main_samples = img->sample_count - img->extra_samples_count;
|
||||
internal void read_bits_per_sample(TiffReader *reader) {
|
||||
TiffAlpha alpha = reader->img.alpha;
|
||||
u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count;
|
||||
|
||||
u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->sample_count;
|
||||
u16 bits_per_sample[img->sample_count];
|
||||
u64 byte_count = TIFF_SHORT_BYTE_COUNT * reader->img.sample_count;
|
||||
u16 bits_per_sample[reader->img.sample_count];
|
||||
memset(bits_per_sample, 0, byte_count);
|
||||
|
||||
if (img->bits_per_sample_offset) {
|
||||
if (reader->img.bits_per_sample_offset) {
|
||||
read_from_file_with_offset(reader->fp, bits_per_sample, byte_count,
|
||||
img->bits_per_sample);
|
||||
reader->img.bits_per_sample);
|
||||
|
||||
switch (reader->header.order) {
|
||||
case TIFF_ORDER_BIG_ENDIAN:
|
||||
if (IS_LITTLE_ENDIAN) {
|
||||
for (u64 i = 0; i < reader->img.sample_count; ++i) {
|
||||
bits_per_sample[i] = ntohs(bits_per_sample[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIFF_ORDER_LITTLE_ENDIAN:
|
||||
if (IS_BIG_ENDIAN) {
|
||||
for (u64 i = 0; i < reader->img.sample_count; ++i) {
|
||||
bits_per_sample[i] = htons(bits_per_sample[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
memcpy(bits_per_sample, &(img->bits_per_sample), byte_count);
|
||||
memcpy(bits_per_sample, &(reader->img.bits_per_sample), byte_count);
|
||||
}
|
||||
|
||||
TiffSampleBits bits = {0};
|
||||
memcpy(&bits, bits_per_sample, TIFF_SHORT_BYTE_COUNT * main_samples);
|
||||
TiffSampleBits *bits = &(reader->img.rgba_bits_per_sample);
|
||||
*bits = (TiffSampleBits){0};
|
||||
memcpy(bits, bits_per_sample, TIFF_SHORT_BYTE_COUNT * main_samples);
|
||||
|
||||
// Set missing samples if image doesn't have all RGB samples
|
||||
if (main_samples < RGB_SAMPLE_COUNT) {
|
||||
u64 count = RGB_SAMPLE_COUNT - main_samples;
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
u16 *value = &(((u16 *)(&bits))[main_samples + i]);
|
||||
*value = MINIMUM_BITS_PER_SAMPLE;
|
||||
*value = MIN_BITS_PER_SAMPLE;
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.type == ALPHA_TYPE_UNDEFINED) {
|
||||
bits.a = MINIMUM_BITS_PER_SAMPLE;
|
||||
bits->a = MIN_BITS_PER_SAMPLE;
|
||||
} else {
|
||||
void *alpha_sample = &(bits_per_sample[main_samples + alpha.sample_offset]);
|
||||
memcpy(&(bits.a), alpha_sample, TIFF_SHORT_BYTE_COUNT);
|
||||
memcpy(&(bits->a), alpha_sample, TIFF_SHORT_BYTE_COUNT);
|
||||
}
|
||||
|
||||
bits.r = bits.r < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.r;
|
||||
bits.g = bits.g < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.g;
|
||||
bits.b = bits.b < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.b;
|
||||
bits.a = bits.a < MINIMUM_BITS_PER_SAMPLE ? MINIMUM_BITS_PER_SAMPLE : bits.a;
|
||||
|
||||
return bits;
|
||||
bits->r = bits->r < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->r;
|
||||
bits->g = bits->g < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->g;
|
||||
bits->b = bits->b < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->b;
|
||||
bits->a = bits->a < MIN_BITS_PER_SAMPLE ? MIN_BITS_PER_SAMPLE : bits->a;
|
||||
}
|
||||
|
||||
internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) {
|
||||
Pixel *buf = NULL;
|
||||
internal void load_image_pixels(TiffReader *reader, Arena *arena) {
|
||||
reader->pixels = NULL;
|
||||
u64 img_byte_count =
|
||||
sizeof(Pixel) * reader->img.image_width * reader->img.image_length;
|
||||
|
||||
if (!read_strip_data(reader, arena)) {
|
||||
goto LOAD_IMAGE_PIXELS_RETURN;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -381,15 +405,12 @@ internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) {
|
||||
}
|
||||
#endif
|
||||
|
||||
buf = wapp_mem_arena_alloc(arena, img_byte_count);
|
||||
if (!buf) {
|
||||
goto LOAD_IMAGE_PIXELS_RETURN;
|
||||
reader->pixels = wapp_mem_arena_alloc(arena, img_byte_count);
|
||||
if (!reader->pixels) {
|
||||
return;
|
||||
}
|
||||
|
||||
read_strips(reader, buf);
|
||||
|
||||
LOAD_IMAGE_PIXELS_RETURN:
|
||||
return buf;
|
||||
read_strips(reader);
|
||||
}
|
||||
|
||||
internal bool read_strip_data(TiffReader *reader, Arena *arena) {
|
||||
@ -438,7 +459,7 @@ internal bool read_strip_data(TiffReader *reader, Arena *arena) {
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void read_strips(const TiffReader *reader, Pixel *buf) {
|
||||
internal void read_strips(TiffReader *reader) {
|
||||
u64 position = 0;
|
||||
u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count;
|
||||
TiffAlpha alpha = reader->img.alpha;
|
||||
@ -451,7 +472,7 @@ internal void read_strips(const TiffReader *reader, Pixel *buf) {
|
||||
const TiffStrip *strip = &(reader->img.strips[i]);
|
||||
|
||||
for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) {
|
||||
p = &(buf[position]);
|
||||
p = &(reader->pixels[position]);
|
||||
start_offset = strip->offset + j * reader->img.sample_count;
|
||||
alpha_offset = start_offset + main_samples + alpha.sample_offset;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user