23 #include "gvplugin_skillgui_cairo.h"
26 #include <sys/types.h>
27 #include <utils/system/argparser.h>
50 if (!(argp.has_arg(
"i") && argp.has_arg(
"o") && argp.has_arg(
"f")) || argp.has_arg(
"h")) {
55 format = argp.arg(
"f");
58 white_bg = argp.has_arg(
"w");
59 postproc_required =
false;
60 do_postproc = argp.has_arg(
"p");
61 maxwidth = maxheight = 0;
64 if ((format !=
"pdf") && (format !=
"svg") && (format !=
"png")) {
65 printf(
"Unknown format '%s'\n\n", format.c_str());
70 if (do_postproc && (format !=
"png")) {
71 printf(
"Post-processing only available for PNG output format.\n");
75 if (argp.has_arg(
"s")) {
77 scale = strtod(argp.arg(
"s"), &endptr);
79 printf(
"Invalid scale value '%s', could not convert to number (failed at '%s').\n",
86 indir = argp.arg(
"i");
87 outdir = argp.arg(
"o");
89 struct stat statbuf_in, statbuf_out;
90 if (stat(indir.c_str(), &statbuf_in) != 0) {
91 perror(
"Unable to stat input directory");
94 if (stat(outdir.c_str(), &statbuf_out) != 0) {
95 perror(
"Unable to stat output directory");
98 if (!S_ISDIR(statbuf_in.st_mode) || !S_ISDIR(statbuf_out.st_mode)) {
99 printf(
"Input or output directory is not a directory.\n\n");
103 char outdir_real[PATH_MAX];
104 if (realpath(outdir.c_str(), outdir_real)) {
105 outdir = outdir_real;
108 directory = opendir(indir.c_str());
110 printf(
"Could not open input directory\n");
115 gvplugin_skillgui_cairo_setup(gvc,
this);
129 printf(
"\nUsage: %s -i <dir> -o <dir> -f <format> [-w] [-s scale]\n"
130 " -i dir Input directory containing dot graphs\n"
131 " -o dir Output directory for generated graphs\n"
132 " -f format Output format, one of pdf, svg, or png\n"
133 " -w White background\n"
134 " -p Postprocess frames to same size (PNG only)\n"
135 " -s scale Scale factor to apply during rendering\n"
137 argp.program_name());
140 virtual Cairo::RefPtr<Cairo::Context>
144 if (format ==
"pdf") {
145 surface = Cairo::PdfSurface::create(outfile, bbw * scale, bbh * scale);
146 printf(
"Creating PDF context of size %f x %f\n", bbw * scale, bbh * scale);
147 }
else if (format ==
"svg") {
148 surface = Cairo::SvgSurface::create(outfile, bbw * scale, bbh * scale);
149 }
else if (format ==
"png") {
150 surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,
151 (
int)ceilf(bbw * scale),
152 (
int)ceilf(bbh * scale));
155 cairo = Cairo::Context::create(surface);
157 cairo->set_source_rgb(1, 1, 1);
174 height = bbh * scale;
190 ty = (bbh - pad_y) * scale;
199 if (bbw * scale > maxwidth) {
200 postproc_required = (maxwidth != 0);
201 maxwidth = bbw * scale;
203 if (bbh * scale > maxheight * scale) {
204 postproc_required = (maxheight != 0);
205 maxheight = bbh * scale;
227 FILE *f = fopen(infile.c_str(),
"r");
228 #if defined(GRAPHVIZ_ATLEAST_230) && defined(WITH_CGRAPH)
229 Agraph_t *g = agread(f, 0);
231 Agraph_t *g = agread(f);
234 gvLayout(gvc, g, (
char *)
"dot");
235 gvRender(gvc, g, (
char *)
"skillguicairo", NULL);
236 gvFreeLayout(gvc, g);
242 surface->write_to_png(outfile);
255 while ((d = readdir(directory)) != NULL) {
256 if (fnmatch(
"*.dot", d->d_name, FNM_PATHNAME | FNM_PERIOD) == 0) {
257 char infile_real[PATH_MAX];
258 infile = indir +
"/" + d->d_name;
259 if (realpath(infile.c_str(), infile_real)) {
260 infile = infile_real;
262 char * basefile = strdup(infile.c_str());
263 std::string basen = basename(basefile);
265 outfile = outdir +
"/" + basen.substr(0, basen.length() - 3) + format;
266 printf(
"Converting %s to %s\n", infile.c_str(), outfile.c_str());
269 printf(
"%s does not match pattern\n", d->d_name);
273 if (do_postproc && postproc_required) {
284 static cairo_status_t
285 write_func(
void *closure,
const unsigned char *data,
unsigned int length)
287 FILE *f = (FILE *)closure;
288 if (fwrite(data, length, 1, f)) {
289 return CAIRO_STATUS_SUCCESS;
291 return CAIRO_STATUS_WRITE_ERROR;
299 printf(
"Post-processing PNG files, resizing to %fx%f\n", maxwidth, maxheight);
301 DIR * output_dir = opendir(outdir.c_str());
302 while ((d = readdir(output_dir)) != NULL) {
303 if (fnmatch(
"*.png", d->d_name, FNM_PATHNAME | FNM_PERIOD) == 0) {
304 infile = outdir +
"/" + d->d_name;
305 Cairo::RefPtr<Cairo::ImageSurface> imgs = Cairo::ImageSurface::create_from_png(infile);
306 if ((imgs->get_height() != maxheight) || (imgs->get_width() != maxwidth)) {
308 char *tmpout = strdup((outdir +
"/tmpXXXXXX").c_str());
309 FILE *f = fdopen(mkstemp(tmpout),
"w");
313 Cairo::RefPtr<Cairo::ImageSurface> outs =
314 Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,
315 (
int)ceilf(maxwidth),
316 (
int)ceilf(maxheight));
317 double tx = (maxwidth - imgs->get_width()) / 2.0;
318 double ty = (maxheight - imgs->get_height()) / 2.0;
319 printf(
"Re-creating %s for post-processing, "
320 "resizing from %ix%i, tx=%f, ty=%f\n",
326 Cairo::RefPtr<Cairo::Context> cc = Cairo::Context::create(outs);
328 cc->set_source_rgb(1, 1, 1);
331 cc->set_source(imgs, tx, ty);
338 rename(outfile.c_str(), infile.c_str());
342 closedir(output_dir);
349 Cairo::RefPtr<Cairo::Surface> surface;
350 Cairo::RefPtr<Cairo::Context> cairo;
360 double maxwidth, maxheight;
361 bool postproc_required;
369 main(
int argc,
char **argv)
DOT graph batch renderer.
virtual void get_translation(double &tx, double &ty)
Get translation values.
void usage()
Show usage instructions.
virtual bool scale_override()
Check if scale override is enabled.
virtual void get_pad(double &pad_x, double &pad_y)
Get padding.
void render()
Render graph.
virtual void get_dimensions(double &width, double &height)
Get available space dimensions.
virtual void set_bb(double bbw, double bbh)
Set the bounding box.
static cairo_status_t write_func(void *closure, const unsigned char *data, unsigned int length)
Write function for Cairo.
void postprocess()
Post-process files.
virtual void set_pad(double pad_x, double pad_y)
Set padding.
virtual void set_scale(double scale)
Set scale.
virtual double get_scale()
Get scale factor.
SkillGuiBatchRenderer(int argc, char **argv)
Constructor.
virtual Cairo::RefPtr< Cairo::Context > get_cairo()
Get Cairo context.
virtual void set_translation(double tx, double ty)
Set translation.
~SkillGuiBatchRenderer()
Destructor.
void run()
Run the renderer.
Graphviz Cairo render plugin instructor.
Parse command line arguments.
Fawkes library namespace.