First botched attempt at reading image data :D

This commit is contained in:
Abdelrahman Said 2024-04-21 18:55:02 +01:00
parent 0bd448a8a9
commit 8040dd7381
9 changed files with 369 additions and 74 deletions

View File

@ -3,17 +3,19 @@
CC=clang
CFLAGS="-g -Wall -Werror -pedantic -fsanitize=address -fsanitize=undefined"
INCLUDES="\
-Isrc \
-I$(find ./src -type d | xargs -I{} echo -n "-I{} ") \
-Iintern/wizapp/aliases \
-Iintern/wizapp/cpath/include \
-Iintern/wizapp/dstr/include \
$(find intern/wizapp/mem/include -type d | xargs -I{} echo -n "-I{} ") \
$(pkg-config --cflags sdl2) \
"
LIBS="\
-lm \
$(pkg-config --libs sdl2) \
"
SRC="\
./src/*.c \
$(find ./src -name *.c | xargs -I{} echo -n "{} ") \
intern/wizapp/cpath/src/*.c \
intern/wizapp/dstr/src/*.c \
intern/wizapp/mem/src/*/*.c \

View File

@ -1,12 +1,40 @@
#include "aliases.h"
#include "image.h"
#include "mem_allocator.h"
#include "mem_ctx.h"
#include "tiffread.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define AMASK 0xff000000
#define BMASK 0x00ff0000
#define GMASK 0x0000ff00
#define RMASK 0x000000ff
#define WHITE 0xff
typedef struct point Point;
struct point {
u32 x;
u32 y;
};
Point point_from_index(u32 index, u32 w);
int main(int argc, char *argv[]) {
int exit_code = EXIT_SUCCESS;
wapp_mem_ctx_init(10 * 1024 * 1024, 2 * 1024 * 1024);
Allocator ctx_main_allocator = wapp_mem_ctx_allocator(CTX_DEST_BUFFER_MAIN);
Allocator ctx_temp_allocator = wapp_mem_ctx_allocator(CTX_DEST_BUFFER_TEMP);
@ -14,41 +42,134 @@ int main(int argc, char *argv[]) {
const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif";
read_baseline_tiff(file_to_open, &ctx_main_allocator);
Image *img = read_baseline_tiff(file_to_open, &ctx_main_allocator);
if (!img) {
exit_code = EXIT_FAILURE;
goto MAIN_FREE_CONTEXT;
}
// FILE *fp = fopen(file_to_open, "rb");
FILE *out = fopen("test.ppm", "wb");
// TiffHdr header;
// fread(&header, sizeof(header), 1, fp);
char magic[] = {'P', '6', '\n'};
fwrite(magic, sizeof(magic), 1, out);
// TiffIFD ifd = {0};
char size[128];
sprintf(size, "%lu %lu\n", img->width, img->height);
u64 size_length = strlen(size);
fwrite(size, size_length, 1, out);
// printf("ORDER: %04x\n", header.order);
// printf("MAGIC: %04x\n", header.magic);
char max[] = {'2', '5', '5', '\n'};
fwrite(max, sizeof(max), 1, out);
// fseek(fp, header.first_ifd_offset, SEEK_SET);
for (u64 i = 0; i < img->buf_length; i += 4) {
fwrite(&(img->data[i]), sizeof(u8), 3, out);
}
// fread(&(ifd.count), sizeof(ifd.count), 1, fp);
fclose(out);
// printf("COUNT: %u\n", ifd.count);
// if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
// exit_code = EXIT_FAILURE;
// goto MAIN_FREE_CONTEXT;
// };
// TiffField fields[ifd.count];
// memset(fields, 0, sizeof(TiffField) * ifd.count);
// for (u32 i = 0; i < ifd.count; ++i) {
// fread(fields + i, sizeof(TiffField), 1, fp);
// printf("ENTRY %02u (%lu)\n", i, ftell(fp));
// printf("\t TAG: %04u (%s)\n", fields[i].tag,
// tag_names[fields[i].tag] ? tag_names[fields[i].tag] : "UNKNOWN");
// printf("\t TYPE: 0x%04x (%s)\n", fields[i].type,
// field_types[fields[i].type].name ?
// field_types[fields[i].type].name
// : "UNKNOWN");
// printf("\t COUNT: %04u\n", fields[i].count);
// printf("\tVAL/OFF: %04u\n", fields[i].value_offset);
// SDL_Window *window =
// SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED,
// SDL_WINDOWPOS_CENTERED,
// WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN);
// if (!window) {
// exit_code = EXIT_FAILURE;
// goto MAIN_QUIT_SDL;
// }
// SDL_Renderer *renderer = SDL_CreateRenderer(
// window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// if (!renderer) {
// exit_code = EXIT_FAILURE;
// goto MAIN_DESTROY_WINDOW;
// }
// SDL_Surface *surface = SDL_CreateRGBSurface(0, img->width, img->height, 32,
// RMASK, GMASK, BMASK, AMASK);
// if (!surface) {
// exit_code = EXIT_FAILURE;
// goto MAIN_DESTROY_RENDERER;
// }
// uint64_t surface_length = surface->h * surface->pitch;
// printf("%lu\n", surface_length);
// printf("%u\n", surface->w * surface->h);
// SDL_LockSurface(surface);
// u64 position = 0;
// for (u64 i = 0; i < surface_length; i += surface->pitch) {
// memcpy(&(((u32 *)surface->pixels)[i]), &(img->data[position]),
// surface->pitch / sizeof(Pixel));
// position += surface->pitch;
// }
// SDL_UnlockSurface(surface);
// SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
// if (!texture) {
// exit_code = EXIT_FAILURE;
// goto MAIN_DESTROY_SURFACE;
// }
// SDL_Rect dest = {
// .w = surface->w,
// .h = surface->h,
// .x = (WINDOW_WIDTH - surface->w) / 2,
// .y = (WINDOW_HEIGHT - surface->h) / 2,
// };
// bool running = true;
// SDL_Event event = {0};
// while (running) {
// while (SDL_PollEvent(&event)) {
// switch (event.type) {
// case SDL_QUIT:
// running = false;
// break;
// }
// }
// SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
// SDL_RenderClear(renderer);
// SDL_RenderCopy(renderer, texture, NULL, &dest);
// SDL_RenderPresent(renderer);
// }
// SDL_DestroyTexture(texture);
// MAIN_DESTROY_SURFACE:
// SDL_FreeSurface(surface);
// MAIN_DESTROY_RENDERER:
// SDL_DestroyRenderer(renderer);
// MAIN_DESTROY_WINDOW:
// SDL_DestroyWindow(window);
// MAIN_QUIT_SDL:
// SDL_Quit();
MAIN_FREE_CONTEXT:
wapp_mem_ctx_free();
return 0;
return exit_code;
}
Point point_from_index(u32 index, u32 w) {
Point out = {0};
out.x = index % w;
out.y = (index - (index % w)) / w;
return out;
}

View File

@ -3,10 +3,12 @@
#include "endianness.h"
#include "image.h"
#include "mem_allocator.h"
#include "mem_arena.h"
#include "mem_ctx.h"
#include "mem_libc.h"
#include <math.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
@ -24,21 +26,22 @@
#define NULL_TIFF_IFD ((TiffIFD){0})
#define IS_NULL_IFD(IFD) (IFD.count == 0)
enum tiff_image_types {
TIFF_IMAGE_BILEVEL,
TIFF_IMAGE_GRAYSCALE,
TIFF_IMAGE_PALETTE,
TIFF_IMAGE_RGB,
#define INVALID_STRIP_COUNT 0
COUNT_TIFF_IMAGE,
};
#define INVALID_ALPHA_OFFSET -1
// clang-format off
internal u16 tiff_image_identifiers[COUNT_TIFF_IMAGE] = {
[TIFF_IMAGE_BILEVEL] = 0,
[TIFF_IMAGE_GRAYSCALE] = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE,
[TIFF_IMAGE_PALETTE] = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_COLOR_MAP,
[TIFF_IMAGE_RGB] = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL,
enum tiff_image_identifiers {
TIFF_IMAGE_BILEVEL = 0,
TIFF_IMAGE_GRAYSCALE = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE,
TIFF_IMAGE_PALETTE = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_COLOR_MAP,
TIFF_IMAGE_RGB = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL,
};
enum tiff_extra_samples {
TIFF_EXTRA_SAMPLE_UNSPECIFIED = 0x0000,
TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA = 0x0001,
TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA = 0x0002,
};
// clang-format on
@ -53,12 +56,12 @@ Image *read_baseline_tiff(const char *file, const Allocator *allocator) {
Image *img_out = NULL;
if (!file) {
goto RETURN_IMG;
goto READ_BASELINE_RETURN_IMG;
}
u64 name_length = strlen(file);
if (name_length < TIFF_FILENAME_MIN_LENGTH) {
goto RETURN_IMG;
goto READ_BASELINE_RETURN_IMG;
}
const char *ext = NULL;
@ -71,17 +74,17 @@ Image *read_baseline_tiff(const char *file, const Allocator *allocator) {
}
if (!ext || !IS_TIFF_EXTENSION(ext)) {
goto RETURN_IMG;
goto READ_BASELINE_RETURN_IMG;
}
FILE *fp = fopen(file, "rb");
if (!fp) {
goto RETURN_IMG;
goto READ_BASELINE_RETURN_IMG;
}
TiffHdr header = read_tiff_header(fp);
if (IS_NULL_HEADER(header)) {
goto FILE_CLEANUP;
goto READ_BASELINE_FILE_CLEANUP;
}
Allocator alloc;
@ -92,12 +95,12 @@ Image *read_baseline_tiff(const char *file, const Allocator *allocator) {
}
TiffIFD ifd = read_ifd(fp, &header, header.first_ifd_offset, &alloc);
read_fields(fp, &header, &ifd, &alloc);
img_out = read_fields(fp, &header, &ifd, &alloc);
FILE_CLEANUP:
READ_BASELINE_FILE_CLEANUP:
fclose(fp);
RETURN_IMG:
READ_BASELINE_RETURN_IMG:
return img_out;
}
@ -186,8 +189,13 @@ Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd,
u16 samples_per_pixel = 1;
u16 *bits_per_sample = NULL;
u16 extra_samples = 0;
bool has_alpha = false;
bool associated_alpha = false;
i32 alpha_offset =
INVALID_ALPHA_OFFSET; // Alpha offset following colour samples
u32 strip_count = 1;
u32 strip_count = INVALID_STRIP_COUNT;
u8 *strip_offsets = NULL;
u16 strip_offsets_type = TIFF_FIELD_TYPE_LONG;
u8 *strip_byte_counts = NULL;
@ -293,9 +301,16 @@ Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd,
break;
case TIFF_PUBLIC_TAG_STRIP_OFFSETS: {
strip_offsets_type = field->type;
u16 field_type_byte_count = field_types[strip_offsets_type].byte_count;
u16 field_type_byte_count = field_types[field->type].byte_count;
u32 total_byte_count = field->count * field_type_byte_count;
strip_count = field->count;
if (strip_count == INVALID_STRIP_COUNT) {
strip_count = field->count;
} else {
if (strip_count != field->count) {
return NULL;
}
}
strip_offsets =
(u8 *)wapp_mem_ctx_alloc(CTX_DEST_BUFFER_TEMP, total_byte_count);
@ -350,9 +365,16 @@ Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd,
break;
case TIFF_PUBLIC_TAG_STRIP_BYTE_COUNTS: {
strip_byte_counts_type = field->type;
u16 field_type_byte_count = field_types[strip_offsets_type].byte_count;
u16 field_type_byte_count = field_types[field->type].byte_count;
u32 total_byte_count = field->count * field_type_byte_count;
strip_count = field->count;
if (strip_count == INVALID_STRIP_COUNT) {
strip_count = field->count;
} else {
if (strip_count != field->count) {
return NULL;
}
}
strip_byte_counts =
(u8 *)wapp_mem_ctx_alloc(CTX_DEST_BUFFER_TEMP, total_byte_count);
@ -396,52 +418,202 @@ Image *read_fields(FILE *fp, const TiffHdr *header, const TiffIFD *ifd,
case TIFF_PUBLIC_TAG_COLOR_MAP:
identifier |= field->tag;
break;
case TIFF_PUBLIC_TAG_EXTRA_SAMPLES: {
extra_samples = field->count;
u64 byte_count = field->count * sizeof(u16);
u8 data_buf[byte_count];
if (byte_count <= 4) {
memcpy(data_buf, (void *)&(field->value_offset), byte_count);
} else {
read_from_file_with_offset(fp, data_buf, byte_count,
field->value_offset);
}
for (u32 i = 0; i < field->count; ++i) {
u16 sample = ((u16 *)&(field->value_offset))[i];
if (byte_count > 4) {
switch (header->order) {
case TIFF_ORDER_LITTLE_ENDIAN:
if (IS_BIG_ENDIAN) {
sample = htons(sample);
}
break;
case TIFF_ORDER_BIG_ENDIAN:
if (IS_LITTLE_ENDIAN) {
sample = ntohs(sample);
}
break;
}
}
if (sample > TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA) {
return NULL;
}
if (sample > TIFF_EXTRA_SAMPLE_UNSPECIFIED) {
if (has_alpha) {
return NULL;
}
has_alpha = true;
associated_alpha =
sample == TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA ? true : false;
alpha_offset = i;
}
}
break;
}
default:
break;
}
}
if (identifier == tiff_image_identifiers[TIFF_IMAGE_BILEVEL]) {
printf("BILEVEL\n");
} else if (identifier == tiff_image_identifiers[TIFF_IMAGE_GRAYSCALE]) {
printf("GRAYSCALE\n");
} else if (identifier == tiff_image_identifiers[TIFF_IMAGE_PALETTE]) {
printf("PALETTE\n");
} else if (identifier == tiff_image_identifiers[TIFF_IMAGE_RGB]) {
printf("RGB\n");
} else {
printf("UNKNOWN\n");
switch (identifier) {
case TIFF_IMAGE_BILEVEL:
case TIFF_IMAGE_GRAYSCALE:
if (photometric_interpretation >
TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO) {
return NULL;
}
break;
case TIFF_IMAGE_PALETTE:
if (photometric_interpretation !=
TIFF_PHOTOMETRIC_INTERPRETATION_RGB_PALETTE) {
return NULL;
}
break;
case TIFF_IMAGE_RGB:
if (photometric_interpretation != TIFF_PHOTOMETRIC_INTERPRETATION_RGB) {
return NULL;
}
break;
default:
return NULL;
}
printf("WIDTH: %lu, HEIGHT: %lu\n", width, height);
printf("SAMPLES: %u\n", samples_per_pixel);
printf("EXTRA SAMPLES: %u\n", extra_samples);
printf("ALPHA: %s, %s, %d\n", has_alpha ? "HAS ALPHA" : "NO ALPHA",
has_alpha && associated_alpha ? "ASSOCIATED"
: has_alpha ? "UNASSOCIATED"
: "N/A",
alpha_offset);
printf("STRIPS: %u\n", strip_count);
printf("PHOTOMETRIC INTERPRETATION: %u\n", photometric_interpretation);
printf("BITS PER SAMPLE: ");
for (u64 i = 0; i < samples_per_pixel; ++i) {
printf("%u\n", bits_per_sample[i]);
printf("%u ", bits_per_sample[i]);
}
printf("\n");
if (has_alpha && alpha_offset == INVALID_ALPHA_OFFSET) {
return NULL;
}
printf("OFFSETS: ");
Image *img_out = NULL;
Arena *temp_arena;
u64 img_buf_size = width * height * sizeof(Pixel);
wapp_mem_arena_init(&temp_arena, img_buf_size * 4);
u8 *temp_img_buf = wapp_mem_arena_alloc(temp_arena, img_buf_size);
if (!temp_img_buf) {
return NULL;
}
u64 position = 0;
for (u64 i = 0; i < strip_count; ++i) {
u64 offset;
u64 count;
if (strip_offsets_type == TIFF_FIELD_TYPE_LONG) {
printf("%u ", ((u32 *)strip_offsets)[i]);
offset = ((u32 *)strip_offsets)[i];
} else {
printf("%u ", ((u16 *)strip_offsets)[i]);
offset = ((u16 *)strip_offsets)[i];
}
}
printf("\n");
printf("COUNTS: ");
for (u64 i = 0; i < strip_count; ++i) {
if (strip_byte_counts_type == TIFF_FIELD_TYPE_LONG) {
printf("%u ", ((u32 *)strip_byte_counts)[i]);
count = ((u32 *)strip_byte_counts)[i];
} else {
printf("%u ", ((u16 *)strip_byte_counts)[i]);
count = ((u16 *)strip_byte_counts)[i];
}
u8 *strip_data = wapp_mem_arena_alloc(temp_arena, count);
read_from_file_with_offset(fp, strip_data, count, offset);
if (samples_per_pixel == 4 && has_alpha) {
memcpy(&(temp_img_buf[position]), strip_data, count);
position += count;
} else if (samples_per_pixel > 4) {
for (u64 j = 0; j < count; ++j) {
memcpy(&(temp_img_buf[position]), &(strip_data[j]), 3);
j += 3;
if (has_alpha) {
memcpy(&(temp_img_buf[position]), &(strip_data[j + alpha_offset]), 1);
j += 1;
} else {
temp_img_buf[position] = 255;
}
j += samples_per_pixel - 4;
position += 1;
}
} else if (samples_per_pixel == 3) {
if (identifier == TIFF_IMAGE_RGB) {
for (u64 j = 0; j < count; ++j) {
memcpy(&(temp_img_buf[position]), &(strip_data[j]), 3);
j += 3;
position += 3;
temp_img_buf[position++] = 255;
}
} else {
goto READ_FIELDS_FREE_ARENA;
}
} else if (samples_per_pixel == 1) {
if (identifier == TIFF_IMAGE_RGB) {
goto READ_FIELDS_FREE_ARENA;
}
for (u64 j = 0; j < count; ++j) {
for (u64 k = 0; k < 3; ++k) {
memcpy(&(temp_img_buf[position]), &(strip_data[j]), 1);
}
j += 1;
position += 3;
if (has_alpha) {
memcpy(&(temp_img_buf[position]), &(strip_data[j + alpha_offset]), 1);
j += 1;
} else {
temp_img_buf[position] = 255;
}
position += 1;
}
} else {
goto READ_FIELDS_FREE_ARENA;
}
}
printf("\n");
return NULL;
img_out = create_image(width, height, (Pixel *)temp_img_buf, allocator);
READ_FIELDS_FREE_ARENA:
wapp_mem_arena_free(&temp_arena);
return img_out;
}
void read_from_file_with_offset(FILE *fp, void *dst, u64 count, u64 offset) {