Last update: May 1, 2022
libmsvg is a minimal and generic C library for reading and writing static SVG files.
SVG stand for Scalable Vector Graphics. It is a standard defined by the World Wide Web Consortium (see http://www.w3.org/Graphics/SVG/).
libmsvg concentrates on a subset of SVG to be useful. More specifically on a subset of the SVG Tiny 1.2 specification. The subset is described in Appendix A.
I think the best way to start with a programmer's guide is to show examples, so here there are.
This example read a SVG file in a MsvgElement tree
#include <stdio.h> #include <msvg.h> int main(int argc, char **argv) { MsvgElement *root; int error; if (argc <2) { printf("Usage: example svgfile\n"); return 0; } root = MsvgReadSvgFile(argv[1], &error); if (root == NULL) { printf("Error %d reading %s\n", error, argv[1]); return 0; } // Now you can process the structure. By example: MsvgPrintRawElementTree(stdout, root, 0); return 1; }
This example builds a MsvgElement tree and writes it to a file
#include <stdio.h> #include <msvg.h> #define TESTFILE "msvgt2.svg" int main(int argc, char **argv) { MsvgElement *root, *son; root = MsvgNewElement(EID_SVG, NULL); MsvgAddRawAttribute(root, "version", "1.2"); MsvgAddRawAttribute(root, "baseProfile", "tiny"); MsvgAddRawAttribute(root, "xmlns", "http://www.w3.org/2000/svg"); MsvgAddRawAttribute(root, "viewBox", "0 0 400 400"); son = MsvgNewElement(EID_RECT, root); MsvgAddRawAttribute(son, "x", "1"); MsvgAddRawAttribute(son, "y", "1"); MsvgAddRawAttribute(son, "width", "398"); MsvgAddRawAttribute(son, "height", "398"); MsvgAddRawAttribute(son, "stroke", "#F00"); MsvgAddRawAttribute(son, "fill", "#FFF"); son = MsvgNewElement(EID_RECT, root); MsvgAddRawAttribute(son, "x", "11"); MsvgAddRawAttribute(son, "y", "11"); MsvgAddRawAttribute(son, "width", "380"); MsvgAddRawAttribute(son, "height", "380"); MsvgAddRawAttribute(son, "stroke", "#0F0"); MsvgAddRawAttribute(son, "fill", "none"); MsvgPrintRawElementTree(stdout, root, 0); if (!MsvgWriteSvgFile(root, TESTFILE)) { printf("Error writing %s\n", TESTFILE); return 0; } return 1; }
We assume here that you have the libmsvg library previously installed. If not, please read the "readme" file for installation instructions.
These are the command lines to compile the examples for the three supported platforms:
The central structure of libmsvg is the MsvgElement tree. Every MsvgElement has an element type id (eid), a pointer to his father, pointers to his previous and next siblings and a pointer to his first son. The root element must be a EID_SVG. In this version of libmsvg only EID_SVG, EID_DEFS and EID_G can have child elements. The other supported elements are EID_RECT, EID_CIRCLE, EID_ELLIPSE, EID_LINE, EID_POLYLINE, EID_POLYGON, EID_PATH, EID_TEXT and EID_USE.
This graph represents an example of a MsvgElement tree:
Every MsvgElement can have attributes, they can be of two types: raw or cooked. The type of MsvgElement attributes in a tree is determined by a variable in the root element: root->psvgattr->tree_type. If this variable is RAW_SVGTREE all attributes are raw. Raw attributes are simple key,value strings pairs. If the variable is COOKED_SVGTREE the tree has cooked attributes too. Cooked attributes are typed variables and can be generic or specific, all elements have the generic ones, each element type id has his specific ones.
After a SVG file is loaded to a MsvgElement tree by the MsvgReadSvgFile function it is marked as a RAW_SVGTREE. Only the supported elements are inserted in the tree, but all the read attributes are stored like raw attributes. This stage of the tree can suffice for some programs. Elements and attributes can be added, deleted or reordered and finally be written to a file using the MsvgWriteSvgFile function.
Using the MsvgRaw2CookedTree funtion you can convert a MsvgElement tree to the COOKED_SVGTREE type. Only the supported attributes are processed and converted to cooked attributes. In this state the tree is easier to be manipulated and/or rasterized by a program.
In addition to attributes an element can have content, content is stored in a MsvgContent variable, and it is shared by RAW and COOKED trees. In this version of the library only EID_TEXT element contents are stored in the tree.
After reading the previous section it must be easy to undestand the MsvgElement structure from the msvg.h include file:
typedef struct _MsvgElement *MsvgElementPtr; typedef struct _MsvgElement { enum EID eid; /* element type id */ MsvgElementPtr father; /* pointer to father element */ MsvgElementPtr psibling; /* pointer to previous sibling element */ MsvgElementPtr nsibling; /* pointer to next sibling element */ MsvgElementPtr fson; /* pointer to first son element */ MsvgRawAttributePtr frattr; /* pointer to first raw attribute */ MsvgContentPtr fcontent; /* pointer to content */ /* cooked generic attributes */ char *id; /* id attribute */ MsvgPaintCtx pctx; /* painting context */ /* cooked specific attributes */ union { MsvgSvgAttributes *psvgattr; MsvgDefsAttributes *pdefsattr; MsvgGAttributes *pgattr; MsvgUseAttributes *puseattr; MsvgRectAttributes *prectattr; MsvgCircleAttributes *pcircleattr; MsvgEllipseAttributes *pellipseattr; MsvgLineAttributes *plineattr; MsvgPolylineAttributes *ppolylineattr; MsvgPolygonAttributes *ppolygonattr; MsvgPathAttributes *ppathattr; MsvgTextAttributes *ptextattr; }; } MsvgElement;
Raw attributes are stored in a simple linked list of MsvgRawAttribute variables:
typedef struct _MsvgRawAttribute *MsvgRawAttributePtr; typedef struct _MsvgRawAttribute { char *key; /* key attribute */ char *value; /* value attribute */ MsvgRawAttributePtr nrattr; /* pointer to next raw attribute */ } MsvgRawAttribute;
Content is stored in a MsvgContent variable:
typedef struct _MsvgConten { int len; /* len content */ char s[1]; /* content (not actual size) */ } MsvgContent;
Cooked generic attributes are the same for all elements, the "id" attribute (that can be NULL) and a MsvgPaintCtx structure:
typedef struct { double a, b, c, d, e, f; } TMatrix; typedef struct _MsvgPaintCtx { rgbcolor fill; /* fill color attribute */ double fill_opacity; /* fill-opacity attribute */ rgbcolor stroke; /* stroke color attribute */ double stroke_width; /* stroke-width attribute */ double stroke_opacity; /* stroke-opacity attribute */ TMatrix tmatrix; /* transformation matrix */ int font_family; /* font-family attribute */ int font_style; /* font-style attribute */ int font_weight; /* font-weight attribute */ double font_size; /* font-size attribute */ } MsvgPaintCtx;
it is important to note that all attributes in the MsvgPaintCtx can be inherited from his father element. This can be doing explicitly with the value INHERIT_COLOR (for colors) INHERIT_VALUE (for doubles) or INHERIT_IVALUE (for ints), that correspond to the raw keyword value "inherit", or implicitly when the value is NODEFINED_COLOR (for colors) NODEFINED_VALUE (for doubles) or NODEFINED_IVALUE (for ints), that occurs when the raw value is not defined and the father value is defined.
fill and stroke colors can have the value NO_COLOR, that correspond to the raw keyword value "none" that means fill or stroke must not be done.
tmatrix is special, if undefined it defaults to the identity matrix. Before rasterizing any element it is neceary to calculate the Current Transformation Matrix, multiplying all the ancestors transformation matrix in order and finally with the own element transformation matrix.
Values that can be converted from raw to cooked are listend in Appendix B.
Cooked specific attributes are different for each element type id and are stored in a union, you can inspect each one in the msvg.h include file.
Using the MsvgReadSvgFile function you load a SVG file in a MsvgElement tree.
MsvgElement *root; int error; root = MsvgReadSvgFile("filein.svg", &error);
If the file doesn't exists or if it isn't a valid SVG file, root will be NULL and error will be filled with the error number, so you must check it. Only the supported elements are stored in the tree, the not supported ones are silently ignored. The tree will be a RAW tree, with all the element attributes stored as raw attributes. If you want a COOKED tree you can use the MsvgRaw2CookedTree funtion:
int result; result = MsvgRaw2CookedTree(root);
result will be true if all was right, false otherwise. Note that after calling this function you have really a mixed RAW/COOKED tree, because all raw parameters are preserved. If you are sure you don't need the raw parameters anymore you can call the MsvgDelAllTreeRawAttributes function:
int result; result = MsvgDelAllTreeRawAttributes(root);
result will be the number of raw parameters deleted.
Using only two function we can construct a MsvgElement tree by program. The MsvgNewElement function takes two parameters: the element type id and the father element, that can be NULL, it returns the pointer to the constructed element. The MsvgAddRawAttribute takes three parameters: an element pointer, a key and a value.
Let's see an example. We begin constructing the SVG element passing NULL in the father parameter, because it is the root element. By default the tree will be RAW_SVGTREE.
MsvgElement *root; root = MsvgNewElement(EID_SVG, NULL);
Now, we add attributes to identify the svg element properly and set the drawing limits using the MsvgAddRawAttribute function.
MsvgAddRawAttribute(root, "version", "1.2"); MsvgAddRawAttribute(root, "baseProfile", "tiny"); MsvgAddRawAttribute(root, "xmlns", "http://www.w3.org/2000/svg"); MsvgAddRawAttribute(root, "xmlns:xlink", "http://www.w3.org/1999/xlink"); MsvgAddRawAttribute(root, "viewBox", "0 0 400 400");
We continue adding two child elements, a RECT element and a translated G element.
MsvgElement *son; son = MsvgNewElement(EID_RECT, root); MsvgAddRawAttribute(son, "x", "1"); MsvgAddRawAttribute(son, "y", "1"); MsvgAddRawAttribute(son, "width", "398"); MsvgAddRawAttribute(son, "height", "398"); MsvgAddRawAttribute(son, "stroke", "#F00"); MsvgAddRawAttribute(son, "fill", "#FFF"); son = MsvgNewElement(EID_G, root); MsvgAddRawAttribute(son, "stroke", "#0F0"); MsvgAddRawAttribute(son, "fill", "none"); MsvgAddRawAttribute(son, "transform", "translate(50)");
Finally we add two child CIRCLE elements to the G element, one directly and the other indirectly by an USE element. Note that they will inherit the stroke and fill attributes and the transformation matrix.
MsvgElement *son2; son2 = MsvgNewElement(EID_CIRCLE, son); MsvgAddRawAttribute(son2, "id", "mycircle"); MsvgAddRawAttribute(son2, "cx", "100"); MsvgAddRawAttribute(son2, "cy", "200"); MsvgAddRawAttribute(son2, "r", "80"); son2 = MsvgNewElement(EID_USE, son); MsvgAddRawAttribute(son2, "xlink:href", "#mycircle"); MsvgAddRawAttribute(son2, "x", "100");
We have now our MsvgElement tree and we can manipulate it or write it to a file.
Here you have two options, you can construct a RAW MsvgElement tree and them call MsvgRaw2CookedTree or you can construct a COOKED tree directly.
Constructing a COOKED tree is the same like constructing a RAW one, except we don't use the MsvgAddRawAttribute function. Instead we set directly the element cooked attributes, there are no functions to hide the variables, because we are programmers and we know what are we doing, doesn't it. The only precaution to take into account is to reserve memory when the parameter to be assigned is a pointer. This space will be freed if we delete the element.
MsvgElement *root; root = MsvgNewElement(EID_SVG, NULL); root->psvgattr->vb_min_x = 0; root->psvgattr->vb_min_y = 0; root->psvgattr->vb_width = 400; root->psvgattr->vb_height = 400; root->psvgattr->tree_type = COOKED_SVGTREE; MsvgElement *son; son = MsvgNewElement(EID_RECT, root); son->prectattr->x = 1; son->prectattr->y = 1; son->prectattr->width = 398; son->prectattr->height = 398; son->pctx.fill = 0XFFFFFF; son->pctx.stroke = 0XFF0000; son = MsvgNewElement(EID_G, root); son->pctx.fill = NO_COLOR; son->pctx.stroke = 0X00FF00; TMSetTranslation(&(son->pctx.tmatrix), 50, 50); MsvgElement *son2; son2 = MsvgNewElement(EID_CIRCLE, son); son2->id = strdup("mycircle"); son2->pcircleattr->cx = 100; son2->pcircleattr->cy = 200; son2->pcircleattr->r = 80; son2 = MsvgNewElement(EID_USE, son); son2->puseattr->refel = strdup("mycircle"); son2->puseattr->x = 100;
There are some functions to manipulate a MsvgElement tree.
void MsvgPruneElement(MsvgElement *el);
The MsvgPruneElement function prune an element from his tree and them we can insert it in another tree or in another point of the same tree. Note that if the pruned element has child, it retains them after pruned.
void MsvgDeleteElement(MsvgElement *el);
The MsvgDeleteElement does two things, prunes the element from his tree and deletes it, freeing the allocated memory used. Note that if the deleted element has child, they are deleted too.
int MsvgInsertSonElement(MsvgElement *el, MsvgElement *father); int MsvgInsertPSiblingElement(MsvgElement *el, MsvgElement *sibling); int MsvgInsertNSiblingElement(MsvgElement *el, MsvgElement *sibling);
This three functios insert an element (that can be a subtree if it has child) in the desired point of a tree. The MsvgInsertSonElement fucntion inserts the element like the last son of the indicated father. The MsvgInsertPSiblingElement function inserts the element like a previous sibling to the indicated sibling. And the MsvgInsertNSiblingElement function inserts the element like a next sibling. The three functions return 1 if all was ok, 0 otherwise.
MsvgElement *MsvgDupElement(MsvgElement *el);
The MsvgDupElement duplicates the element passed as parameter, if that element is a container (like EID_SVG or EID_G) it duplicates all the element child too.
There are some functions to find elements in a MsvgElement tree.
MsvgElement *MsvgFindFirstFather(MsvgElement *el);
returns the first father of an element, normally a EID_SVG element
typedef struct { int nelem[EID_LAST+1]; // num elements per type int totelem; // total num elements int totelwid; // num elements with id != NULL } MsvgTreeCounts; void MsvgCalcCountsCookedTree(MsvgElement *el, MsvgTreeCounts *tc); void MsvgCalcCountsRawTree(MsvgElement *el, MsvgTreeCounts *tc);
fill a MsvgTreeCounts structure counting elements for the tree pointed by el, note that there are a version for raw trees and another for cooked trees, this is necsary to populate the totelwid variable because in raw trees is necesary to check the raw attribute "id" and for cooked trees we can use the id cooked attribute. Note that the root EID_SVG element is not counted
MsvgElement * MsvgFindIdCookedTree(MsvgElement *el, char *id); MsvgElement * MsvgFindIdRawTree(MsvgElement *el, char *id);
find for the element with the provided id in the tree pointed by el, again there is a version for raw trees and another for cooked trees. It returns NULL if not found
The above functions walk all the tree comparing ids to find the element every time they are called, if you have to find lot of elements it is better to construct first a MsvgTableId structure calling one of these functions ( one for raw trees and one for cooked trees):
MsvgTableId * MsvgBuildTableIdCookedTree(MsvgElement *el); MsvgTableId * MsvgBuildTableIdRawTree(MsvgElement *el);
After that you can use next function to find elements (it does an efficient binary search):
MsvgElement *MsvgFindIdTableId(MsvgTableId *tid, char *id);
Note that if you add or delete elements in the tree you have to build a new MsvgTableId structure. when it is no longer necessary use next function to free memory:
void MsvgDestroyTableId(MsvgTableId *tid);
libmsvg has a number of functions to work with the transformation matrix cooked parameter TMatrix. Note that the transformation matrix is like that:
a c e b d f 0 0 1
so only the a, b, c, d, e, f values are stored int the TMatrix structure. Here are the functions:
void TMSetIdentity(TMatrix *des); int TMIsIdentity(TMatrix *t); int TMHaveRotation(TMatrix *t); void TMSetFromArray(TMatrix *des, double *p); void TMMpy(TMatrix *des, TMatrix *op1, TMatrix *op2); void TMSetTranslation(TMatrix *des, double tx, double ty); void TMSetScaling(TMatrix *des, double sx, double sy); void TMSetRotationOrigin(TMatrix *des, double ang); void TMSetRotation(TMatrix *des, double ang, double cx, double cy); void TMTransformCoord(double *x, double *y, TMatrix *ctm);
TMSetIdentity stores in des the identity matrix (1 0 0 1 0 0)
TMIsIdentity returns 1 if it is the identity matrix
TMHaveRotation returns 1 if it includes a rotation (b or c != 0)
TMSetFromArray set des from the double array p of dimension 6
TMMpy multiply op1 by op2 and stores the result in des
TMSetTranslation sets des with a traslation
TMSetScaling sets des with a scaling
TMSetRotationOrigin sets des with a rotation about the origin
TMSetRotation sets des with a rotation about cx, cy
TMTransformCoord changes x, y coordinates using ctm
libmsvg provides a function to serialize a COOKED MsvgElement tree. Using this function is the easier way to rasterize a MsvgElement tree.
int MsvgSerCookedTree(MsvgElement *root, MsvgSerUserFn sufn, void *udata);
this function will process the tree and call the supply user function for every drawable element (not for container elements). The user function must be defined as:
typedef void (*MsvgSerUserFn)(MsvgElement *el, MsvgPaintCtx *pctx, void *udata);
where "el" is the pointer to the drawable element and pctx a pointer to a constructed MsvgPaintCtx whit all the inherit and initial values processed and the current transformation matrix calculated, so the user program must use this painting context instead the element one to do the drawing.
The serialization process has into account the EID_USE elements, replacing them with the referenced element (that can be a subtree).
When calling MsvgSerCookedTree a pointer to a user-data variable can be provided, that will be passed to the supply user function.
Another function that libmsvg provides can be called by the user function:
MsvgElement * MsvgTransformCookedElement(MsvgElement *el, MsvgPaintCtx *pctx,);
that process the element parameters using the current transformation matrix (pctx->tmatrix) and returns a new drawable element that can be of different type that the original one, by example if an EID_RECT has to be rotated an EID_POLYGON or a EID_PATH (if it has rounded corners) is returned. . The function also adjust the element paint context parameters and sets the transformation matrix to the identity matrix. Note that you have to delete the new element returned after using it.
If MsvgTransformCookedElement cannot returns a properly transformed element it returns NULL and it is the user function responsability to manage correctly the element.
So using all the pieces the code to rasterize a SVG image will be like that:
static void userfn(MsvgElement *el, MsvgPaintCtx *pctx, void *udata) { MsvgElement *newel; newel = MsvgTransformCookedElement(el, pctx); if (newel == NULL) return; // or manage "el" + "pctx" by coding switch (newel->eid) { case EID_RECT : YourDrawRectElement(newel); break; case EID_CIRCLE : YourDrawCircleElement(newel); break; case EID_ELLIPSE : YourDrawEllipseElement(newel); break; case EID_LINE : YourDrawLineElement(newel); break; case EID_POLYLINE : YourDrawPolylineElement(newel); break; case EID_POLYGON : YourDrawPolygonElement(newel); break; case EID_PATH : YourDrawPathElement(newel); break; case EID_TEXT : YourDrawTextElement(newel); break; default : break; } MsvgDeleteElement(newel); } ... // in main MsvgElement *root ... // read or build the Msvg tree and convert it to a COOKED tree ... // set the graphics coordinates using the information in the EID_SVG element ... MsvgSerCookedTree(root, userfn, NULL); ...
Another interesting funtion included in libmsvg is:
MsvgElement * MsvgPathEltoPolyEl(MsvgElement *el, int nsp, double px_x_unit);
that transform a subpath from an EID_PATH element either in an EID_POLYLINE or an EID_POLYGON element (note that an EID_PATH element could have one or more subpaths). This way you can use a graphics library that not know how to handle Bezier curves to render the svg-tree. An example of coding:
case EID_PATH : nsp = MsvgCountSubPaths(newel->ppathattr->sp); for (i=0; i<nsp; i++) { newel2 = MsvgPathEltoPolyEl(newel, i, 1); if (newel2) { if (newel2->eid == EID_POLYGON) YourDrawPolygonElement(newel2); else if (newel2->eid == EID_POLYLINE) YourDrawPolylineElement(newel2); MsvgDeleteElement(newel2); } } break;
the px_x_unit parameter indicates the number of pixels per unit of svg coordinates, it is important so that the function can calculate the number of points to interpolate for each bezier curve. Here we pass 1 for simplicity but in a real program it must be calculated to have smooth curves.
Using the MsvgWriteSvgFile function you can write a MsvgElement tree to a file.
MsvgElement *root; int result; // construct the root tree result = MsvgWriteSvgFile(root, "fileout.svg")
MsvgWriteSvgFile only know how to write RAW trees. If you want to write a COOKED only tree you need to use the MsvgCooked2RawTree funtion first:
int result; MsvgDelAllTreeRawAttributes(root); result = MsvgCooked2RawTree(root);
Note that after call MsvgCooked2RawTree you continue to have a COOKED tree, but with all the raw parameters populated. Because the function doesn't delete any previous raw parameters, it is good idea to delete them in advance.
This table lists the SVG elements and attributes that are intended to be supported by libmsvg.
Each row lists an element, the supported attributes and the possible child elements.
Note that attributes listed only affects to COOKED trees, RAW trees can have any attribute.
A status mark (TO DO) means... you know: to do.
Element |
Specific supported attributes (status) |
Notes |
---|---|---|
<svg> |
version="1.2" (fixed value) baseprofile="tiny" (fixed value) xmlns="http://www.w3.org/2000/svg" (fixed value) xmlns:xlink="http://www.w3.org/1999/xlink" (fixed value) --- --- viewbox="min-x min-y width height" width="length" height="length" preserveaspectratio="valor" (TO DO) viewport-fill="color" viewport-fill-opacity="n" id="value" --- for inheritance --- fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" font-family="value" font-style="value" font-weight="value" font-size="value" |
-- possible child elements -- <defs>, <g>, <use>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text> |
<defs> |
id="value" --- for inheritance --- fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" font-family="value" font-style="value" font-weight="value" font-size="value" |
-- possible child elements -- <g>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text> |
<g> |
id="value" --- for inheritance --- fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" font-family="value" font-style="value" font-weight="value" font-size="value" |
-- possible child elements -- <g>, <use>, <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>, <text> |
<use> |
xlink:href ="#id" x="n" y="n" --- for inheritance --- fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" font-family="value" font-style="value" font-weight="value" font-size="value" |
Only local references are supported, stored in the "refel" cooked parameter. |
<rect> |
id="value" x="n" y="n" width="n" height="n" rx="n" ry="n" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<circle> |
id="value" cx="n" cy="n" r="n" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<ellipse> |
id="value" cx="n" cy="n" rx="n" ry="n" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
Using "rx", "ry" and "cx", "cy" raw parameters there will be calculated the "rx_x", "rx_y", "ry_x", "ry_y" cooked parameters, storing the real semi-axis points, so it will be easier transforming and rasterizing an ellipse. |
<line> |
id="value" x1="n" y1="n" x2="n" y2="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<polyline> |
id="value" points="data" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<polygon> |
id="value" points="data" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<path> |
id="value" d="path-data" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" |
|
<text> |
id="value" x="n" y="n" fill="color" fill-opacity="n" stroke="color" stroke-width="n" stroke-opacity="n" transform="transformation" font-family="value" font-style="value" font-weight="value" font-size="value" |
The TEXT content will be stored in a MsvgContent variable. |
This table list the possible values that some parameters can have (obvious parameters are not listed).
Note that these are the values that are expected when converting to a COOKED tree, RAW parameters can have any value.
A status mark (TO DO) means... you know: to do.
Parameters |
Raw value => Cooked value (status) |
Notes |
---|---|---|
svg.width svg.height |
number => same value numberpt => number * 1.25 numberpc => number * 15 numbermm => number * 3.54 numbercm => number * 35.4 numberin => number * 90 |
We assume 90 px per inch If width not defined or <=0 width = viewbox.width |
viewport-fill fill stroke |
NO DEFINED => NODEFINED_COLOR none => NO_COLOR currentColor => INHERIT_COLOR inherit => INHERIT_COLOR black => 0x000000 silver => 0xc0c0c0 gray => 0x808080 white => 0xffffff maroon => 0x800000 red => 0xff0000 purple => 0x800080 fuchsia => 0xff00ff green => 0x008000 lime => 0x00ff00 olive => 0x808000 yellow => 0xffff00 navy => 0x000080 blue => 0x0000ff teal => 0x008080 aqua => 0x00ffff #rgb => 0xrrggbb #rrggbb => 0xrrggbb rgb(rrr, ggg, bbb) => 0xrrggbb (TO DO) |
If viewport-fill is not defined it will be NO_COLOR. If after the inheritance process fill is not defined it will be 0x000000. If after the inheritance process stroke is not defined it will be NO_COLOR. |
viewport-fill-opacity fill-opacity stroke-opacity |
NO DEFINED => NODEFINED_VALUE inherit => INHERIT_VALUE number between 0.0 and 1.0 => same value |
If viewport-fill-opacity is not defined it will be 1. If after the inheritance process fill-opacity is not defined it will be 1. If after the inheritance process stroke-opacity is not defined it will be 1. |
stroke-width |
NO DEFINED => NODEFINED_VALUE inherit => INHERIT_VALUE number > 0.0 => same value |
If after the inheritance process stroke-width is not defined it will be 1. |
transform |
NO DEFINED => (1 0 0 1 0 0) none => (1 0 0 1 0 0) matrix(a b c d e f) => (a b c d e f) translate(x) => (1 0 0 1 x 0) translate(x y) => (1 0 0 1 x y) rotate(ang) => (cos(ang) sin(ang) -sin(ang) cos(ang) 0 0) rotate(ang cx cy) => traslate(cx cy) * rotate(ang) * translate(-cx -cy) scale(sx) => (sx 0 0 sx 0 0) scale(sx sy) => (sx 0 0 sy 0 0) skewX(ang) => (1 0 tan(ang) 1 0 0) (TO DO) skewY(ang) => (1 tan(ang) 0 1 0 0) (TO DO) ref(svg) => no transform for this element (TO DO) |
Note that before a drawable element can be rasterized it is necesary to calculate the current transformation matrix multiplying all transformation matrix from his parents elements. |
font-family |
NO DEFINED => NODEFINED_IVALUE inherit => INHERIT_IVALUE value contents "sans" => FONTFAMILY_SANS value contents "serif" => FONTFAMILY_SERIF value contents "cursive" => FONTFAMILY_CURSIVE value contents "fantasy" => FONTFAMILY_FANTASY value contents "monospace" => FONTFAMILY_MONOSPACE other values => (TO DO or NOT TO DO) |
If after the inheritance process font-family is not defined it will be FONTFAMILY_SANS. |
font-style |
NO DEFINED => NODEFINED_IVALUE inherit => INHERIT_IVALUE normal => FONTSTYLE_NORMAL italic => FONTSTYLE_ITALIC oblique => FONTSTYLE_OBLIQUE |
If after the inheritance process font-style is not defined it will be FONTSTYLE_NORMAL. |
font-weight |
NO DEFINED => NODEFINED_IVALUE inherit => INHERIT_IVALUE 100 => FONTWEIGHT_100 200 => FONTWEIGHT_200 300 => FONTWEIGHT_300 400 => FONTWEIGHT_400 500 => FONTWEIGHT_500 600 => FONTWEIGHT_600 700 => FONTWEIGHT_700 800 => FONTWEIGHT_800 900 => FONTWEIGHT_900 normal => FONTWEIGHT_NORMAL (=FONTWEIGHT_400) bold => FONTWEIGHT_BOLD (=FONTWEIGHT_700) bolder => (TODO) lighter => (TODO) |
If after the inheritance process font-weight is not defined it will be FONTWEIGHT_NORMAL. |
font-size |
NO DEFINED => NODEFINED_VALUE inherit => INHERIT_VALUE number => same value numberpt => number * 1.25 numberpc => number * 15 numbermm => number * 3.54 numbercm => number * 35.4 numberin => number * 90 [ xx-small | x-small | small | medium | large | x-large | xx-large ] => (TODO) [ larger | smaller ] => (TODO) |
If after the inheritance process font-size is not defined it will be 12. |
points |
x1,y1 x2,y2 ... => double values |
Stored in: |
d |
path string => linked list of normalized MsvgSubPath structs |
Stored in: |
Not in the Tiny 1.2 specs, but there are lot of svg images that instead of using individual style attributes group them in a unique style property using this format:
style="attribute:value;attribute:value;..."
If libmsvg finds such a construct it replaces it with individual raw attributes.
The SVG 1.1 specs defines 'a', 'A' commands in paths as elliptical arcs, it isn't in the Tiny 1.2 specs. If libmsvg find some they will be replaced by lines.