Skip to content

Commit

Permalink
Support TinyVG format decoding and rendering
Browse files Browse the repository at this point in the history
Implemented support for decoding TinyVG format by parsing commands
step-by-step. Each decoded command is executed using twin's path
functions to render graphics. This enhances twin's capability to handle
compact vector graphics .

Ref:
https://tinyvg.tech/download/specification.pdf

Close #71
  • Loading branch information
ndsl7109256 committed Dec 10, 2024
1 parent 16f7f9e commit cb60903
Show file tree
Hide file tree
Showing 15 changed files with 1,650 additions and 15 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ ifeq ($(CONFIG_LOADER_GIF), y)
libtwin.a_files-y += src/image-gif.c
endif

ifeq ($(CONFIG_LOADER_TVG), y)
libtwin.a_files-y += src/image-tvg.c
endif

# Applications

libapps.a_files-y := apps/dummy.c
Expand All @@ -96,6 +100,7 @@ libapps.a_files-$(CONFIG_DEMO_CALCULATOR) += apps/calc.c
libapps.a_files-$(CONFIG_DEMO_LINE) += apps/line.c
libapps.a_files-$(CONFIG_DEMO_SPLINE) += apps/spline.c
libapps.a_files-$(CONFIG_DEMO_ANIMATION) += apps/animation.c
libapps.a_files-$(CONFIG_DEMO_IMAGE) += apps/image.c

libapps.a_includes-y := include

Expand Down
14 changes: 14 additions & 0 deletions apps/apps_image.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Twin - A Tiny Window System
* Copyright (c) 2024 National Cheng Kung University
* All rights reserved.
*/

#ifndef _APPS_IMAGE_H_
#define _APPS_IMAGE_H_

#include <twin.h>

void apps_image_start(twin_screen_t *screen, const char *name, int x, int y);

#endif /* _APPS_ANIMATION_H_ */
122 changes: 122 additions & 0 deletions apps/image.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Twin - A Tiny Window System
* Copyright (c) 2024 National Cheng Kung University
* All rights reserved.
*/

#include <stdlib.h>

#include "twin_private.h"

#include "apps_image.h"

#define _apps_image_pixmap(image) ((image)->widget.window->pixmap)
#define D(x) twin_double_to_fixed(x)
#define ASSET_PATH "assets/"
#define APP_WIDTH 400
#define APP_HEIGHT 400
typedef struct {
twin_widget_t widget;
twin_pixmap_t **pixes;
int image_idx;
} apps_image_t;

static const char *tvg_files[] = {
/* https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/ */
ASSET_PATH "tiger.tvg",
/* https://tinyvg.tech/img/chart.svg */
ASSET_PATH "chart.tvg",
/* https://freesvg.org/betrayed */
ASSET_PATH "comic.tvg",
/* https://github.com/PapirusDevelopmentTeam/papirus-icon-theme */
ASSET_PATH "folder.tvg",
/* https://materialdesignicons.com/ */
ASSET_PATH "shield.tvg",
/* https://tinyvg.tech/img/flowchart.png */
ASSET_PATH "flowchart.tvg",
};

static void _apps_image_paint(apps_image_t *img)
{
twin_operand_t srcop = {
.source_kind = TWIN_PIXMAP,
.u.pixmap = img->pixes[img->image_idx],
};

twin_composite(_apps_image_pixmap(img), 0, 0, &srcop, 0, 0, NULL, 0, 0,
TWIN_SOURCE, APP_WIDTH, APP_HEIGHT);
}

static twin_dispatch_result_t _apps_image_dispatch(twin_widget_t *widget,
twin_event_t *event)
{
apps_image_t *img = (apps_image_t *) widget;
if (_twin_widget_dispatch(widget, event) == TwinDispatchDone)
return TwinDispatchDone;
switch (event->kind) {
case TwinEventPaint:
_apps_image_paint(img);
break;
default:
break;
}
return TwinDispatchContinue;
}

