Skip to content

Commit

Permalink
Implement a generic image loader
Browse files Browse the repository at this point in the history
The symbols of available image loaders should be hidden. This commit
introduces a generic image loader that can select the appropriate image
loader implementation by parsing the name of the given image file.

Currently, both PNG and JPEG image formats are supported, and we might
support (animated) GIFs later.

Close #14
  • Loading branch information
jserv committed Aug 1, 2024
1 parent 4c96aea commit db1162e
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 21 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ libtwin.a_files-y = \
src/icon.c \
src/pixmap.c \
src/timeout.c \
src/image.c \
src/api.c

libtwin.a_includes-y := \
Expand Down
15 changes: 4 additions & 11 deletions apps/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@

#define ASSET_PATH "assets/"

/**
/*
* Load the background pixmap from storage.
* @filename: File name of a PNG background.
*
* Return a default pattern if the load of @filename fails.
* Return a default pattern if the load of @path or image loader fails.
*/
static twin_pixmap_t *load_background(twin_screen_t *screen,
const char *filename)
static twin_pixmap_t *load_background(twin_screen_t *screen, const char *path)
{
#if defined(CONFIG_LOADER_PNG)
twin_pixmap_t *raw_background = twin_png_to_pixmap(filename, TWIN_ARGB32);
twin_pixmap_t *raw_background = twin_pixmap_from_file(path, TWIN_ARGB32);
if (!raw_background) /* Fallback to a default pattern */
return twin_make_pattern();

Expand Down Expand Up @@ -67,9 +63,6 @@ static twin_pixmap_t *load_background(twin_screen_t *screen,
twin_pixmap_destroy(raw_background);

return scaled_background;
#else
return twin_make_pattern();
#endif
}

static twin_context_t *tx = NULL;
Expand Down
10 changes: 2 additions & 8 deletions include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -687,16 +687,10 @@ void twin_icon_draw(twin_pixmap_t *pixmap,
twin_matrix_t matrix);

/*
* image-jpeg.c
* image.c
*/

twin_pixmap_t *twin_jpeg_to_pixmap(const char *filepath, twin_format_t fmt);

/*
* image-png.c
*/

twin_pixmap_t *twin_png_to_pixmap(const char *filepath, twin_format_t fmt);
twin_pixmap_t *twin_pixmap_from_file(const char *path, twin_format_t fmt);

/*
* label.c
Expand Down
16 changes: 16 additions & 0 deletions include/twin_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,4 +536,20 @@ static inline int twin_clz(uint32_t v)
}
#endif

/* Pattern Matching for C macros.
* https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms
*/

/* In Visual Studio, __VA_ARGS__ is treated as a separate parameter. */
#define FIX_VC_BUG(x) x

/* catenate */
#define PRIMITIVE_CAT(a, ...) FIX_VC_BUG(a##__VA_ARGS__)

#define IIF(c) PRIMITIVE_CAT(IIF_, c)
/* run the 2nd parameter */
#define IIF_0(t, ...) __VA_ARGS__
/* run the 1st parameter */
#define IIF_1(t, ...) t

#endif /* _TWIN_PRIVATE_H_ */
2 changes: 1 addition & 1 deletion src/image-jpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static void twin_jpeg_error_exit(j_common_ptr cinfo)
longjmp(jerr->jbuf, 1);
}

twin_pixmap_t *twin_jpeg_to_pixmap(const char *filepath, twin_format_t fmt)
twin_pixmap_t *_twin_jpeg_to_pixmap(const char *filepath, twin_format_t fmt)
{
twin_pixmap_t *pix = NULL;

Expand Down
2 changes: 1 addition & 1 deletion src/image-png.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static void _convertBGRtoARGB(uint8_t *data, int width, int height)
}
#endif

twin_pixmap_t *twin_png_to_pixmap(const char *filepath, twin_format_t fmt)
twin_pixmap_t *_twin_png_to_pixmap(const char *filepath, twin_format_t fmt)
{
uint8_t signature[8];
int rb = 0;
Expand Down
81 changes: 81 additions & 0 deletions src/image.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <string.h>
#include <strings.h>

#include "twin_private.h"

#if !defined(CONFIG_LOADER_PNG)
#define CONFIG_LOADER_PNG 0
#endif

#if !defined(CONFIG_LOADER_JPEG)
#define CONFIG_LOADER_JPEG 0
#endif

/* Feature test macro */
#define LOADER_HAS(x) CONFIG_LOADER_##x

/* clang-format off */
#define SUPPORTED_FORMATS \
IIF(LOADER_HAS(PNG))( \
_(png) \
) \
IIF(LOADER_HAS(JPEG))( \
_(jpeg) \
)
/* clang-format on */

typedef enum {
IMAGE_TYPE_unknown,
#define _(x) IMAGE_TYPE_##x,
SUPPORTED_FORMATS
#undef _
} twin_image_format_t;

/* FIXME: Check the header of the given images to determine the supported image
* formats instead of parsing the filename without checking its content.
*/
static twin_image_format_t image_type_from_name(const char *path)
{
twin_image_format_t type = IMAGE_TYPE_unknown;
const char *extname = strrchr(path, '.');
if (!extname)
return IMAGE_TYPE_unknown;
#if LOADER_HAS(PNG)
else if (!strcasecmp(extname, ".png")) {
type = IMAGE_TYPE_png;
}
#endif
#if LOADER_HAS(JPEG)
else if (!strcasecmp(extname, ".jpg") || !strcasecmp(extname, ".jpeg")) {
type = IMAGE_TYPE_jpeg;
}
#endif
/* otherwise, unsupported format */

return type;
}

#define _(x) \
twin_pixmap_t *_twin_##x##_to_pixmap(const char *filepath, \
twin_format_t fmt);
SUPPORTED_FORMATS
#undef _

typedef twin_pixmap_t *(*loader_func_t)(const char *, twin_format_t);

/* clang-format off */
static loader_func_t image_loaders[] = {
[IMAGE_TYPE_unknown] = NULL,
#define _(x) [IMAGE_TYPE_##x] = _twin_##x##_to_pixmap,
SUPPORTED_FORMATS
#undef _
};
/* clang-format on */

twin_pixmap_t *twin_pixmap_from_file(const char *path, twin_format_t fmt)
{
loader_func_t loader = image_loaders[image_type_from_name(path)];
if (!loader)
return NULL;
return loader(path, fmt);
}

0 comments on commit db1162e

Please sign in to comment.