From 38862899d0d0342478ccf3428163e4bd80227b8e Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 5 May 2024 22:05:39 +0100 Subject: [PATCH] Read bits per sample --- src/tiff/tiffread.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ src/tiff/tiffread.h | 9 ++++++++ 2 files changed, 63 insertions(+) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index 43d6052..eb5b934 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -39,6 +39,9 @@ #define TIFF_SHORT_BYTE_COUNT field_types[TIFF_FIELD_TYPE_SHORT].byte_count #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 TEMP_ARENA_CAPACITY (20 * 1024 * 1024) typedef struct tiff_reader TiffReader; @@ -63,6 +66,8 @@ 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 bool read_strip_data(TiffReader *reader, Arena *arena); internal void read_strips(const TiffReader *reader, Pixel *buf); @@ -127,6 +132,11 @@ Image *read_baseline_tiff(const char *file, Arena *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) && + "Currently, only 8-bit images are supported"); reader.pixels = load_image_pixels(&reader, temp_arena); if (!reader.pixels) { @@ -258,6 +268,7 @@ internal TiffImage read_ifd_fields(const TiffReader *reader) { } img_out.alpha = read_alpha(reader, &img_out); + img_out.rgba_bits_per_sample = read_bits_per_sample(reader, &img_out); #ifdef DEBUG // clang-format off @@ -302,6 +313,7 @@ internal TiffAlpha read_alpha(const TiffReader *reader, TiffImage *img) { alpha.type = *sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA ? ALPHA_TYPE_ASSOCIATED : ALPHA_TYPE_UNASSOCIATED; + alpha.sample_offset = i; break; } } @@ -310,6 +322,48 @@ 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; + + u64 byte_count = TIFF_SHORT_BYTE_COUNT * img->sample_count; + u16 bits_per_sample[img->sample_count]; + memset(bits_per_sample, 0, byte_count); + + if (img->bits_per_sample_offset) { + read_from_file_with_offset(reader->fp, bits_per_sample, byte_count, + img->bits_per_sample); + } else { + memcpy(bits_per_sample, &(img->bits_per_sample), byte_count); + } + + TiffSampleBits bits = {0}; + memcpy(&bits, bits_per_sample, TIFF_SHORT_BYTE_COUNT * main_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; + } + } + + if (alpha.type == ALPHA_TYPE_UNDEFINED) { + bits.a = MINIMUM_BITS_PER_SAMPLE; + } else { + void *alpha_sample = &(bits_per_sample[main_samples + alpha.sample_offset]); + 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; +} + internal Pixel *load_image_pixels(TiffReader *reader, Arena *arena) { Pixel *buf = NULL; u64 img_byte_count = diff --git a/src/tiff/tiffread.h b/src/tiff/tiffread.h index cf6f624..c342806 100644 --- a/src/tiff/tiffread.h +++ b/src/tiff/tiffread.h @@ -123,6 +123,14 @@ struct tiff_alpha { u32 sample_offset; }; +typedef struct tiff_sample_bits TiffSampleBits; +struct tiff_sample_bits { + u16 r; + u16 g; + u16 b; + u16 a; +}; + typedef struct tiff_strip TiffStrip; struct tiff_strip { u32 offset; @@ -152,6 +160,7 @@ struct tiff_image { u32 extra_samples_count; bool extra_samples_offset; TiffAlpha alpha; + TiffSampleBits rgba_bits_per_sample; TiffStrip *strips; };