-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support TinyVG format decoding and rendering #77
base: main
Are you sure you want to change the base?
Conversation
0c18345
to
cd9554e
Compare
330f7a8
to
88edea8
Compare
Summarize the rendering of TinyVG by validating the examples provided by TinyVG website. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tiger SVG is a standard demonstration image for SVG viewers, which can be set as the default viewer image in TinyVG rendering.
The font rasterization in TinyVG image does not precisely match the rendered flow chart. Could you verify? |
src/path.c
Outdated
@@ -369,6 +369,7 @@ void twin_path_arc_ellipse(twin_path_t *path, | |||
param.extent); | |||
|
|||
twin_path_set_matrix(path, save); | |||
twin_path_draw(path, target_x, target_y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't get it. Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there might be some error in the arc ellipse calculation, so I enforced drawing to the target point to ensure correctness.
I would expect that we can overcome the underlying issues before the merging of this pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the accuracy of twin_acos
could be improved. When I use the acos function from the standard math library, the results seem better. To enhance the accuracy of the arctan calculation, I try to use more precise angle values (0-32768) which allows us perform additional iterations for the CORDIC algorithm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jouae, Please comment the above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ndsl7109256 could you provide how you use math.h to get the conclusion, along with a comparison between math.h and current twin_acos
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just replace twin_acos
with acos
in vector_angle
and check the rendering result.Besides, I evaluated the CORDIC algorithm's error for different iteration count(original and modified) by testing all integer pairs
Iteration | 12 | 15 |
---|---|---|
avg error | 0.071239 | 0.011101 |
std dev | 0.054116 | 0.008201 |
max error | 0.284898 | 0.043332 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found you can compute the angle between two vectors without any sqrt
operations.
Just modify vector_angle
function as:
twin_fixed_t dot = twin_fixed_mul(ux, vx) + twin_fixed_mul(uy, vy);
+ twin_fixed_t det = twin_fixed_mul(ux, vy) - twin_fixed_mul(uy, vx);
+ twin_fixed_t angle = twin_atan2(det, dot);
You can derive how to calculate the angle based on the following relationship
where
The advantage of this formula is that it avoids calculating the lengths of sqrt
operation.
However, this might not be a solution to the rendering problem. The issue is likely caused by insufficient precision, leading to rendering errors. Further detailed analysis is required to obtain a more accurate conclusion and potential solutions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uint8_t g; | ||
uint8_t b; | ||
uint8_t a; | ||
} tvg_rgba32_t; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typedef uint32_t twin_argb32_t;
Can we reuse the previous implementation? I'm uncertain if it's better to stick with the previous type by converting from float
to uint8_t
when the pixel format is float
.
return res; | ||
} | ||
res = tvg_read_unit(ctx, &out_header->line_width); | ||
if (res != TVG_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Within the function, it can check whether res
is TVG_SUCCESS
. If res
is not TVG_SUCCESS
, the function can return res
immediately. Otherwise, at the end of the function, it can return res
directly without checking whether res
is TVG_SUCCESS
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create a user-friendly file selection interface for TinyVG vector graphics using buttons, enabling seamless file picking. Conduct thorough validation of the TinyVG image processing capabilities to ensure the usability.
Then, we can explore potential contributions to established embedded graphics libraries like LVGL, which currently uses ThorVG for vector rendering. The goal is to develop a more efficient graphics solution that excels in resource efficiency and can operate effectively in environments without FPU support.
0137be5
to
8570e00
Compare
@@ -121,9 +124,9 @@ static twin_angle_t twin_atan2_first_quadrant(twin_fixed_t y, twin_fixed_t x) | |||
return TWIN_ANGLE_90; | |||
if (y == 0) | |||
return TWIN_ANGLE_0; | |||
twin_angle_t angle = TWIN_ANGLE_0; | |||
twin_angle_t angle = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not TWIN_ANGLE_0
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we use angle [0-32768] instead of [0-4096], I replaced TWIN_ANGLE_0
with 0
to distinguish them
/* CORDIC iteration */ | ||
for (int i = 0; i < 12; i++) { | ||
for (int i = 0; i < 15; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add comments for the considerations behind this iteration.
src/image-tvg.c
Outdated
} | ||
} | ||
twin_path_t *path = ctx->path; | ||
if (!path) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It checks whether the path
is NULL here. However, on line 946, it does not perform this check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this checking could be remove since we check path is NULL initially.
if (line_width == 0) { | ||
line_width = .01; | ||
} | ||
twin_path_t *path = ctx->path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it need to check whether the path is NULL
?
212b62d
to
cb60903
Compare
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 sysprog21#71
out_style->flat = flat; | ||
break; | ||
case TVG_STYLE_LINEAR: | ||
res = tvg_parse_gradient(ctx, &grad); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does line 532 require checking if res equals TVG_SUCCESS, while lines 538 and 542 do not?
Should a log_error be added if they require it?
static tvg_result_t tvg_parse_path(tvg_context_t *ctx, size_t size) | ||
{ | ||
tvg_result_t res = TVG_SUCCESS; | ||
tvg_point_t st, cur, pt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there are variables like st
, cur
, ctrl1
, ctrl2
and pt
, the name endp
is difficult to understand.
{ | ||
uint32_t u32; | ||
tvg_result_t res = tvg_read_varuint(ctx, &u32); | ||
if (res != TVG_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should log_error
be added here?
int kind, | ||
tvg_style_t *out_style) | ||
{ | ||
tvg_result_t res; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I cannot understand why res
will be checked initially in line 557, but res
will not be checked here?
uint32_t u32;
tvg_result_t res = tvg_read_varuint(ctx, &u32);
if (res != TVG_SUCCESS) {
return res;
}
{ | ||
float f32; | ||
tvg_result_t res = tvg_read_unit(ctx, &f32); | ||
if (res != TVG_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should log_error
be added here?
} | ||
out_point->x = f32; | ||
res = tvg_read_unit(ctx, &f32); | ||
if (res != TVG_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should log_error
be added here?
return TVG_E_INVALID_FORMAT; | ||
} | ||
ctx->colors = malloc(color_count * sizeof(twin_argb32_t)); | ||
if (ctx->colors == NULL) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!ctx->colors)
for consistency.
float line_width = 0.0f; | ||
if (TVG_PATH_CMD_HAS_LINE(path_info)) { | ||
res = tvg_read_unit(ctx, &line_width); | ||
if (res != TVG_SUCCESS) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've noticed the code below is repeated in several places. Should it be refactored into a function for easier maintenance?
if (res != TVG_SUCCESS) {
log_error("Failed to read point, error = [%d]", res);
goto error;
}
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 .
2024-12-09.3.20.24.mov
Validating with TinyVG examples (Left : Origin, Right : Rendered by Mado)
Tiger
Shield Icon
Flow Chart
Folder Icon
Comic
FlowChart
Ref:
https://tinyvg.tech/download/specification.pdf
Close #71