Coder Social home page Coder Social logo

thorvg / thorvg Goto Github PK

View Code? Open in Web Editor NEW
548.0 26.0 86.0 370.13 MB

Thor Vector Graphics is a lightweight portable library used for drawing vector-based scenes and animations including SVG and Lottie. It can be freely utilized across various software platforms and applications to visualize graphical contents.

Home Page: https://www.thorvg.org

License: MIT License

Meson 0.48% C++ 90.11% C 8.67% Shell 0.01% Python 0.03% JavaScript 0.06% HTML 0.27% TypeScript 0.36%
drawing-library shapes svg path-drawing image animation vector-graphics-engine png jpeg tvg

thorvg's Introduction

Discord ThorVGPT OpenCollective License BinarySize CodeFactor
Build Ubuntu Build Windows Build MacOS Build iOS Build Android

ThorVG

ThorVG is an open-source graphics library designed for creating vector-based scenes and animations. Embracing the philosophy of "Simpler is better," the ThorVG project offers intuitive and user-friendly interfaces, all the while maintaining a compact size and minimal software complexity.

The following list shows primitives that are supported by ThorVG:

  • Shapes: Line, Arc, Curve, Path, Polygon
  • Filling: Solid Color, Linear & Radial Gradients and Texture Mapping
  • Stroking: Width, Join, Cap, Dash Patterns
  • Scene Graph & Transformations
  • Composition: Blending, Masking, Path Clipping
  • Text: Unicode Characters and Horizontal Text Layout using the Scalable Fonts (TTF)
  • Images: TVG, SVG, JPG, PNG, WebP, Raw Bitmap
  • Animations: Lottie

​ThorVG is designed for a wide range of programs, offering adaptability for integration and use in various applications and systems. It achieves this through a single binary with selectively buildable, modular components in a building block style. This ensures both optimal size and easy maintanence.

If your program includes the main renderer, you can seamlessly utilize ThorVG APIs by transitioning drawing contexts between the main renderer and ThorVG. Throughout these API calls, ThorVG effectively serializes drawing commands among volatile paint nodes. Subsequently, it undertakes synchronous or asynchronous rendering via its backend raster engines.

ThorVG is adept at handling vector images, including formats like SVG, and it remains adaptable for accommodating additional popular formats as needed. In the rendering process, the library may generate intermediate frame buffers for scene compositing, though only when essential. The accompanying diagram provides a concise overview of how to effectively incorporate ThorVG within your system.

ThorVG incorporates a threading mechanism that aims to seamlessly acquire subsequent scenes without unnecessary delays. It operates using a finely-tuned task scheduler based on thread pools, encompassing various tasks such as encoding, decoding, updating, and rendering. This design ensures that all tasks can effectively leverage multi-processing capabilities.

The task scheduler has been meticulously crafted to conceal complexity, streamline integration, and enhance user convenience. Therefore, the policy it employs is optional, allowing users to select it based on their specific requirements.

Contents


Installation

This section details the steps required to configure the environment for installing ThorVG.

Build and Install

ThorVG supports meson build system. Install meson and ninja if you don't have them already.

Run meson to configure ThorVG in the thorvg root folder.

meson setup builddir

Run ninja to build & install ThorVG:

ninja -C builddir install

Regardless of the installation, all build results (symbols, executable) are generated in the builddir folder in thorvg. Some results such as examples won't be installed, you can check More examples section to see how to change it.

Note that some systems might include ThorVG package as a default component. In that case, you can skip this manual installation.

Build with Visual Studio

If you want to create Visual Studio project files, use the command --backend=vs. The resulting solution file (thorvg.sln) will be located in the build folder.

meson setup builddir --backend=vs

Install with vcpkg

You can download and install pre-packaged ThorVG using the vcpkg package manager.

Clone the vcpkg repo. Make sure you are in the directory you want the tool installed to before doing this.

git clone https://github.com/Microsoft/vcpkg.git

Run the bootstrap script to build the vcpkg.

./bootstrap-vcpkg.sh

Install the ThorVG package.

./vcpkg install thorvg

Install with MSYS2

You can download and install pre-packaged ThorVG using the MSYS2 package manager.

Download and execute the MSYS2 installer on the web page above and follow the steps. When done, just launch one of the terminals in the start menu, according to the architecture and compiler you want (either 32 or 64 bits, with MSVCRT or UCRT library). Then you can install the ThorVG package :

pacman -S thorvg

To update to a newer release (and update all the packages, which is preferable), run :

pacman -Syu

Back to contents

Quick Start

ThorVG renders vector shapes to a given canvas buffer. The following is a quick start to show you how to use the essential APIs.

First, you should initialize the ThorVG engine:

tvg::Initializer::init(0);   //thread count

Then it would be best if you prepared an empty canvas for drawing on it:

static uint32_t buffer[WIDTH * HEIGHT];                                 //canvas target buffer

auto canvas = tvg::SwCanvas::gen();                                     //generate a canvas
canvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888);  //buffer, stride, w, h, Colorspace

Next you can draw multiple shapes on the canvas:

auto rect = tvg::Shape::gen();               //generate a shape
rect->appendRect(50, 50, 200, 200, 20, 20);  //define it as a rounded rectangle (x, y, w, h, rx, ry)
rect->fill(100, 100, 100);                   //set its color (r, g, b)
canvas->push(move(rect));                    //push the rectangle into the canvas

auto circle = tvg::Shape::gen();             //generate a shape
circle->appendCircle(400, 400, 100, 100);    //define it as a circle (cx, cy, rx, ry)