static void _apps_image_button_signal(maybe_unused twin_button_t *button,
twin_button_signal_t signal,
void *closure)
{
if (signal != TwinButtonSignalDown)
return;

apps_image_t *img = closure;
const int n = sizeof(tvg_files) / sizeof(tvg_files[0]);
img->image_idx = img->image_idx == n - 1 ? 0 : img->image_idx + 1;
if (!img->pixes[img->image_idx]) {
twin_pixmap_t *pix = twin_tvg_to_pixmap_scale(
tvg_files[img->image_idx], TWIN_ARGB32, APP_WIDTH, APP_HEIGHT);
if (!pix)
return;
img->pixes[img->image_idx] = pix;
}
_twin_widget_queue_paint(&img->widget);
}

static void _apps_image_init(apps_image_t *img,
twin_box_t *parent,
twin_dispatch_proc_t dispatch)
{
static twin_widget_layout_t preferred = {0, 0, 1, 1};
preferred.height = parent->widget.window->screen->height * 3.0 / 4.0;
_twin_widget_init(&img->widget, parent, 0, preferred, dispatch);
img->image_idx = 0;
img->pixes = calloc(sizeof(tvg_files), sizeof(twin_pixmap_t *));
img->pixes[0] = twin_tvg_to_pixmap_scale(tvg_files[0], TWIN_ARGB32,
APP_WIDTH, APP_HEIGHT);
twin_button_t *button =
twin_button_create(parent, "Next Image", 0xFF482722, D(10),
TwinStyleBold | TwinStyleOblique);
twin_widget_set(&button->label.widget, 0xFFFEE4CE);
button->signal = _apps_image_button_signal;
button->closure = img;
button->label.widget.shape = TwinShapeRectangle;
}

static apps_image_t *apps_image_create(twin_box_t *parent)
{
apps_image_t *img = malloc(sizeof(apps_image_t));

_apps_image_init(img, parent, _apps_image_dispatch);
return img;
}

void apps_image_start(twin_screen_t *screen, const char *name, int x, int y)
{
twin_toplevel_t *toplevel =
twin_toplevel_create(screen, TWIN_ARGB32, TwinWindowApplication, x, y,
APP_WIDTH, APP_HEIGHT, name);
apps_image_t *img = apps_image_create(&toplevel->box);
(void) img;
twin_toplevel_show(toplevel);
}
4 changes: 4 additions & 0 deletions apps/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "apps_calc.h"
#include "apps_clock.h"
#include "apps_hello.h"
#include "apps_image.h"
#include "apps_line.h"
#include "apps_multi.h"
#include "apps_spline.h"
Expand Down Expand Up @@ -127,6 +128,9 @@ int main(void)
apps_animation_start(tx->screen, "Viewer", ASSET_PATH "nyancat.gif", 20,
20);
#endif
#if defined(CONFIG_DEMO_IMAGE)
apps_image_start(tx->screen, "Viewer", 20, 20);
#endif

twin_dispatch(tx);

Expand Down
Binary file added assets/chart.tvg
Binary file not shown.
Binary file added assets/comic.tvg
Binary file not shown.
Binary file added assets/flowchart.tvg
Binary file not shown.
Binary file added assets/folder.tvg
Binary file not shown.
Binary file added assets/shield.tvg
Binary file not shown.
Binary file added assets/tiger.tvg
Binary file not shown.
9 changes: 9 additions & 0 deletions configs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ config LOADER_GIF
bool "Enable GIF loader"
default y

config LOADER_TinyVG
bool "Enable TinyVG loader"
default y

endmenu

menu "Demo Applications"
Expand Down Expand Up @@ -113,4 +117,9 @@ config DEMO_ANIMATION
bool "Build animation demo"
default y
depends on DEMO_APPLICATIONS

config DEMO_IMAGE
bool "Build image demo"
default y
depends on DEMO_APPLICATIONS
endmenu
9 changes: 9 additions & 0 deletions include/twin.h
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,15 @@ twin_work_t *twin_set_work(twin_work_proc_t work_proc,

void twin_clear_work(twin_work_t *work);

/*
* image-tvg.c
*/

twin_pixmap_t *twin_tvg_to_pixmap_scale(const char *filepath,
twin_format_t fmt,
twin_coord_t w,
twin_coord_t h);

/*
* backend
*/
Expand Down
Loading

0 comments on commit cb60903

Please sign in to comment.