Compare commits

...

4 Commits

Author SHA1 Message Date
a3114e9387 Read each strip in a separate thread 2024-05-26 14:49:29 +01:00
256a65f5b3 Fix compile script 2024-05-26 14:49:19 +01:00
72e7a8171b Update .gitignore 2024-05-25 19:45:16 +01:00
fb972c4737 Load the image in a separate thread 2024-05-12 20:00:09 +01:00
4 changed files with 182 additions and 61 deletions

2
.gitignore vendored
View File

@ -5,5 +5,5 @@ big_endian*
float32_example.tiff float32_example.tiff
*.py *.py
tiffread tiffread
test.ppm test*
compile_commands.json compile_commands.json

View File

@ -9,11 +9,12 @@ INCLUDES="\
" "
LIBS="\ LIBS="\
-lm \ -lm \
-pthread \
$(pkg-config --libs sdl2) \ $(pkg-config --libs sdl2) \
" "
SRC="\ SRC="\
$(find ./src -name *.c | xargs -I{} echo -n "{} ") \ $(find ./src -name "*.c" | xargs -I{} echo -n "{} ") \
$(find intern/wizapp/src -type f -name *.c | xargs -I{} echo -n "{} ") \ $(find intern/wizapp/src -type f -name "*.c" | xargs -I{} echo -n "{} ") \
" "
OUT=tiffread OUT=tiffread

View File

@ -8,6 +8,7 @@
#include <SDL2/SDL_surface.h> #include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -32,8 +33,13 @@ struct point {
}; };
internal void write_debug_ppm6(const Image *img); internal void write_debug_ppm6(const Image *img);
internal SDL_Texture *image_to_texture(SDL_Renderer *renderer, internal void *load_tiff_image(void *args);
const Image *img);
typedef struct img_thread_args ImgThreadArgs;
struct img_thread_args {
const char *filename;
Arena *arena;
};
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int exit_code = EXIT_SUCCESS; int exit_code = EXIT_SUCCESS;
@ -45,14 +51,13 @@ int main(int argc, char *argv[]) {
const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif"; const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif";
Image *img = read_baseline_tiff(file_to_open, arena); pthread_t img_thread;
if (!img) { ImgThreadArgs args = {.filename = file_to_open, .arena = arena};
if (pthread_create(&img_thread, NULL, load_tiff_image, &args) != 0) {
exit_code = EXIT_FAILURE; exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_ARENA; goto MAIN_DESTROY_ARENA;
} }
write_debug_ppm6(img);
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
exit_code = EXIT_FAILURE; exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_ARENA; goto MAIN_DESTROY_ARENA;
@ -73,17 +78,23 @@ int main(int argc, char *argv[]) {
goto MAIN_DESTROY_WINDOW; goto MAIN_DESTROY_WINDOW;
} }
SDL_Texture *texture = image_to_texture(renderer, img); SDL_Surface *surface = NULL;
if (!texture) { if (pthread_join(img_thread, (void **)&surface) != 0 || !surface) {
exit_code = EXIT_FAILURE; exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_RENDERER; goto MAIN_DESTROY_RENDERER;
} }
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_SURFACE;
}
SDL_Rect dest = { SDL_Rect dest = {
.h = img->height, .h = surface->h,
.w = img->width, .w = surface->w,
.x = (WINDOW_WIDTH - img->width) / 2, .x = (WINDOW_WIDTH - surface->w) / 2,
.y = (WINDOW_HEIGHT - img->height) / 2, .y = (WINDOW_HEIGHT - surface->h) / 2,
}; };
bool running = true; bool running = true;
@ -110,6 +121,9 @@ int main(int argc, char *argv[]) {
SDL_DestroyTexture(texture); SDL_DestroyTexture(texture);
MAIN_DESTROY_SURFACE:
SDL_FreeSurface(surface);
MAIN_DESTROY_RENDERER: MAIN_DESTROY_RENDERER:
SDL_DestroyRenderer(renderer); SDL_DestroyRenderer(renderer);
@ -146,17 +160,19 @@ internal void write_debug_ppm6(const Image *img) {
fclose(out); fclose(out);
} }
internal SDL_Texture *image_to_texture(SDL_Renderer *renderer, internal void *load_tiff_image(void *args) {
const Image *img) { ImgThreadArgs *img_args = (ImgThreadArgs *)args;
SDL_Texture *output = NULL; Image *img = read_baseline_tiff(img_args->filename, img_args->arena);
if (!renderer || !img) { if (!img) {
goto IMAGE_TO_TEXTURE_RETURN; return NULL;
} }
write_debug_ppm6(img);
SDL_Surface *surface = SDL_CreateRGBSurface(0, img->width, img->height, 32, SDL_Surface *surface = SDL_CreateRGBSurface(0, img->width, img->height, 32,
RMASK, GMASK, BMASK, AMASK); RMASK, GMASK, BMASK, AMASK);
if (!surface) { if (!surface) {
goto IMAGE_TO_TEXTURE_RETURN; return NULL;
} }
SDL_LockSurface(surface); SDL_LockSurface(surface);
@ -170,10 +186,5 @@ internal SDL_Texture *image_to_texture(SDL_Renderer *renderer,
} }
SDL_UnlockSurface(surface); SDL_UnlockSurface(surface);
output = SDL_CreateTextureFromSurface(renderer, surface); return surface;
SDL_FreeSurface(surface);
IMAGE_TO_TEXTURE_RETURN:
return output;
} }