auto fill = tvg::RadialGradient::gen();      //generate a radial gradient
fill->radial(400, 400, 150);                 //set the radial gradient geometry info (cx, cy, radius)

tvg::Fill::ColorStop colorStops[2];          //gradient colors
colorStops[0] = {0.0, 255, 255, 255, 255};   //1st color values (offset, r, g, b, a)
colorStops[1] = {1.0, 0, 0, 0, 255};         //2nd color values (offset, r, g, b, a)
fill->colorStops(colorStops, 2);             //set the gradient colors info

circle->fill(move(fill));                    //set the circle fill
canvas->push(move(circle));                  //push the circle into the canvas

This code generates the following result:

You can also draw you own shapes and use dashed stroking:

auto path = tvg::Shape::gen();               //generate a path
path->moveTo(199, 34);                       //set sequential path coordinates
path->lineTo(253, 143);
path->lineTo(374, 160);
path->lineTo(287, 244);
path->lineTo(307, 365);
path->lineTo(199, 309);
path->lineTo(97, 365);
path->lineTo(112, 245);
path->lineTo(26, 161);
path->lineTo(146, 143);
path->close();

path->fill(150, 150, 255);                   //path color

path->strokeWidth(3);                        //stroke width
path->strokeFill(0, 0, 255);                 //stroke color
path->strokeJoin(tvg::StrokeJoin::Round);    //stroke join style
path->strokeCap(tvg::StrokeCap::Round);      //stroke cap style

float pattern[2] = {10, 10};                 //stroke dash pattern (line, gap)
path->strokeDash(pattern, 2);                //set the stroke pattern

canvas->push(move(path));                    //push the path into the canvas

The code generates the following result:

Now begin rendering & finish it at a particular time:

canvas->draw();
canvas->sync();

Then you can acquire the rendered image from the buffer memory.

Lastly, terminate the engine after its usage:

tvg::Initializer::term();

Back to contents

SVG

ThorVG facilitates SVG Tiny Specification rendering via its dedicated SVG interpreter. Adhering to the SVG Tiny Specification, the implementation maintains a lightweight profile, rendering it particularly advantageous for embedded systems. While ThorVG comprehensively adheres to most of the SVG Tiny specs, certain features remain unsupported within the current framework. These include:

  • Animation
  • Fonts & Text
  • Interactivity
  • Multimedia

The following code snippet shows how to draw SVG image using ThorVG:

auto picture = tvg::Picture::gen();         //generate a picture
picture->load("tiger.svg");                 //load a SVG file
canvas->push(move(picture));                //push the picture into the canvas

The result is:

Back to contents

Lottie

ThorVG aims to fully support Lottie Animation features. Lottie is a JSON-based vector animation file format that enables seamless distribution of animations on any platform, akin to shipping static assets. These files are compact and compatible with various devices, scaling up or down without pixelation. With Lottie, you can easily create, edit, test, collaborate, and distribute animations in a user-friendly manner. For more information, please visit LottieFiles' website.

Currently, ThorVG supports Lottie animations. Although most features are supported, some advanced properties of Lottie may not be available yet:

  • Shape Modifiers
  • Layer Effects
  • Expressions

The following code snippet demonstrates how to use ThorVG to play a Lottie animation.

auto animation = tvg::Animation::gen();     //generate an animation
auto picture = animation->picture()         //acquire a picture which associated with the animation.
picture->load("lottie.json");               //load a Lottie file
auto duration = animation->duration();      //figure out the animation duration time in seconds.
canvas->push(tvg::cast(picture));           //push the picture into the canvas

First, an animation and a picture are generated. The Lottie file (lottie.json) is loaded into the picture, and then the picture is added to the canvas. The animation frames are controlled using the animation object to play the Lottie animation. Also you might want to know the animation duration time to run your animation loop.

animation->frame(animation->totalFrame() * progress);  //Set a current animation frame to display
canvas->update(animation->picture());                  //Update the picture to be redrawn.

Let's suppose the progress variable determines the position of the animation, ranging from 0 to 1 based on the total duration time of the animation. Adjusting the progress value allows you to control the animation at the desired position. Afterwards, the canvas is updated to redraw the picture with the updated animation frame.

Back to contents

TVG Picture

ThorVG introduces the dedicated vector data format, known as TVG Picture, designed to efficiently store Paint node properties within a scene in binary form. This format is meticulously optimized in advance, ensuring compact file sizes and swift data loading processes.

To leverage the TVG Picture format, ThorVG employs a specialized module called TVG Saver. This module is responsible for optimizing the data associated with all scene-tree nodes and storing them in binary form. During the optimization phase, TVG Saver intelligently eliminates unused information, eliminates duplicated properties, consolidates overlapping shapes, and employs data compression where feasible. Remarkably, these optimizations maintain compatibility with future versions of ThorVG libraries, with data compression utilizing the Lempel-Ziv-Welchi algorithm when applicable.

As a result of these efforts, the final data size is notably smaller than other text-based vector data formats, such as SVG. This reduction in data size not only minimizes I/O operations but also mitigates memory bandwidth requirements during data loading. This aspect proves particularly beneficial for programs reliant on substantial vector resources.

Furthermore, TVG Picture substantially streamlines resource loading tasks by circumventing the need for data interpretation, resulting in reduced runtime memory demands and rendering tasks that subsequently enhance performance.

By adopting TVG Picture, you can achieve an average reduction of over 30% in data size and loading times (for more details, refer to "See More"). Notably, the extent of performance improvement is contingent on resource size and complexity.

