Thursday, December 10, 2009

Manipulate SVG 2D Graphics programmatically with GPAC

If you publish a scientific work based on GPAC thank you to mention in the article, mentioning "GPAC: open source multimedia framework" (DOI: 10.1145/1291233.1291452)


GPAC is a framework, focused on multimedia development, developed by Telecom ParisTech. GPAC is an Open Source project hosted on sourceforge.

GPAC has excellent SVG support. (look at the Show grid implementations of SVG).

This note is a start point for a series on the use of the GPAC library for manipulating SVG documents programmatically. The first note is about creating a SVG scene by C program and its backup as a file.

Create SVG

Create a scenegraph

Basically, a SceneGraph? is the object used by the Gpac library to manipulate a graphic scene. The same object is used for MPEG-4 BIFS, Laser, SVG.

Declaration:

GF_SceneGraph * sg;

Object creation:

sg = gf_sg_new ();

Now we are ready to put things in the sg object.

Create the root of the SVG document

SVG elements are handled in the GPAC type SVG_Element. We will create such an element, which we call root as the root SVG document.

Declaration

SVG_Element * root;

Creation:

root = (SVG_Element *)gf_node_new(sg, TAG_SVG_svg);

Here, we show that we create the element in the scene graph sg created earlier and that the element created must be of type TAG_SVG_svg. The constants used are defined in the file nodes_svg.h. The constants name is constructed with the prefix TAG_SVG_ followed by the name of the corresponding SVG element. For example, TAG_SVG_circle for the element circle, TAG_SVG_text for the text element.

The object is created. As it is the root of our SVG document, this particular role must be reported to GPAC by the following call:

gf_sg_set_root_node(sg, (GF_Node *)root);

In addition, each object created should be recorded at its parent (we shall see later that this is useful in the reuse of objects). As the root has no parent, we pass NULL as parameter. The call is:

gf_node_register ((GF_Node *) root, NULL);

Finally, the root element of an SVG document must have at least one attribute that associates the SVG namespace.

setAttributeNS(root, NULL, "xmlns", "http://www.w3.org/2000/svg");

This procedure is built on the DOM model. As we are not in an object language, we can not write root.setAttributeNS(...); we pass the object as first parameter of the procedure. The other parameters are similar to those of setAttributeNS DOM. The second is the namespace attribute, the third is the attribute name, the fourth is the attribute value. We will return later on the second parameter, the namespace; for the moment we use the default namespace by passing NULL.

Now, an empty SVG document is ready to receive content.

Add content into the document

We'll add a circle in the document.

For this, we declare a SVG_Element:

SVG_Element *circle;

then we create it:

circle = (SVG_Element *)gf_node_new(sg, TAG_SVG_circle);

like we created the element .

We must add it to the list of children of the root:

gf_node_list_add_child(&root->children, (GF_Node *)circle);

Then, as before, register it with its parent:

gf_node_register((GF_Node *)circle, (GF_Node *)root);

Finally, we create a set of attributes that will define the circle

setAttributeNS (circle, null, "cx", "200");
setAttributeNS(circle, NULL, "cy", "100"); setAttributeNS (circle, null, "cy", "100");
setAttributeNS(circle, NULL, "r", "50"); setAttributeNS (circle, NULL, "r", "50");

And here we have an SVG document with a circle.

Generate the corresponding file


To create the file, GPAC has a mechanism called dumper which produces an image of a scene graph.

We declare a dump object:

GF_SceneDumper *dumper;

Then we create the SVG dumper:

dumper = gf_sm_dumper_new(sg, "test", ' ', GF_SM_DUMP_SVG);

The first parameter is the SVG scene graph which we will dump. The second parameter is the name of file to generate. The third character is the character used for indentation. The fourth is the type of representation we want to generate, here we are concerned only with dump SVG specified by the constant GF_SM_DUMP_SVG.

Finally, we start writing the file:

gf_sm_dump_graph(dumper, 0, 0);

The first parameter is obviously the dump created just before. The other two parameters have no interest in the case of SVG backup.

Finish properly

Finally, we must free the memory occupied by the scene and objects within it. For this one call (provided that the objects be properly integrated into the scene):

gf_sg_del (sg);

To be continued

In the next few notes, we discuss the display of the created SVG document, the creation of more complex scenes with multiple levels of nested elements, then we'll create a scene with internal and external links.

Thursday, June 11, 2009

Manipuler du graphique 2D SVG par programme avec GPAC

Si vous publiez un travail scientifique qui s'appuie sur GPAC, merci de mentionner GPAC en citant cet article "GPAC: open source multimedia framework" (DOI: 10.1145/1291233.1291452)

GPAC est un environnement de travail sur des développements multimédia porté par Telecom ParisTech. GPAC est un projet Open Source hébergé sur sourceforge.

GPAC a un excellent support de SVG. Voir la grille des implémentations de SVG.

Je démarre avec ce billet une série concernant l'utilisation de la librairie GPAC pour manipuler des documents SVG par programme. Ce premier billet porte sur la création par programme C d'une scène SVG et sa sauvegarde sous forme de fichier.

