Implement reading RGB and RGBA images

This commit is contained in:
Abdelrahman Said 2024-05-02 22:00:32 +01:00
parent c46535c20b
commit 4b52630c1e

View File

@ -3,6 +3,7 @@
#include "endianness.h" #include "endianness.h"
#include "image.h" #include "image.h"
#include "mem_arena.h" #include "mem_arena.h"
#include <assert.h>
#include <math.h> #include <math.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <stdbool.h> #include <stdbool.h>
@ -35,7 +36,8 @@
TiffHdr read_tiff_header(FILE *fp); TiffHdr read_tiff_header(FILE *fp);
TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena); TiffIFD read_ifd(FILE *fp, const TiffHdr *header, u32 offset, Arena *arena);
TiffImage read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd); 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, void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips,
Pixel *buf); Pixel *buf);
bool read_field(const TiffField *field, TiffImage *img, 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; 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; goto READ_BASELINE_DESTROY_ARENA;
} }
@ -260,7 +262,8 @@ READ_FIELDS_RETURN_IMAGE:
return img_out; 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) { if (!fp || !img || !strips) {
return false; return false;
} }
@ -285,6 +288,21 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) {
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);
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 { } else {
memcpy(&(strip->offset), &(img->strip_offsets.long_val), offset_size); 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)) { if (byte_count_total_bytes > sizeof(u32)) {
u32 offset = img->strip_byte_counts.long_val + counts_size * i; u32 offset = 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(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 { } else {
memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val), memcpy(&(strip->byte_count), &(img->strip_byte_counts.long_val),
counts_size); counts_size);
@ -303,16 +338,25 @@ bool read_strip_data(FILE *fp, const TiffImage *img, TiffStrip *strips) {
void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips, void read_strips(FILE *fp, const TiffImage *img, const TiffStrip *strips,
Pixel *buf) { 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) { for (u64 i = 0; i < img->strip_count; ++i) {
const TiffStrip *strip = &(strips[i]); const TiffStrip *strip = &(strips[i]);
for (u64 j = 0; j < img->image_width * img->image_length; ++j) { for (u64 j = 0; j < strip->byte_count / img->sample_count; ++j) {
Pixel *p = &(buf[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);
if (img->sample_count == 3) {
p->a = 255; p->a = 255;
} }
++position;
}
} }
} }