As TVG Saver facilitates the export of the scene-tree into TVG Picture data files (TVG), the subsequent task of importing and restoring this data to programmable instances is efficiently handled by the TVG Loader. For seamless conversion from SVG to TVG, the ThorVG Viewer provides a swift solution.

Back to contents

In Practice

dotLottie

dotLottie is an open-source file format that aggregates one or more Lottie files and their associated resources, such as images and fonts, into a single file. This enables an efficient and easy distribution of animations. dotLottie files are ZIP archives compressed with the Deflate compression method and carry the file extension of “.lottie”. Think of it as a superset of Lottie. LottieFiles aims to achieve just that. dotLottie player by LottieFiles is now powered by ThorVG.

Godot

ThorVG has been integrated into the Godot project to enable the creation of sleek and visually appealing user interfaces (UIs) and vector resources in the Godot game engine. Godot is a modern game engine that is both free and open-source, offering a comprehensive range of tools. With Godot, you can concentrate on developing your game without the need to recreate existing functionalities.

LVGL

LVGL is the most popular free and open-source embedded graphics library to create beautiful UIs for any MCU, MPU and display type. The complete graphic framework includes a variety of widgets for you to use in the creation of your GUI, and supports more advanced functions such as animations and anti-aliasing. ThorVG serves as the vector drawing primitives library in the LVGL framework.

Tizen

ThorVG has been integrated into the Tizen platform as the vector graphics engine. NUI is the name of Tizen UI framework which is written in C#. ThorVG is the backend engine of the NUI Vector Graphics which is used for vector primitive drawings and scalable image contents such as SVG and Lottie Animation among the Tizen applications.

Back to contents

Examples

here are plenty of sample code in thorvg/src/examples to help you in understanding the ThorVG APIs.

To execute these examples, you can build them with the following meson build option:

meson setup builddir -Dexamples=true

Note that these examples require the EFL dev package for launching. If you're using Linux-based OS, you can easily install this package from your OS distribution server. For Ubuntu, you can install it with this command.

apt-get install libefl-all-dev

Alternatively, you can download the package here for Windows. For more information, please visit the official EFL page.

Back to contents

Documentation

The ThorVG API documentation can be accessed at thorvg.org/apis, and is also available in the C++ API, C API within this repository.

Back to contents

Tools

ThorVG Viewer

ThorVG provides the resource verification tool for the ThorVG Engine. ThorVG viewer does immediate rendering via web browser running on the ThorVG web-assembly binary, allowing real-time editing of the vector elements on it. It doesn't upload your resources to any external server while allowing to export to supported formats such as TVG, so the designer resource copyright is protected.

Lottie to GIF

ThorVG provides an executable lottie2gif converter that generates a GIF file from a Lottie file.

To use the lottie2gif, you must turn on this feature in the build option:

meson setup builddir -Dtools=lottie2gif -Dsavers=gif

To use the 'lottie2gif' converter, you need to provide the 'Lottie files' parameter. This parameter can be a file name with the '.json' extension or a directory name. It also accepts multiple files or directories separated by spaces. If a directory is specified, the converter will search for files with the '.json' extension within that directory and all its subdirectories.

Optionally, you can specify the image resolution in the 'WxH' format, with two numbers separated by an 'x' sign, following the '-r' flag.

Both flags, if provided, are applied to all of the .json files.

The usage examples of the lottie2gif:

Usage:
    lottie2gif [Lottie file] or [Lottie folder] [-r resolution] [-f fps] [-b background color]

Flags:
    -r set the output image resolution.
    -f specifies the frames per second (fps) for the generated animation.
    -b specifies the base background color (RGB in hex). If not specified, the background color will follow the original content.

Examples:
    $ lottie2gif input.json
    $ lottie2gif input.json -f 30
    $ lottie2gif input.json -r 600x600 -f 30
    $ lottie2gif lottiefolder
    $ lottie2gif lottiefolder -r 600x600
    $ lottie2gif lottiefolder -r 600x600 -f 30 -b fa7410

SVG to PNG

ThorVG provides an executable svg2png converter that generates a PNG file from an SVG file.

To use the svg2png, you must turn on this feature in the build option:

meson setup builddir -Dtools=svg2png

To use the 'svg2png' converter, you need to provide the 'SVG files' parameter. This parameter can be a file name with the '.svg' extension or a directory name. It also accepts multiple files or directories separated by spaces. If a directory is specified, the converter will search for files with the '.svg' extension within that directory and all its subdirectories.

Optionally, you can specify the image resolution in the 'WxH' format, with two numbers separated by an 'x' sign, following the '-r' flag.

The background color can be set with the -b flag. The bgColor parameter should be passed as a three-bytes hexadecimal value in the ffffff format. The default background is transparent.

Both flags, if provided, are applied to all of the .svg files.

The usage examples of the svg2png:

Usage:
    svg2png [SVG files] [-r resolution] [-b bgColor]

Flags:
    -r set the output image resolution.
    -b set the output image background color.

Examples:
    $ svg2png input.svg
    $ svg2png input.svg -r 200x200
    $ svg2png input.svg -r 200x200 -b ff00ff
    $ svg2png input1.svg input2.svg -r 200x200 -b ff00ff
    $ svg2png . -r 200x200

SVG to TVG

ThorVG provides an executable svg2tvg converter that generates a TVG file from an SVG file.

To use svg2tvg, you need to activate this feature in the build option:

meson setup builddir -Dtools=svg2tvg -Dsavers=tvg

