diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index 62010e4..43d6052 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -27,6 +27,9 @@ #define NULL_TIFF_IMAGE ((TiffImage){0}) #define IS_NULL_IMAGE(IMG) (IMG.type == TIFF_IMAGE_TYPE_INVALID) +#define NULL_TIFF_ALPHA ((TiffAlpha){0}) +#define IS_NULL_ALPHA(ALPHA) (ALPHA.type == ALPHA_TYPE_UNDEFINED) + #define INVALID_SAMPLE_COUNT 0 #define INVALID_ROWS_PER_STRIP 0 #define INVALID_STRIP_COUNT 0 @@ -59,6 +62,7 @@ struct strip_data_field { 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 Pixel *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); @@ -253,11 +257,14 @@ internal TiffImage read_ifd_fields(const TiffReader *reader) { goto READ_FIELDS_RETURN_IMAGE; } + img_out.alpha = read_alpha(reader, &img_out); + #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); @@ -270,6 +277,39 @@ 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]; + + if (img->extra_samples_count == 0) { + goto READ_ALPHA_RETURN; + } + + u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->extra_samples_count; + memset(samples, 0, byte_count); + + if (img->extra_samples_offset) { + read_from_file_with_offset(reader->fp, samples, byte_count, + img->extra_samples); + } else { + memcpy(samples, &(img->extra_samples), byte_count); + } + + for (u32 i = 0; i < 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 + ? ALPHA_TYPE_ASSOCIATED + : ALPHA_TYPE_UNASSOCIATED; + break; + } + } + +READ_ALPHA_RETURN: + return alpha; +} + internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) { Pixel *buf = NULL; u64 img_byte_count = @@ -345,17 +385,27 @@ internal bool read_strip_data(TiffReader *reader, Arena *arena) { internal void read_strips(const TiffReader *reader, Pixel *buf) { u64 position = 0; + u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count; + TiffAlpha alpha = reader->img.alpha; + + Pixel *p; + u64 start_offset; + u64 alpha_offset; + for (u64 i = 0; i < reader->img.strip_count; ++i) { const TiffStrip *strip = &(reader->img.strips[i]); for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { - Pixel *p = &(buf[position]); + p = &(buf[position]); + start_offset = strip->offset + j * reader->img.sample_count; + alpha_offset = start_offset + main_samples + alpha.sample_offset; - read_from_file_with_offset(reader->fp, p, reader->img.sample_count, - strip->offset + j * reader->img.sample_count); + read_from_file_with_offset(reader->fp, p, main_samples, start_offset); - if (reader->img.sample_count == 3) { + if (alpha.type == ALPHA_TYPE_UNDEFINED) { p->a = 255; + } else { + read_from_file_with_offset(reader->fp, &(p->a), 1, alpha_offset); } ++position; diff --git a/src/tiff/tiffread.h b/src/tiff/tiffread.h index e31a238..cf6f624 100644 --- a/src/tiff/tiffread.h +++ b/src/tiff/tiffread.h @@ -111,6 +111,18 @@ struct IFD { u32 next_ifd; }; +typedef enum { + ALPHA_TYPE_UNDEFINED = 0, + ALPHA_TYPE_ASSOCIATED, + ALPHA_TYPE_UNASSOCIATED, +} AlphaType; + +typedef struct tiff_alpha TiffAlpha; +struct tiff_alpha { + AlphaType type; + u32 sample_offset; +}; + typedef struct tiff_strip TiffStrip; struct tiff_strip { u32 offset; @@ -139,6 +151,7 @@ struct tiff_image { u32 extra_samples; u32 extra_samples_count; bool extra_samples_offset; + TiffAlpha alpha; TiffStrip *strips; };