View File

@ -4,8 +4,10 @@
#include "image.h" #include "image.h"
#include "mem_arena.h" #include "mem_arena.h"
#include <assert.h> #include <assert.h>
#include <bits/pthreadtypes.h>
#include <math.h> #include <math.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -200,6 +202,7 @@ struct tiff_image {
typedef struct tiff_reader TiffReader; typedef struct tiff_reader TiffReader;
struct tiff_reader { struct tiff_reader {
const char *filename;
FILE *fp; FILE *fp;
TiffHdr header; TiffHdr header;
TiffIFD ifd; TiffIFD ifd;
@ -214,7 +217,8 @@ internal void read_alpha(TiffReader *reader);
internal void read_bits_per_sample(TiffReader *reader); internal void read_bits_per_sample(TiffReader *reader);
internal bool read_image_pixels(TiffReader *reader, Arena *arena); internal bool read_image_pixels(TiffReader *reader, Arena *arena);
internal bool read_strip_data(TiffReader *reader, Arena *arena); internal bool read_strip_data(TiffReader *reader, Arena *arena);
internal void read_strips(TiffReader *reader); internal bool read_strips(TiffReader *reader);
internal void *read_strip(void *arg);
internal void read_strip_data_field(const TiffReader *reader, internal void read_strip_data_field(const TiffReader *reader,
StripDataField *field); StripDataField *field);
internal bool read_field(const TiffField *field, TiffImage *img); internal bool read_field(const TiffField *field, TiffImage *img);
@ -231,7 +235,7 @@ Image *read_baseline_tiff(const char *file, Arena *arena) {
goto READ_BASELINE_RETURN_IMG; goto READ_BASELINE_RETURN_IMG;
} }
TiffReader reader = {.fp = fopen(file, "rb")}; TiffReader reader = {.filename = file, .fp = fopen(file, "rb")};
if (!reader.fp) { if (!reader.fp) {
goto READ_BASELINE_RETURN_IMG; goto READ_BASELINE_RETURN_IMG;
} }
@ -534,9 +538,7 @@ internal bool read_image_pixels(TiffReader *reader, Arena *arena) {
return false; return false;
} }
read_strips(reader); return read_strips(reader);
return true;
} }
internal bool read_strip_data(TiffReader *reader, Arena *arena) { internal bool read_strip_data(TiffReader *reader, Arena *arena) {
@ -585,42 +587,149 @@ internal bool read_strip_data(TiffReader *reader, Arena *arena) {
return true; return true;
} }
internal void read_strips(TiffReader *reader) { // internal void read_strips(TiffReader *reader) {
u64 position = 0; // u64 position = 0;
u64 main_samples = reader->img.sample_count - reader->img.extra_samples_count; // u64 main_samples = reader->img.sample_count -
TiffAlpha alpha = reader->img.alpha; // reader->img.extra_samples_count; TiffAlpha alpha = reader->img.alpha;
Pixel *p; // Pixel *p;
u64 start_offset; // u64 start_offset;
u64 alpha_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) {
// p = &(reader->pixels[position]);
// start_offset = strip->offset + j * reader->img.sample_count;
// alpha_offset = start_offset + main_samples + alpha.sample_offset;
// fread_with_offset(reader->fp, p, main_samples, start_offset);
// if (alpha.type == ALPHA_TYPE_UNDEFINED) {
// p->a = 255;
// } else {
// fread_with_offset(reader->fp, &(p->a), 1, alpha_offset);
// if (alpha.type == ALPHA_TYPE_UNASSOCIATED) {
// f32 a_norm = u8_normalise(p->a);
// p->r = u8_denormalise(u8_normalise(p->r) * a_norm);
// p->g = u8_denormalise(u8_normalise(p->g) * a_norm);
// p->b = u8_denormalise(u8_normalise(p->b) * a_norm);
// }
// }
// ++position;
// }
// }
// }
typedef struct strip_reader_args StripReaderArgs;
struct strip_reader_args {
FILE *fp;
const TiffStrip *strip;
u64 pixel_count;
u64 samples_per_pixel;
u64 main_samples;
TiffAlpha alpha;
Pixel *pixel_write_start;
};
internal bool read_strips(TiffReader *reader) {
bool output = true;
u64 position = 0;
u64 strips_read = 0;
u64 threads_created = 0;
StripReaderArgs args[reader->img.strip_count];
pthread_t threads[reader->img.strip_count];
for (u64 i = 0; i < reader->img.strip_count; ++i) { for (u64 i = 0; i < reader->img.strip_count; ++i) {
const TiffStrip *strip = &(reader->img.strips[i]); const TiffStrip *strip = &(reader->img.strips[i]);
u64 pixel_count = strip->byte_count / reader->img.sample_count;
args[i] = (StripReaderArgs){
.fp = fopen(reader->filename, "rb"),
.strip = strip,
.pixel_count = pixel_count,
.samples_per_pixel = reader->img.sample_count,
.main_samples =
reader->img.sample_count - reader->img.extra_samples_count,
.alpha = reader->img.alpha,
.pixel_write_start = &(reader->pixels[position]),
};
for (u64 j = 0; j < strip->byte_count / reader->img.sample_count; ++j) { if (!args[i].fp) {
p = &(reader->pixels[position]); output = false;
start_offset = strip->offset + j * reader->img.sample_count; goto READ_STRIPS_CLOSE_FILES;
alpha_offset = start_offset + main_samples + alpha.sample_offset;
fread_with_offset(reader->fp, p, main_samples, start_offset);
if (alpha.type == ALPHA_TYPE_UNDEFINED) {
p->a = 255;
} else {
fread_with_offset(reader->fp, &(p->a), 1, alpha_offset);
if (alpha.type == ALPHA_TYPE_UNASSOCIATED) {
f32 a_norm = u8_normalise(p->a);
p->r = u8_denormalise(u8_normalise(p->r) * a_norm);
p->g = u8_denormalise(u8_normalise(p->g) * a_norm);
p->b = u8_denormalise(u8_normalise(p->b) * a_norm);
}
}
++position;
} }
position += pixel_count;
++strips_read;
} }
for (u64 i = 0; i < reader->img.strip_count; ++i) {
if (pthread_create(&(threads[i]), NULL, read_strip, (void *)&(args[i])) !=
0) {
break;
}
++threads_created;
}
if (threads_created < reader->img.strip_count) {
for (u64 i = 0; i < strips_read; ++i) {
pthread_cancel(threads[i]);
}
return false;
}
for (u64 i = 0; i < reader->img.strip_count; ++i) {
pthread_join(threads[i], NULL);
}
READ_STRIPS_CLOSE_FILES:
for (u64 i = 0; i < strips_read; ++i) {
fclose(args[i].fp);
}
return output;
}
internal void *read_strip(void *arg) {
StripReaderArgs *args = (StripReaderArgs *)arg;
Pixel *p;
u64 write_offset = 0;
u64 read_offset;
u64 alpha_offset;
for (u64 j = 0; j < args->pixel_count; ++j) {
p = args->pixel_write_start + write_offset;
read_offset = args->strip->offset + j * args->samples_per_pixel;
alpha_offset = read_offset + args->main_samples + args->alpha.sample_offset;
fread_with_offset(args->fp, p, args->main_samples, read_offset);
if (args->alpha.type == ALPHA_TYPE_UNDEFINED) {
p->a = 255;
} else {
fread_with_offset(args->fp, &(p->a), 1, alpha_offset);
if (args->alpha.type == ALPHA_TYPE_UNASSOCIATED) {
f32 a_norm = u8_normalise(p->a);
p->r = u8_denormalise(u8_normalise(p->r) * a_norm);
p->g = u8_denormalise(u8_normalise(p->g) * a_norm);
p->b = u8_denormalise(u8_normalise(p->b) * a_norm);
}
}
++write_offset;
}
return NULL;
} }
internal void read_strip_data_field(const TiffReader *reader, internal void read_strip_data_field(const TiffReader *reader,