Examples of the usage of the svg2tvg:

Usage:
   svg2tvg [SVG file] or [SVG folder]

Examples:
    $ svg2tvg input.svg
    $ svg2tvg svgfolder

Back to contents

API Bindings

Our main development APIs are written in C++, but ThorVG also provides API bindings for C.

To enable CAPI binding, you need to activate this feature in the build options:

meson setup builddir -Dbindings="capi"

Back to contents

Dependencies

ThorVG offers versatile support for image loading, accommodating both static and external loaders. This flexibility ensures that, even in environments without external libraries, users can still leverage static loaders as a reliable alternative. At its foundation, the ThorVG core library is engineered to function autonomously, free from external dependencies. However, it is important to note that ThorVG also encompasses a range of optional feature extensions, each with its specific set of dependencies. The dependencies associated with these selective features are outlined as follows:

Back to contents

Contributors

ThorVG stands as a purely open-source initiatives. We are grateful to the individuals, organizations, and companies that have contributed to the development of the ThorVG project. The dedicated efforts of the individuals and entities listed below have enabled ThorVG to reach its current state.

Back to contents

Communication

For real-time conversations and discussions, please join us on Discord

Back to contents

thorvg's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

thorvg's Issues

In SVG, dasharray is not displayed when dashes and gap are the same.

image
(second line)

<svg viewBox="0 0 30 10" xmlns="http://www.w3.org/2000/svg">
  <!-- No dashes nor gaps -->
  <line x1="0" y1="1" x2="30" y2="1" stroke="black" />
 
  <!-- Dashes and gaps of the same size -->
  <line x1="0" y1="3" x2="30" y2="3" stroke="black"
          stroke-dasharray="4" />
 
</svg>

Support Fill Rule

Current Fill doesn't support fill option, it uses winding behavior in default.
We need to provide new api & enum values for fill method.

ex)
enum class FillRule { Winding = 0, EventOdd };
Result Fill::rule(FillRule rule) noexcept;

Support GL Engine

We can provide decent GL backend rasterizer for optimal performance
So that users can choose either or both raster canvases by their demand.

Need ignore list for svg unsupported feature.

Does this necessary to print?

SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:inkscape]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:rdf]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:cc]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:dc]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:sodipodi]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: xmlns:ns1]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: id]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: sodipodi:docname]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: version]
SVG: Unsupported attributes used [Elements type: Doc][Attribute: inkscape:version]

If so, what user supposed to do?

ClipPath Runtime Error Cases

The following cases are runtime error cases with the clip path

  1. clip path is pushed
    auto star3 = tvg::Shape::gen().release();

    star3->moveTo(199, 34);
    star3->lineTo(253, 143);
    star3->lineTo(374, 160);
    star3->lineTo(287, 244);
    star3->lineTo(307, 365);
    star3->lineTo(199, 309);
    star3->lineTo(97, 365);
    star3->lineTo(112, 245);
    star3->lineTo(26, 161);
    star3->lineTo(146, 143);
    star3->close();

    star3->translate(400, 0);
    star3->fill(255, 255, 0, 255);
    star3->stroke(255 ,0, 0, 128);
    star3->stroke(10);

    auto clipRect = tvg::Shape::gen().release();
    clipRect->appendRect(480, 110, 200, 200, 0, 0);
    clipRect->fill(255, 0, 0, 128);
    clipRect->translate(20, 20);
    canvas->push(std::unique_ptr<tvg::Shape>(clipRect));

    star3->composite(std::unique_ptr<tvg::Shape>(clipRect), tvg::CompositeMethod::ClipPath);
    canvas->push(std::unique_ptr<tvg::Shape>(star3));
  1. clip the multiple shapes with the same clip path
    ...
    auto clipRect = tvg::Shape::gen().release();
    clipRect->appendRect(480, 110, 200, 200, 0, 0);
    clipRect->fill(255, 0, 0, 128);
    clipRect->translate(20, 20);

    star3->composite(std::unique_ptr<tvg::Shape>(clipRect), tvg::CompositeMethod::ClipPath);
    star4->composite(std::unique_ptr<tvg::Shape>(clipRect), tvg::CompositeMethod::ClipPath);
    canvas->push(std::unique_ptr<tvg::Shape>(star3));
    canvas->push(std::unique_ptr<tvg::Shape>(star4));

Picture needs to support resizing method.

Svg has a preserveAspectRatio option.
User might need to resize picture based on this option.
What is the best interface for this?

  1. picture->viewbox(0, 0, w, h);
  2. picture->size(w, h);
  3. picture->transform(?) + return picture->aspectRatio();?

Opacity duplicate issue of "fill-opacity" and "opacity" (SVG)

In SVG
The fill-opacity attribute only applies to fil.
The opaicty attribute is applied to fill and stroke.
In tvg, Alpha of shape and Alpha of stroke are applied respectively.

In SVG, fill-opacity 0.5 is
shape->fill(,,, 255*0.5)

But
opacity 0.5 is
shape->fill(,,, 2550.5)
shape->stroke(,,, 255
0.5)

It goes like this.
image

(testShape.cpp)

