From 4b52630c1ee0db380263a49d0e90e761c6834481 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Thu, 2 May 2024 22:00:32 +0100 Subject: [PATCH] Implement reading RGB and RGBA images --- src/tiff/tiffread.c | 58 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/src/tiff/tiffread.c b/src/tiff/tiffread.c index bb8a301..cd6a46d 100644 --- a/src/tiff/tiffread.c +++ b/src/tiff/tiffread.c @@ -3,6 +3,7 @@ #include "endianness.h" #include "image.h" #include "mem_arena.h" +#include #include #include #include @@ -35,7 +36,8 @@ TiffHdr read_tiff_header(FILE *fp); TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd); -bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips); +bool read_strip_data(FILE *fp, const TiffHdr *header, const TiffImage *img, + TiffStrip *strips); void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, Pixel *buf); bool read_field(const TiffField *field, TiffImage *img, @@ -96,7 +98,7 @@ Image *read_baseline_tiff(const char *file, Arena *arena) { goto READ_BASELINE_DESTROY_ARENA; } - if (!read_strip_data(fp, &img, strips)) { + if (!read_strip_data(fp, &header, &img, strips)) { goto READ_BASELINE_DESTROY_ARENA; } @@ -260,7 +262,8 @@ READ_FIELDS_RETURN_IMAGE: return img_out; } -bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { +bool read_strip_data(FILE *fp, const TiffHdr *header, const TiffImage *img, + TiffStrip *strips) { if (!fp || !img || !strips) { return false; } @@ -285,6 +288,21 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { if (offsets_total_bytes > sizeof(u32)) { u32 offset = img->strip_offsets.long_val + offset_size * i; read_from_file_with_offset(fp, &(strip->offset), offset_size, offset); + + switch (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), &(img->strip_offsets.long_val), offset_size); } @@ -292,6 +310,23 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { if (byte_count_total_bytes > sizeof(u32)) { u32 offset = img->strip_byte_counts.long_val + counts_size * i; read_from_file_with_offset(fp, &(strip->byte_count), counts_size, offset); + + switch (header->order) { + case TIFF_ORDER_BIG_ENDIAN: + if (IS_LITTLE_ENDIAN) { + strip->byte_count = counts_size > sizeof(u16) + ? ntohl(strip->byte_count) + : ntohs(strip->byte_count); + } + break; + case TIFF_ORDER_LITTLE_ENDIAN: + if (IS_BIG_ENDIAN) { + strip->byte_count = counts_size > sizeof(u16) + ? htonl(strip->byte_count) + : htons(strip->byte_count); + } + break; + } } else { memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), counts_size); @@ -303,15 +338,24 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) { void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, Pixel *buf) { + assert((img->sample_count == 3 || img->sample_count == 4) && + "Only RGB or RGBA images supported"); + + u64 position = 0; for (u64 i = 0; i < img->strip_count; ++i) { const TiffStrip *strip = &(strips[i]); - for (u64 j = 0; j < img->image_width * img->image_length; ++j) { - Pixel *p = &(buf[j]); + for (u64 j = 0; j < strip->byte_count / img->sample_count; ++j) { + Pixel *p = &(buf[position]); - read_from_file_with_offset(fp, p, 3, strip->offset + j * 3); + read_from_file_with_offset(fp, p, img->sample_count, + strip->offset + j * img->sample_count); - p->a = 255; + if (img->sample_count == 3) { + p->a = 255; + } + + ++position; } } }