Compare commits

...

47 Commits

Author SHA1 Message Date
35a33e2fa6 Reformat 2024-05-26 17:56:32 +01:00
1c08881dfb Ensure pthread_join succeeded before returning true 2024-05-26 17:51:28 +01:00
7593eb4732 Add release build 2024-05-26 15:54:01 +01:00
ec2835e900 Read the image in a separate thread and ensure each strip is read in its own thread (#1)
Reviewed-on: #1
Co-authored-by: Abdelrahman <said.abdelrahman89@gmail.com>
Co-committed-by: Abdelrahman <said.abdelrahman89@gmail.com>
2024-05-26 14:44:12 +00:00
53c70156a6 Update .gitignore 2024-05-26 14:52:42 +01:00
ad4b7b40aa Update .gitignore 2024-05-26 14:52:00 +01:00
aa12b62e7e Fix compile script 2024-05-26 14:51:53 +01:00
5762ac33b0 Reorganise type definitions 2024-05-12 17:34:03 +01:00
efad22f21e Fix alpha multiplication for images with unassociated alpha 2024-05-06 00:54:25 +01:00
d278d7ee55 Multiply RGB when reading image with unassociated alpha 2024-05-06 00:37:23 +01:00
1c667f4128 Move all TIFF type definitions to the source file 2024-05-06 00:31:14 +01:00
c2391df946 Update main.c 2024-05-05 23:42:38 +01:00
b2f002b12f Increase MAIN_ARENA_CAPACITY 2024-05-05 23:41:14 +01:00
cd424bf074 Remove NULL header, ifd and image definitions 2024-05-05 23:33:53 +01:00
11798a0683 Main read functions return boolean 2024-05-05 23:26:02 +01:00
c2a55279fd Rename load_image_pixels to read_image_pixels 2024-05-05 22:57:47 +01:00
53f53874a6 Update 8-bit assertion 2024-05-05 22:51:17 +01:00
ba21bcb2f4 Switch internal reading functions to directly manipulate reader object 2024-05-05 22:46:13 +01:00
5bf78d3e01 Add comment 2024-05-05 22:13:37 +01:00
38862899d0 Read bits per sample 2024-05-05 22:05:39 +01:00
f0d4108a64 Add reading alpha 2024-05-05 21:21:48 +01:00
3e3c4d27fe Reorder type definitions 2024-05-05 19:47:20 +01:00
ed2737d330 Check field sizes against field type sizes instead of C primitives 2024-05-05 18:42:24 +01:00
9b7e07b9ad Update .gitignore 2024-05-05 16:28:30 +01:00
71b7c682db Rename read_fields to read_ifd_fields 2024-05-05 16:25:39 +01:00
a9143642a0 Declare TiffReader before attempting to open the file 2024-05-04 23:52:15 +01:00
d195086af8 Make functions internal 2024-05-04 23:48:01 +01:00
3f022acf9c Reorder functions 2024-05-04 23:46:24 +01:00
484d30d84c Add MAIN_ARENA_CAPACITY constant 2024-05-04 23:34:21 +01:00
de0235c0af Refactor reading the strip data fields into a function 2024-05-04 23:31:20 +01:00
b546ce9fa7 Calculate strip field size once 2024-05-04 22:47:23 +01:00
c98802542d Add TiffReader struct 2024-05-04 22:35:12 +01:00
9fdee24672 Refactor loading image data 2024-05-04 22:01:24 +01:00
cd698a3921 Add debug flag to compile script 2024-05-04 22:01:05 +01:00
9312c0fb6b Move TiffStrip array inside the TiffImage struct 2024-05-04 21:17:22 +01:00
51f79275de Assert image is RGB earlier 2024-05-04 20:59:57 +01:00
a508048211 Display loaded TIFF in SDL window 2024-05-04 19:15:34 +01:00
8f9edb441a Update .gitignore 2024-05-02 22:01:50 +01:00
4b52630c1e Implement reading RGB and RGBA images 2024-05-02 22:00:32 +01:00
c46535c20b Test implementation of read_strips 2024-05-01 23:53:04 +01:00
55720ac331 Fix bug with PPM writing 2024-05-01 23:52:46 +01:00
8f20c7b30a Update image creation function 2024-05-01 23:52:32 +01:00
69c13b83ea Read strip data 2024-05-01 00:17:53 +01:00
d508af1809 Refactor read_fields function 2024-04-30 22:17:17 +01:00
e371ca7160 Remove unnecessary comments 2024-04-30 22:01:55 +01:00
eaa6e52fbe Switch from using Allocator to Arena 2024-04-30 22:00:54 +01:00
3c6e5defb9 Fix compile script 2024-04-30 22:00:31 +01:00
7 changed files with 969 additions and 527 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@
refs
file_example*
big_endian*
float32_example.tiff
*.py
tiffread
test*
compile_commands.json

38
compile
View File

@@ -1,19 +1,41 @@
#!/bin/bash
BUILD_TYPE="debug"
while [[ $# > 0 ]];do
case $1 in
--release)
BUILD_TYPE="release"
shift
;;
*|-*|--*)
echo "Unknown option $1"
exit 1
;;
esac
done
CC=clang
CFLAGS="-g -Wall -Werror -pedantic -fsanitize=address -fsanitize=undefined"
if [[ $BUILD_TYPE == "release" ]]; then
CFLAGS="-O3 -Wall -Werror -pedantic"
else
CFLAGS="-g -Wall -Werror -pedantic -fsanitize=address -fsanitize=undefined -DDEBUG"
fi
INCLUDES="\
-I$(find ./src -type d | xargs -I{} echo -n "-I{} ") \
$(find intern/wizapp/src -type d | xargs -I{} echo -n "-I{} ") \
$(pkg-config --cflags sdl2) \
-I$(find ./src -type d | xargs -I{} echo -n "-I{} ") \
$(find intern/wizapp/src -type d | xargs -I{} echo -n "-I{} ") \
$(pkg-config --cflags sdl2) \
"
LIBS="\
-lm \
$(pkg-config --libs sdl2) \
-lm \
-pthread \
$(pkg-config --libs sdl2) \
"
SRC="\
$(find ./src -name *.c | xargs -I{} echo -n "{} ") \
$(find intern/wizapp/src -type f -name *.x | xargs -I{} echo -n "{} ") \
$(find ./src -name "*.c" | xargs -I{} echo -n "{} ") \
$(find intern/wizapp/src -type f -name "*.c" | xargs -I{} echo -n "{} ") \
"
OUT=tiffread

View File

@@ -1,45 +1,26 @@
#include "image.h"
#include "mem_allocator.h"
#include "mem_libc.h"
#include "mem_arena.h"
#include <stddef.h>
#include <string.h>
Image *create_image(u64 width, u64 height, Pixel *data,
const Allocator *allocator) {
Allocator alloc;
if (!allocator) {
alloc = wapp_mem_libc_allocator();
} else {
alloc = *allocator;
Image *create_image(u64 width, u64 height, Pixel *data, Arena *arena) {
if (!arena) {
return NULL;
}
u64 buf_length = width * height;
u64 total_size = sizeof(Image) + sizeof(Pixel) * buf_length;
u64 pixel_count = width * height;
u64 buf_length = sizeof(Pixel) * pixel_count;
u64 alloc_size = sizeof(Image) + buf_length;
Image *img = wapp_mem_allocator_alloc(&alloc, total_size);
Image *img = wapp_mem_arena_alloc(arena, alloc_size);
if (!img) {
return NULL;
}
img->width = width;
img->height = height;
img->buf_length = buf_length;
img->pixel_count = pixel_count;
memcpy(img->data, data, buf_length);
return img;
}
void destroy_image(Image **img, const Allocator *allocator) {
if (!img || !(*img)) {
return;
}
Allocator alloc;
if (!allocator) {
alloc = wapp_mem_libc_allocator();
} else {
alloc = *allocator;
}
wapp_mem_allocator_free(&alloc, (void **)img);
}

View File

@@ -1,7 +1,7 @@
#ifndef IMAGE_H
#define IMAGE_H
#include "mem_allocator.h"
#include "mem_arena.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
@@ -20,13 +20,11 @@ typedef struct image Image;
struct image {
u64 width;
u64 height;
u64 buf_length;
u64 pixel_count;
Pixel data[];
};
Image *create_image(u64 width, u64 height, Pixel *data,
const Allocator *allocator);
void destroy_image(Image **img, const Allocator *allocator);
Image *create_image(u64 width, u64 height, Pixel *data, Arena *arena);
#ifdef __cplusplus
}

View File

@@ -1,21 +1,26 @@
#include "aliases.h"
#include "image.h"
#include "mem_allocator.h"
#include "mem_ctx.h"
#include "mem_arena.h"
#include "tiffread.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_events.h>
#include <SDL2/SDL_rect.h>
#include <SDL2/SDL_render.h>
#include <SDL2/SDL_surface.h>
#include <SDL2/SDL_video.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAIN_ARENA_CAPACITY 50 * 1024 * 1024
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define VIEW_AREA_WIDTH 700
#define VIEW_AREA_HEIGHT 500
#define AMASK 0xff000000
#define BMASK 0x00ff0000
@@ -30,24 +35,110 @@ struct point {
u32 y;
};
Point point_from_index(u32 index, u32 w);
internal void write_debug_ppm6(const Image *img);
internal void *load_tiff_image(void *args);
internal SDL_Rect get_dest_rect(SDL_Surface *surface);
typedef struct img_thread_args ImgThreadArgs;
struct img_thread_args {
const char *filename;
Arena *arena;
};
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);
(void)(ctx_temp_allocator);
Arena *arena = NULL;
if (!wapp_mem_arena_init(&arena, MAIN_ARENA_CAPACITY)) {
return EXIT_FAILURE;
}
const char *file_to_open = argc > 1 ? argv[1] : "./resources/test.tif";
Image *img = read_baseline_tiff(file_to_open, &ctx_main_allocator);
if (!img) {
pthread_t img_thread;
ImgThreadArgs args = {.filename = file_to_open, .arena = arena};
if (pthread_create(&img_thread, NULL, load_tiff_image, &args) != 0) {
exit_code = EXIT_FAILURE;
goto MAIN_FREE_CONTEXT;
goto MAIN_DESTROY_ARENA;
}
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_ARENA;
};
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 = NULL;
if (pthread_join(img_thread, (void **)&surface) != 0 || !surface) {
exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_RENDERER;
}
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
exit_code = EXIT_FAILURE;
goto MAIN_DESTROY_SURFACE;
}
SDL_Rect dest = get_dest_rect(surface);
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_DESTROY_ARENA:
wapp_mem_arena_destroy(&arena);
return exit_code;
}
internal void write_debug_ppm6(const Image *img) {
FILE *out = fopen("test.ppm", "wb");
char magic[] = {'P', '6', '\n'};
@@ -61,115 +152,51 @@ int main(int argc, char *argv[]) {
char max[] = {'2', '5', '5', '\n'};
fwrite(max, sizeof(max), 1, out);
for (u64 i = 0; i < img->buf_length; i += 4) {
for (u64 i = 0; i < img->pixel_count; ++i) {
fwrite(&(img->data[i]), sizeof(u8), 3, out);
}
fclose(out);
// if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
// exit_code = EXIT_FAILURE;
// goto MAIN_FREE_CONTEXT;
// };
// 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 exit_code;
}
Point point_from_index(u32 index, u32 w) {
Point out = {0};
internal void *load_tiff_image(void *args) {
ImgThreadArgs *img_args = (ImgThreadArgs *)args;
Image *img = read_baseline_tiff(img_args->filename, img_args->arena);
if (!img) {
return NULL;
}
out.x = index % w;
write_debug_ppm6(img);
out.y = (index - (index % w)) / w;
SDL_Surface *surface = SDL_CreateRGBSurface(0, img->width, img->height, 32,
RMASK, GMASK, BMASK, AMASK);
if (!surface) {
return NULL;
}
return out;
SDL_LockSurface(surface);
u64 position = 0;
for (u64 i = 0; i < img->pixel_count; i += surface->w) {
void *start = (void *)((uptr)(surface->pixels) + position);
memcpy(start, &(img->data[i]), surface->w * sizeof(Pixel));
position += surface->pitch;
}
SDL_UnlockSurface(surface);
return surface;
}
internal SDL_Rect get_dest_rect(SDL_Surface *surface) {
f64 ratio = (f64)(surface->h) / (f64)(surface->w);
u64 width = surface->w <= VIEW_AREA_WIDTH ? surface->w : VIEW_AREA_WIDTH;
u64 height = width * ratio;
return (SDL_Rect){
.w = width,
.h = height,
.x = (WINDOW_WIDTH - width) / 2,
.y = (WINDOW_HEIGHT - height) / 2,
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,130 +1,14 @@
#ifndef TIFFREAD_H
#define TIFFREAD_H
#include "mem_arena.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "aliases.h"
#include "image.h"
#include <stdbool.h>
#define TYPE_MAX_COUNT (UINT8_MAX * sizeof(const char *))
typedef struct hdr TiffHdr;
struct hdr {
u16 order;
u16 magic;
u32 first_ifd_offset;
};
typedef struct field TiffField;
struct field {
u16 tag;
u16 type;
u32 count;
u32 value_offset;
};
typedef struct IFD TiffIFD;
struct IFD {
u16 count;
TiffField *fields;
u32 next_ifd;
};
// clang-format off
enum tiff_byte_order {
TIFF_ORDER_LITTLE_ENDIAN = 0x4949,
TIFF_ORDER_BIG_ENDIAN = 0x4d4d,
};
enum tiff_public_tags {
#include "tiff_public_tags.inc"
};
enum tiff_field_types {
#include "tiff_field_types.inc"
};
typedef struct field_type TiffFieldType;
struct field_type {
const char *name;
u16 byte_count;
};
internal TiffFieldType field_types[TYPE_MAX_COUNT] = {
#define TIFF_TYPE_LOOKUP
#include "tiff_field_types.inc"
#undef TIFF_TYPE_LOOKUP
};
typedef enum tiff_image_type_names {
TIFF_IMAGE_TYPE_INVALID = 0,
TIFF_IMAGE_TYPE_BILEVEL = 1,
TIFF_IMAGE_TYPE_GRAYSCALE = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE,
TIFF_IMAGE_TYPE_PALETTE = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_COLOR_MAP,
TIFF_IMAGE_TYPE_RGB = TIFF_PUBLIC_TAG_BITS_PER_SAMPLE | TIFF_PUBLIC_TAG_SAMPLES_PER_PIXEL,
} TiffImageType;
enum tiff_extra_samples {
TIFF_EXTRA_SAMPLE_UNSPECIFIED = 0x0000,
TIFF_EXTRA_SAMPLE_ASSOCIATED_ALPHA = 0x0001,
TIFF_EXTRA_SAMPLE_UNASSOCIATED_ALPHA = 0x0002,
};
enum tiff_compression {
TIFF_COMPRESSION_UNCOMPRESSED = 0x0001,
TIFF_COMPRESSION_CCITT_1D = 0x0002,
TIFF_COMPRESSION_GROUP_3_FAX = 0x0003,
TIFF_COMPRESSION_GROUP_4_FAX = 0x0004,
TIFF_COMPRESSION_LZW = 0x0005,
TIFF_COMPRESSION_JPEG = 0x0006,
TIFF_COMPRESSION_PACK_BITS = 0x8005,
};
enum tiff_photometric_interpretation {
TIFF_PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO = 0x0000,
TIFF_PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO = 0x0001,
TIFF_PHOTOMETRIC_INTERPRETATION_RGB = 0x0002,
TIFF_PHOTOMETRIC_INTERPRETATION_RGB_PALETTE = 0x0003,
TIFF_PHOTOMETRIC_INTERPRETATION_TRANSPARENCY_MASK = 0x0004,
TIFF_PHOTOMETRIC_INTERPRETATION_CMYK = 0x0005,
TIFF_PHOTOMETRIC_INTERPRETATION_YCbCr = 0x0006,
TIFF_PHOTOMETRIC_INTERPRETATION_CIELab = 0x0008,
TIFF_PHOTOMETRIC_INTERPRETATION_INVALID,
};
enum tiff_planar_configuration {
TIFF_PLANAR_CONFIG_CHUNKY = 0x0001,
TIFF_PLANAR_CONFIG_PLANAR = 0x0002,
};
// clang-format on
typedef struct tiff_image TiffImage;
struct tiff_image {
TiffImageType type;
u32 image_width;
u32 image_length;
u32 bits_per_sample;
u32 sample_count;
bool bits_per_sample_offset;
u16 compression;
u16 photometric_interpretation;
u32 strip_offsets;
bool strip_offsets_offset;
u32 rows_per_strip;
u32 strip_byte_counts;
bool strip_byte_counts_offset;
u32 strip_count;
u32 color_map;
u32 extra_samples;
u32 extra_samples_count;
bool extra_samples_offset;
};
Image *read_baseline_tiff(const char *file, const Allocator *allocator);
Image *read_baseline_tiff(const char *file, Arena *arena);
#ifdef __cplusplus
}