void tvgDrawCmds(tvg::Canvas* canvas)
{
    if (!canvas) return;

    //Prepare a Shape (Rectangle + Rectangle + Circle + Circle)
    auto shape1 = tvg::Shape::gen();
    shape1->appendRect(0, 0, 200, 200, 0, 0);          //x, y, w, h, rx, ry      
    shape1->appendRect(100, 100, 300, 300, 100, 100);  //x, y, w, h, rx, ry
    shape1->appendCircle(400, 400, 100, 100);          //cx, cy, radiusW, radiusH
    shape1->appendCircle(400, 500, 170, 100);          //cx, cy, radiusW, radiusH
    shape1->fill(255, 255, 0, 128);                    //r, g, b, a            
    shape1->stroke(255, 0, 0, 128);       //color: r, g, b, a
    shape1->stroke(40);                       //width: 10px

    canvas->push(move(shape1));
}   

But the result we want is

<!-- Learn about this code on MDN: https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill-opacity -->

<svg viewBox="0 0 400 100" xmlns="http://www.w3.org/2000/svg">

  <!-- Fill opacity as a number -->
  <circle cx="150" cy="50" r="40"
          opacity="0.5" fill-opacity="0.5" stroke="#FF0000" stroke-width="20"/>

</svg>

image

Introduce Paint Opacity method

For better flexible usage, I'm considering to separate alpha from color like this:

  • Paint::opacity(a);
  • Shape::fill(r, g, b, a) - > Shape::color(r, g, b);
  • Shape::stroke(r, g, b, a) -> Shape::stroke(r, g, b);

In this case, user could toggle on/off of paint by opacity change (255 <-> 0)

Also, it's easier to change scene opacity by this
scene->opacity(127);

Related Issue:
#38

Support Logging method

ThorVG requires an abstract (glue) layer to attach logging method, for convenient debugging.
These logging method could depend on systems (fprintf, dlog, etc), our engine must have modular design here for easy integration.

Support Masking Method

There is a requirement to apply vector object as masking source.

ex)
auto maskSource; //This paint is used for masking source
auto maskTarget; //This paint is used for masking target

maskTarget->composite(maskSource, AlphaBlend ); //Now, maskTarget can be masked(or clipped) by maskSource.

TaskScheduler Optimization

Current TaskScheduler uses c++ promise&future which are allocates a lot of memory during frames.

tvgTaskScheduler.h:

struct Task
promise sender;
future receiver;
...

We can consider to apply own synchronization mechanism by using mutex locks.

Crash in _rasterSolidRle and _rasterTranslucentRle API

0x00007ffff74d3595 in _rasterSolidRle (surface=0x555555610c00, rle=0x7fffdc001040, color=4294836224) at ../src/lib/sw_engine/tvgSwRaster.cpp:252
252	                dst[i] = src + ALPHA_BLEND(dst[i], ialpha);
(gdb) bt
#0  0x00007ffff74d3595 in _rasterSolidRle (surface=0x555555610c00, rle=0x7fffdc001040, color=4294836224) at ../src/lib/sw_engine/tvgSwRaster.cpp:252
#1  0x00007ffff74d47d5 in rasterStroke (surface=0x555555610c00, shape=0x5555555df680, r=254 '\376', g=0 '\000', b=0 '\000', a=255 '\377') at ../src/lib/sw_engine/tvgSwRaster.cpp:481
#2  0x00007ffff74d53bf in tvg::SwRenderer::render (this=0x55555562acd0, shape=..., data=0x5555555df5e0) at ../src/lib/sw_engine/tvgSwRenderer.cpp:391
#3  0x00007ffff74c9e77 in tvg::Shape::Impl::render (this=0x5555555de7d0, renderer=...) at ../src/lib/tvgShapeImpl.h:223
#4  0x00007ffff74cac5b in tvg::PaintMethod<tvg::Shape::Impl>::render (this=0x55555562fab0, renderer=...) at ../src/lib/tvgPaint.h:225
#5  0x00007ffff74bef9e in tvg::Paint::Impl::render (this=0x55555562fa80, renderer=...) at ../src/lib/tvgPaint.h:169
#6  0x00007ffff74c719c in tvg::Scene::Impl::render (this=0x55555562d690, renderer=...) at ../src/lib/tvgSceneImpl.h:81
#7  0x00007ffff74c7baf in tvg::PaintMethod<tvg::Scene::Impl>::render (this=0x55555562d6c0, renderer=...) at ../src/lib/tvgPaint.h:225
#8  0x00007ffff74bef9e in tvg::Paint::Impl::render (this=0x55555562d660, renderer=...) at ../src/lib/tvgPaint.h:169
#9  0x00007ffff74bf49f in tvg::Canvas::Impl::draw (this=0x55555562ad00) at ../src/lib/tvgCanvasImpl.h:101
#10 0x00007ffff74beb30 in tvg::Canvas::draw (this=0x55555562acb0) at ../src/lib/tvgCanvas.cpp:60
#11 0x00007ffff74ec5d2 in tvg_canvas_draw (canvas=0x55555562acb0) at ../src/bindings/capi/tvgCapi.cpp:115
#12 0x00007ffff7e4d569 in _render_to_buffer_tvg (obj=0x555555627830, pd=0x555555627950, root=0x400000008328, w=200, h=94) at ../src/lib/evas/canvas/efl_canvas_vg_object.c:463
#13 0x00007ffff7e4dad4 in _efl_canvas_vg_object_render (eo_obj=0x400000007725, obj=0x555555627830, type_private_data=0x555555627950, engine=0x555555610a10, output=0x5555556136e0, 
    context=0x555555631440, surface=0x555555634040, x=0, y=0, do_async=1 '\001') at ../src/lib/evas/canvas/efl_canvas_vg_object.c:933
