In the end SVG is just XML, so I picked an XML parser (my choice was xml.c) and then used the result to draw elements with LVGL’s vector graphics API. This is a crude example:
struct xml_document *document = xml_parse_document((uint8_t *)source, strlen(source));
if (!document) {
printf("Could parse document\n");
exit(EXIT_FAILURE);
}
struct xml_node *root = xml_document_root(document);
// lv_demo_vector_graphic();
lv_draw_buf_t *draw_buf = lv_draw_buf_create(480, 320, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO);
lv_obj_t *canvas = lv_canvas_create(lv_scr_act());
lv_canvas_set_draw_buf(canvas, draw_buf);
lv_layer_t layer;
lv_canvas_init_layer(canvas, &layer);
// Draw vector
lv_vector_dsc_t *ctx = lv_vector_dsc_create(&layer);
lv_vector_path_t *path = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
lv_area_t rect = {0, 0, 480, 320};
lv_vector_dsc_set_fill_color(ctx, lv_color_white());
lv_vector_clear_area(ctx, &rect);
for (size_t i = 0; i < xml_node_children(svg); i++) {
struct xml_node *xml_child = xml_node_child(svg, i);
struct xml_string *xml_name = xml_node_name(xml_child);
char *name_str = copy_string(xml_name);
printf("%s\n", name_str);
if (strcmp(name_str, "rect") == 0) {
printf("Found rect\n");
display_rect(ctx, path, xml_child);
}
free(name_str);
}
Where display_rect
is:
static int display_rect(lv_vector_dsc_t *ctx, lv_vector_path_t *path, struct xml_node *node) {
struct {
uint8_t x : 1;
uint8_t y : 1;
uint8_t width : 1;
uint8_t height : 1;
uint8_t fill : 1;
} arguments = {0};
uint8_t tmp = 0;
int32_t x = 0;
int32_t y = 0;
int32_t width = 0;
int32_t height = 0;
uint32_t fill = 0;
int32_t rx = 0;
int32_t ry = 0;
for (size_t i = 0; i < xml_node_attributes(node); i++) {
struct xml_string *xml_attribute_content = xml_node_attribute_content(node, i);
struct xml_string *xml_attribute_name = xml_node_attribute_name(node, i);
char *attribute_name = copy_string(xml_attribute_name);
char *attribute_content = copy_string(xml_attribute_content);
if (strcmp(attribute_name, "x") == 0) {
arguments.x = 1;
x = atoi(attribute_content);
} else if (strcmp(attribute_name, "y") == 0) {
arguments.y = 1;
y = atoi(attribute_content);
} else if (strcmp(attribute_name, "rx") == 0) {
rx = atoi(attribute_content);
} else if (strcmp(attribute_name, "ry") == 0) {
ry = atoi(attribute_content);
} else if (strcmp(attribute_name, "width") == 0) {
arguments.width = 1;
width = atoi(attribute_content);
} else if (strcmp(attribute_name, "height") == 0) {
arguments.height = 1;
height = atoi(attribute_content);
} else if (strcmp(attribute_name, "fill") == 0) {
if (attribute_content[0] == '#') {
fill = strtol(&attribute_content[1], NULL, 16);
} else if (strcmp(attribute_content, "white")) {
tmp = 1;
} else if (strcmp(attribute_content, "black")) {
tmp = 1;
fill = 0xFFFFFF;
}
arguments.fill = 1;
} else if (strcmp(attribute_name, "stroke") == 0) {
} else if (strcmp(attribute_name, "stroke-width") == 0) {
}
free(attribute_name);
free(attribute_content);
}
if (arguments.x && arguments.y && arguments.width && arguments.height) {
lv_vector_path_t *path2 = lv_vector_path_create(LV_VECTOR_PATH_QUALITY_MEDIUM);
lv_vector_dsc_identity(ctx);
lv_area_t rect = {x, y, x + width, y + height};
lv_vector_path_append_rect(path2, &rect, rx, ry);
lv_vector_dsc_set_fill_color(ctx, lv_color_make((fill >> 16) & 0xFF, (fill >> 8) & 0xFF, fill & 0xFF));
//"<rect x=\"-200\" y=\"0\" width=\"550\" height=\"180\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" "
//"transform=\"skewX(-50) translate(120 0)\" rx=\"10\" ry=\"10\" />"
if (tmp) {
lv_matrix_t matrix;
lv_matrix_identity(&matrix);
lv_matrix_skew(&matrix, -50, 0);
lv_matrix_translate(&matrix, 120, 0);
lv_vector_dsc_set_transform(ctx, &matrix);
}
lv_vector_path_append_path(path, path2);
lv_vector_dsc_add_path(ctx, path); // draw a path
//
if (tmp) {
lv_matrix_t matrix;
lv_matrix_identity(&matrix);
lv_vector_dsc_set_transform(ctx, &matrix);
}
printf("Rect %i-%i, %i-%i, 0x%X\n", (int)rect.x1, (int)rect.y1, (int)rect.x2, (int)rect.y2, (int)fill);
lv_vector_path_delete(path2);
}
return 0;
}
This is code for LVGL 9.1. The vector graphics API is still evolving and not properly documented, so I had to learn how it works by trial and error. I hope this helps.