1

I am trying to generate graphs in picture format from graphviz in a C++ application.

The way I proceed is the following. From boost library, I create an adjancy_list:

struct VertexP { std::string tag; std::string shape;std::string style; };
struct EdgeP { std::string symbol; std::string color; };
struct GraphP { };

typedef adjacency_list<vecS, vecS, directedS, VertexP, EdgeP, GraphP> Graph;

I have a function which build my graph recursively from external data

Graph addnode_progeny(data, Graph );

Then, I have a function which generate the dot file of this graph.

void printGraphDot(Graph g, std::string file_path){
std::ofstream dot_file(file_path+".dot");
dynamic_properties dp;
dp.property("node_id", get(&VertexP::tag, g));
dp.property("label", get(&VertexP::tag, g));
dp.property("shape", get(&VertexP::shape, g));
dp.property("style", get(&VertexP::style, g));
dp.property("label", get(&EdgeP::symbol, g));
dp.property("color", get(&EdgeP::color, g));
dp.property("rankdir", boost::make_constant_property<Graph*>(std::string("TB")));
write_graphviz_dp(dot_file, g, dp);
}

Until this point, everything goes fine.

Now, I want to transform this dot file into png file. I do not want to pass by a system("dot -Tpng input -o output") command as, I dont want to oblige the user to have graphviz installed.

I have found a first idea in the following post: Generate image of GraphViz graph given dot text c++

I have adapted the code. I have added it to the previous function and it works when I need to generate ONE graph.

The new function is:

void printGraphDot(Graph g, std::string file_path){
std::ofstream dot_file(file_path+".dot");
dynamic_properties dp;
dp.property("node_id", get(&VertexP::tag, g));
dp.property("label", get(&VertexP::tag, g));
dp.property("shape", get(&VertexP::shape, g));
dp.property("style", get(&VertexP::style, g));
dp.property("label", get(&EdgeP::symbol, g));
dp.property("color", get(&EdgeP::color, g));
dp.property("rankdir", boost::make_constant_property<Graph*>(std::string("TB")));

write_graphviz_dp(dot_file, g, dp);
std::string o_arg = "-o" +file_path+".png";
std::string i_arg = file_path+".dot";
char* args[] = {const_cast<char*>("dot"),
                const_cast<char*>("-Tpng"),
                const_cast<char*>(i_arg.c_str()),
                const_cast<char*>(o_arg.c_str()) };

const int argc = sizeof(args)/sizeof(args[0]);
Agraph_t *h, *prev = NULL;
GVC_t *gvc;
gvc = gvContext();
gvParseArgs(gvc, argc, args);

while ((h = gvNextInputGraph(gvc)))
{
  if (prev)
  {
    gvFreeLayout(gvc, prev);
    agclose(prev);
  }
  gvLayoutJobs(gvc, h);
  gvRenderJobs(gvc, h);
  prev = h;
}
}

However, for multiple graph, if I call again this function, it does not work and I have a segmentation error. In fact, it is written that we can use only one GVC_t in an application, in the following documentation, page 25: http://www.graphviz.org/pdf/libguide.pdf.

So in the following case, it stops the program with segmentation fault:

printGraphDot( g1,  file_path1);
printGraphDot( g2,  file_path2);

Is there another way to generate png graph from dot file inside a C++ application without using the command?

Thank you very much for your help. Cheers

froz
  • 163
  • 1
  • 12
  • Some of your `const_cast` lead to undefined behavior. You should really to do a proper copy or put the literals in `std::string` objects. – Galik Aug 21 '18 at 15:54
  • Unfortunately, it is not the reason of the problem. In the libguide http://www.graphviz.org/pdf/libguide.pdf , they use const_cast. That is because the 2nd argument in function gvParseArgs takes char* – froz Aug 23 '18 at 16:07
  • I did not see an example of them using `const_cast` in that document. And even if they did, it is still *undefined behavior* if performed on an object that was originally defined to be *const* (like some of yours). – Galik Aug 23 '18 at 16:16
  • Hum I just checked the docment and you are right, sorry, I misunderstood. So I tried to replace the const_cast by this way: char* args[] = {"dot", "-Tpng", i_arg.c_str(), o_arg.c_str() }; It gives an invalide conversion error. Sorry for my stupid questions but how can I write it properly? – froz Aug 23 '18 at 16:28
  • You can do the same thing you did with the other strings like `o_arg` (make a string object out of it) then your `const_cast` will be well defined. But it's still bad style. Instead you can do `&i_arg[0]` in place of `const_cast(i_arg.data())`. – Galik Aug 23 '18 at 16:32

1 Answers1

0

I found a way, I used the following function and it works and I added this answer as well in Generate image of GraphViz graph given dot text c++:

bool saveImageGV(std::string file_path){
    GVC_t *gvc;
    Agraph_t *g;
    FILE *fp;
    gvc = gvContext();
    fp = fopen((file_path+".dot").c_str(), "r");
    g = agread(fp, 0);
    gvLayout(gvc, g, "dot");
    gvRender(gvc, g, "png", fopen((file_path+".png").c_str(), "w"));
    gvFreeLayout(gvc, g);
    agclose(g);
    return (gvFreeContext(gvc));
}
froz
  • 163
  • 1
  • 12
  • 1
    Froz, instead of posting an answer which merely links to another answer, please instead [flag the question](https://stackoverflow.com/help/privileges/flag-posts) as a duplicate. – 4b0 Aug 30 '18 at 05:15
  • Shree and Coeur, I have modified my answer according to your wishes. – froz Aug 30 '18 at 07:37