#14 0x00007ffff7e074e9 in evas_render_mapped (evas=0x555555608d50, eo_obj=0x400000007725, obj=0x555555627830, context=0x555555613610, output=0x5555556136e0, surface=0x555555634040, 
    off_x=0, off_y=0, mapped=0, ecx=0, ecy=0, ecw=200, ech=94, proxy_render_data=0x0, level=3, do_async=1 '\001') at ../src/lib/evas/canvas/evas_render.c:2290
#15 0x00007ffff7e0acb2 in evas_render_updates_internal_loop (eo_e=0x400000003715, evas=0x555555608d50, output=0x5555556136e0, surface=0x555555634040, context=0x555555613610, top=0x0, 
    ux=0, uy=0, uw=200, uh=94, cx=0, cy=0, cw=200, ch=94, fx=0, fy=0, skip_cutouts=0 '\000', cutout_margin=0x0, alpha=0 '\000', do_async=1 '\001', offset=0x7fffffffd58c, level=0)
    at ../src/lib/evas/canvas/evas_render.c:3145
#16 0x00007ffff7e0cbc7 in evas_render_updates_internal (eo_e=0x400000003715, make_updates=1 '\001', do_draw=1 '\001', do_async=1 '\001') at ../src/lib/evas/canvas/evas_render.c:3618
#17 0x00007ffff7e0f0b2 in _evas_canvas_render_async (eo_e=0x400000003715, e=0x555555608d50) at ../src/lib/evas/canvas/evas_render.c:4081
#18 0x00007ffff7d6292d in evas_canvas_render_async (obj=0x400000003715) at ../src/lib/evas/canvas/evas_canvas_eo.c:168
#19 0x00007ffff7d65d45 in evas_render_async (obj=0x400000003715) at ../src/lib/evas/canvas/evas_canvas_eo.legacy.c:179
#20 0x00007fffecc7da3d in _ecore_evas_x_render (ee=0x555555601030) at ../src/modules/ecore_evas/engines/x/ecore_evas_x.c:765
#21 0x00007ffff7f9d61b in _ecore_evas_idle_enter (data=0x0) at ../src/lib/ecore_evas/ecore_evas.c:295
#22 0x00007ffff7bb67df in _ecore_call_task_cb (func=0x7ffff7f9d418 <_ecore_evas_idle_enter>, data=0x0) at ../src/lib/ecore/ecore_private.h:456
#23 0x00007ffff7bb684f in _ecore_factorized_idle_process (data=0x5555555a9d20, event=0x7fffffffd910) at ../src/lib/ecore/ecore_idler.c:35
#24 0x00007ffff78a8f24 in _event_callback_call (obj_id=0x400000000308, pd=0x555555599880, desc=0x7ffff7c410a0 <_EFL_LOOP_EVENT_IDLE_ENTER>, event_info=0x0, legacy_compare=0 '\000')
    at ../src/lib/eo/eo_base_class.c:2113
#25 0x00007ffff78a9135 in _efl_object_event_callback_call (obj_id=0x400000000308, pd=0x555555599880, desc=0x7ffff7c410a0 <_EFL_LOOP_EVENT_IDLE_ENTER>, event_info=0x0)
    at ../src/lib/eo/eo_base_class.c:2185
#26 0x00007ffff78a91f2 in efl_event_callback_call (obj=0x400000000308, desc=0x7ffff7c410a0 <_EFL_LOOP_EVENT_IDLE_ENTER>, event_info=0x0) at ../src/lib/eo/eo_base_class.c:2188
#27 0x00007ffff7bbb709 in _ecore_main_loop_iterate_internal (obj=0x400000000308, pd=0x5555555998e0, once_only=0) at ../src/lib/ecore/ecore_main.c:2432
#28 0x00007ffff7bb8ba6 in _ecore_main_loop_begin (obj=0x400000000308, pd=0x5555555998e0) at ../src/lib/ecore/ecore_main.c:1218
#29 0x00007ffff7bc0eb2 in _efl_loop_begin (obj=0x400000000308, pd=0x5555555998e0) at ../src/lib/ecore/efl_loop.c:57
#30 0x00007ffff7bc346a in efl_loop_begin (obj=0x400000000308) at src/lib/ecore/efl_loop.eo.c:28
#31 0x00007ffff7bb8d74 in ecore_main_loop_begin () at ../src/lib/ecore/ecore_main.c:1303
#32 0x000055555555679e in main () at ../src/examples/evas/evas-vg-circles.c:96

Stroke wrong display

test code

--- a/src/examples/Opacity.cpp
+++ b/src/examples/Opacity.cpp
@@ -52,6 +52,9 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape3->cubicTo(cx - halfRadius, cy + radius, cx - radius, cy + halfRadius, cx - radius, cy);
     shape3->cubicTo(cx - radius, cy - halfRadius, cx - halfRadius, cy - radius, cx, cy - radius);
     shape3->fill(255, 0, 0, 255);
+
+    shape3->stroke(100);
+    shape3->stroke(255, 0, 0, 255);
     scene->push(move(shape3));

image

There is a problem with the top of red circle.

Floats comparison

fabs(a-b) < FLT_EPSILON
does not work very well for 'a' and 'b' being floats

How to clear current canvas

Hello.
I am using following changes to clear current canvas.
It is calling swCanvas->clear/draw/sync, but it seems that it is not working.

diff --git a/test/testCommon.h b/test/testCommon.h
index 5dd70cd..926d5f9 100644
--- a/test/testCommon.h
+++ b/test/testCommon.h
@@ -14,12 +14,22 @@ using namespace std;

void tvgSwTest(uint32_t* buffer);
void drawSwView(void* data, Eo* obj);
+void tvgSwClearTest(void);