Créer un SVG



Créer un SceneGraph



A la base, l'objet manipulé par la librairie GPAC pour représenter une scène graphique est un SceneGraph. Ce même objet est utilisé pour du MPEG-4 BIFS, du Laser, du SVG.

La déclaration:
GF_SceneGraph *sg;

La création de l'objet:
sg = gf_sg_new();

Maintenant, nous sommes prêt pour mettre des choses dans l'objet sg.

Créer la racine du document SVG



Les éléments SVG manipulés dans GPAC sont de type SVG_Element. Nous allons créer un tel élément, que nous nommerons root, en tant que racine du document SVG.
La déclaration
SVG_Element *root;

La création:
root = (SVG_Element *)gf_node_new(sg, TAG_SVG_svg);

Ici, nous indiquons que nous créons l'élément dans la scène graphique sg créée précédemment et que l'élément créé doit être de type TAG_SVG_svg. Les constantes utilisées sont définies dans le fichier nodes_svg.h. Le nom des constantes est construit avec la racine TAG_SVG_ suivi du nom de l'élément SVG concerné. Par exemple, TAG_SVG_circle pour l'élément circle, TAG_SVG_text pour l'élément text.


L'objet est créé. Comme c'est la racine de notre document, ce rôle particulier doit être indiqué à GPAC par l'appel suivant:
gf_sg_set_root_node(sg, (GF_Node *)root);

En plus, chaque objet créé doit être comptabilisé au niveau de son parent (nous verrons plus tard que cela est utile dans des réutilisations d'objets). Comme la racine n'a pas de parent, on passe NULL comme paramètre. L'appel est donc: gf_node_register((GF_Node *)root, NULL);

Enfin, l'élément <svg> racine d'un document SVG doit posséder au moins un attribut qui lui associe le namespace SVG.
setAttributeNS(root, NULL, "xmlns", "http://www.w3.org/2000/svg");

Cette procédure est construite sur le modèle DOM. Comme nous ne sommes pas dans un langage objet, nous ne pouvons pas écrire root.setAttributeNS(...); nous passons l'objet comme premier paramètre de la procédure. Les autres paramètres sont similaires à ceux du setAttributeNS DOM. Le deuxième est le namespace de l'attribut, le troisième est le nom de l'attribut, le quatrième est la valeur de l'attribut. Nous reviendrons plus tard sur le deuxième paramètre, le namespace, pour l'instant nous utilisons le namespace par défaut en passant la valeur NULL.

Maintenant, un document SVG vide est prêt à recevoir du contenu.

Ajouter du contenu dans le document



Nous allons ajouter un cercle dans le document.
Pour cela, nous déclarons un SVG_Element:
SVG_Element *circle;

puis nous le créons:
circle = (SVG_Element *)gf_node_new(sg, TAG_SVG_circle);
à la façon dont nous avons créé l'élément <svg>.

Nous devons l'ajouter dans la liste des enfants de la racine:
gf_node_list_add_child(&root->children, (GF_Node *)circle);

Puis, comme précédemment, l'enregistrer auprès de son parent:
gf_node_register((GF_Node *)circle, (GF_Node *)root);

Enfin, nous créons un ensemble d'attribut qui vont définir le cercle: setAttributeNS(circle, NULL, "cx", "200");
setAttributeNS(circle, NULL, "cy", "100");
setAttributeNS(circle, NULL, "r", "50");

Et, voilà, nous avons un document SVG avec un cercle.

Générer le fichier correspondant



Pour créer le fichier, GPAC dispose d'un mécanisme nommé dumper qui permet de sauver une représentation d'une scène graphique.
Nous déclarons un objet dumper:
GF_SceneDumper *dumper;

Puis, nous créons l'objet:
dumper = gf_sm_dumper_new(sg, "test", ' ', GF_SM_DUMP_SVG);

Le premier paramètre est la scène pour laquelle nous créons un dumper. Le deuxième paramètre est le nom du fichier à générer. Le troisième caractère est le caractère utilisé pour l'indentation. Le quatrième est le type de représentation que nous souhaitons générer; ici, nous ne sommes concernés que par le dump SVG, spécifié par la constante GF_SM_DUMP_SVG.

Enfin, nous déclencons la sauvegarde proprement dite:
gf_sm_dump_graph(dumper, 0, 0);

Le premier paramètre est de façon évidente le dumper créé juste avant. Les deux autres paramètres n'ont pas d'intérêt pour le cas de la sauvegarde SVG.

Finir proprement



Enfin, nous devons libérer la mémoire occupée par la scène et les objets qui la composent. Pour cela, un appel suffit (pourvu que les objets aient correctement incorporés dans la scène):
gf_sg_del(sg);

A suivre



Dans les prochains billets, nous évoquerons l'affichage de la scène créée, la création de scènes plus complexe, avec plusieurs niveaux d'imbrication d'éléments, puis nous créerons une scène avec des liens internes et externes.