void win_del(void *data, Evas_Object *o, void *ev)
{
elm_exit();
}

+static void
+mouse_down_cb(void *data EINA_UNUSED,

  •          Evas *e EINA_UNUSED,
    
  •          Evas_Object *o,
    
  •          void *event_info)
    

+{

  • tvgSwClearTest();
    +}

static Eo* createSwView()
{
static uint32_t buffer[WIDTH * HEIGHT];
@@ -36,6 +46,8 @@ static Eo* createSwView()
evas_object_size_hint_weight_set(view, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(view);

  • evas_object_event_callback_add(view, EVAS_CALLBACK_MOUSE_DOWN, mouse_down_cb, NULL);
  • elm_win_resize_object_add(win, view);
    evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT);
    evas_object_show(win);
    diff --git a/test/testSvg2.cpp b/test/testSvg2.cpp
    index c859b04..6cb49e2 100644
    --- a/test/testSvg2.cpp
    +++ b/test/testSvg2.cpp
    @@ -63,6 +63,13 @@ void tvgSwTest(uint32_t* buffer)
    Canvas keeps this shape node unless user call canvas->clear() */
    tvgDrawCmds(swCanvas.get());
    }
    +void tvgSwClearTest(void)
    +{
  • swCanvas->clear();
  • if (swCanvas->draw() == tvg::Result::Success) {
  •    swCanvas->sync();
    
  • }
    +}

void drawSwView(void* data, Eo* obj)
{

Support ClipTo property in SVG

We missed to implement clipPath feature in engine side and svg parser.

<svg viewBox="0 0 100 100"> <clipPath id="myClip"> <!-- Everything outside the circle will be clipped and therefore invisible. --> <circle cx="40" cy="35" r="35" /> </clipPath>

This can be accomplished with this interface.

auto shape = tvg::Shape::gen();
...
auto paint = tvg::Shape::gen();
...
paint->composite(shape, ClipTo);

Composition surface not stretched by (stroke-width * transform)

image

Test Code (src/example/Opacity.cpp)

diff --git a/src/examples/Opacity.cpp b/src/examples/Opacity.cpp
index 53a2bab..33e1a25 100644
--- a/src/examples/Opacity.cpp
+++ b/src/examples/Opacity.cpp
@@ -44,9 +44,9 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     //Circle
     auto shape3 = tvg::Shape::gen();
 
-    auto cx = 550.0f;
-    auto cy = 550.0f;
-    auto radius = 125.0f;
+    auto cx = 150.0f;
+    auto cy = 150.0f;
+    auto radius = 50.0f;
     auto halfRadius = radius * 0.552284f;
 
     //Append Paths
@@ -59,6 +59,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     shape3->stroke(10);
     shape3->stroke(0, 0, 255, 255);
     shape3->opacity(200);
+    shape3->scale(3);
     scene->push(move(shape3));

When Transform is applied, the size of the surface does not increase sufficiently.

Documentation for svg2png

Describe how to use svg2png function in thorvg in README.

  1. how to enable & execute it with examples.

Please add one section "SVG to PNG" after "Quick Start"

AVX Optimization for Sw Engine

Still there are a lot of rasterzing parts, not have SIMD operation.
We need a better fine-tuned software raster engine.

We can consider to apply AVX to some rasterizing methods in tvgSwRaster.cpp

such as:

_translucentRect()
_translucentRectAlphaMask()
_translucentRectInvAlphaMask()
_rasterTranslucentRect()
...
_rasterRadialGradientRle()

Some might not fit to SIMD (this case we can skip to apply) but Some would be nicer than basic.

  • Submitting individual patches for each methods will be better.

Optimization Image Raster

Image rasterization still unnecessary transform pixels.
We can avoid this precisely if check the transform matrix

for example, transform has only translation, we can just shift image origin position without transform.

see OPTIMIZE ME comments in tvgSwRaster.cpp rasterImage()

Implement API TCT (Unit-Test Suite)

We support Unit Tests using catch2 framework

See thorvg Unit Tests
#409

I suggest to separate tasks.

C++:
Initializer (o) / Paint / Canvas (o) / SwCanvas (o) / Shape (o) / Picture (o) / Fill / RadialGradient / LinearGradient => @hermet
Scene (o) => @JSUYA

CAPI:
please make a sub-folder in test (like thorvg/test/capi)
Initializer (o) / Paint (o) / SwCanvas (o) / Shape (o) => @mmaciola
Fill (o) / RadialGradient (o) / LinearGradient (o) => @mihashco
Picture (o) => @hermet
Scene => @jykeon

Threading Optimization for Sw Engine

There is still a point to optimize for SW rasterization.
We need to figure out any spinning section among threads and fit them up to reduce the cpu idle time.

Shape Stroke needs to support Gradient Fill

Current Shape stroke feature only allows the solid color, we need to extend it to support gradient fill for stroke.
ex) Result Shape::stroke(std::unique_ptr f) noexcept;

Consider stroking rendering re-use gradient fill which is applied to shape rendering (in sw_engine)

Fix memory violation issues

  1. Examples/Capi:
    ==13002==
    ==13002== 292 (40 direct, 252 indirect) bytes in 1 blocks are definitely lost in loss record 418 of 457
    ==13002== at 0x4C3217F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==13002== by 0x504EDF5: tvg::Paint::Paint() (tvgPaint.cpp:28)
    ==13002== by 0x5050443: tvg::Shape::Shape() (tvgShape.cpp:34)
    ==13002== by 0x50504F5: tvg::Shape::gen() (tvgShape.cpp:48)
    ==13002== by 0x5060DF0: tvg_shape_new (tvgCapi.cpp:193)
    ==13002== by 0x109F33: testCapi() (Capi.cpp:143)
    ==13002== by 0x109876: main (Capi.cpp:207)
    ==13002==

Implement Scene & Picture Duplicate() Method

It's necessary to copy paint nodes by interface. This would be helpful for users to retain data in some scenario.

ex)
std::unique_ptr Shape::copy() const noexcept;
std::unique_ptr Scene::copy() const noexcept;

unique_ptr copied = scene->copy();
unique_ptr copied = shape->copy();

Support for applying the r value of radial gradient relative to the width and height

<?xml version="1.0" encoding="UTF-8"?>
<svg width="1000px" height="100px" viewBox="0 0 1000 100" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
    <title>ime_bg_input_auto</title>
    <desc>Created with Sketch.</desc>
    <defs>
        <radialGradient cx="50%" cy="50%" r="10%"  id="radialGradient-3">
            <stop stop-color="#0000FF" offset="0%"></stop>
            <stop stop-color="#FF0000" offset="100%"></stop>
        </radialGradient>
    </defs>
    <g id="ime_bg_input_auto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
        <rect id="Popup/Gradient-Copy-2" fill="url(#radialGradient-3)"  x="0" y="0" width="1000" height="100"></rect>
    </g>
</svg>

shape->rect(0,0,1000, 100)
grad->radial(500, 50 , 10);
// -> grad->radial(500, 50 , 0.1);
shape->fill(grad)

[Current]
image

[To be]
image

Shapes are sometimes not filled when using update

You can recreate this issue with this example: example
Just switch betweent '1' and '2', you will see that some of the shapes are sometimes not drawn.

This happens when we use fill between push and update_paint, like so:

shape = tvg_shape_new();
tvg_shape_append_rect(shape, 0, 0, 100, 100, 0, 0);
tvg_shape_push(canvas, shape);
tvg_shape_set_fill_color(shape, 0, 0, 255, 255); // if this was moved up one line, it would always work
tvg_canvas_update_paint(canvas, shape);
tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);

fill_bug
Whole window should be filled with rectangles, but some of them are not drawn

NEON Optimization for Sw Engine

Still there are a lot of rasterzing parts, not have SIMD operation.
We need a better fine-tuned software raster engine for ARM NEON devices.

Support Bitmap Rendering

tvg::Picture should support Bitmap Rendering

auto picture = tvg::Picture::gen();
picture->load(buffer);
...

Shape after reset is not rendered properly when multiple draw commands is used

Test code
`
tvg_engine_init(TVG_ENGINE_SW | TVG_ENGINE_GL, 0);

Tvg_Canvas* canvas = tvg_swcanvas_create();
tvg_swcanvas_set_target(canvas, buffer, WIDTH, WIDTH, HEIGHT, TVG_COLORSPACE_ARGB8888);

Tvg_Paint* shape = tvg_shape_new();
tvg_shape_append_rect(shape, 0, 0, 200, 200, 0, 0);

tvg_shape_set_stroke_color(shape, 255, 0, 0, 255);
tvg_shape_set_stroke_width(shape, 4);
tvg_shape_set_fill_color(shape, 0, 0, 255, 255);

tvg_canvas_push(canvas, shape);

tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);

tvg_shape_reset(shape);
tvg_canvas_update_paint(canvas, shape);

tvg_canvas_draw(canvas);
tvg_canvas_sync(canvas);
tvg_canvas_destroy(canvas);

tvg_engine_term(TVG_ENGINE_SW | TVG_ENGINE_GL);

`

Masking display incorrectly

In Masking.cpp example.
When mask object has transparency, the result wrong display.
Alpha is applied to the stroke and fill of the target.

Test code

diff --git a/src/examples/Masking.cpp b/src/examples/Masking.cpp
index 8d517ef..fc942d7 100644
--- a/src/examples/Masking.cpp
+++ b/src/examples/Masking.cpp
@@ -52,13 +52,14 @@ void tvgDrawCmds(tvg::Canvas* canvas)
     star->lineTo(426, 161);
     star->lineTo(546, 143);
     star->close();
-    star->stroke(10);
+    star->stroke(30);
     star->stroke(255, 255, 255, 255);
 
     //Mask3
     auto mask3 = tvg::Shape::gen();
     mask3->appendCircle(600, 200, 125, 125);
-    mask3->fill(255, 255, 255, 255);
+    mask3->fill(255, 255, 255, 125);
+    //or mask3->opacity(125);
     star->composite(move(mask3), tvg::CompositeMethod::AlphaMask);
     if (canvas->push(move(star)) != tvg::Result::Success) return;

image

Fix compile warnings

Do you have any better idea?

27/29] Compiling C++ object 'src/25a6634@@thorvg@sha/bindings_capi_tvgCapi.cpp.o'.

../src/bindings/capi/tvgCapi.cpp:35:1: warning: empty struct has size 0 in C, size 1 in C++ [-Wextern-c-compat]

struct _Tvg_Canvas

^

../src/bindings/capi/tvgCapi.cpp:40:1: warning: empty struct has size 0 in C, size 1 in C++ [-Wextern-c-compat]

struct _Tvg_Paint

^

../src/bindings/capi/tvgCapi.cpp:45:1: warning: empty struct has size 0 in C, size 1 in C++ [-Wextern-c-compat]

struct _Tvg_Gradient

^

3 warnings genera

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.