Graphviz  2.41.20170921.2350
gvrender_gd.c
Go to the documentation of this file.
1 /* $Id$ $Revision$ */
2 /* vim:set shiftwidth=4 ts=8: */
3 
4 /*************************************************************************
5  * Copyright (c) 2011 AT&T Intellectual Property
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the Eclipse Public License v1.0
8  * which accompanies this distribution, and is available at
9  * http://www.eclipse.org/legal/epl-v10.html
10  *
11  * Contributors: See CVS logs. Details at http://www.graphviz.org/
12  *************************************************************************/
13 
14 #include "config.h"
15 
16 #include <stdlib.h>
17 #include <stddef.h>
18 #include <stdint.h>
19 #include <string.h>
20 #include <fcntl.h>
21 
22 #include "gvplugin_render.h"
23 #include "gvplugin_device.h"
24 #include "gvcint.h" /* for gvc->g for agget */
25 #include "gd.h"
26 
27 #ifndef INT32_MAX
28 #define INT32_MAX (2147483647)
29 #endif
30 #ifndef UINT32_MAX
31 #define UINT32_MAX (4294967295U)
32 #endif
33 
34 
35 typedef enum {
43 } format_type;
44 
45 extern boolean mapbool(char *);
46 extern pointf Bezier(pointf * V, int degree, double t, pointf * Left, pointf * Right);
47 
48 #define BEZIERSUBDIVISION 10
49 
50 static void gdgen_resolve_color(GVJ_t * job, gvcolor_t * color)
51 {
52  gdImagePtr im = (gdImagePtr) job->context;
53  int alpha;
54 
55  if (!im)
56  return;
57 
58  /* convert alpha (normally an "opacity" value) to gd's "transparency" */
59  alpha = (255 - color->u.rgba[3]) * gdAlphaMax / 255;
60 
61  if(alpha == gdAlphaMax)
62  color->u.index = gdImageGetTransparent(im);
63  else
64  color->u.index = gdImageColorResolveAlpha(im,
65  color->u.rgba[0],
66  color->u.rgba[1],
67  color->u.rgba[2],
68  alpha);
69  color->type = COLOR_INDEX;
70 }
71 
72 static int white, black, transparent, basecolor;
73 
74 #define GD_XYMAX INT32_MAX
75 
76 static void gdgen_begin_page(GVJ_t * job)
77 {
78  char *bgcolor_str = NULL, *truecolor_str = NULL;
79  boolean truecolor_p = FALSE; /* try to use cheaper paletted mode */
80  boolean bg_transparent_p = FALSE;
81  gdImagePtr im = NULL;
82 
83  truecolor_str = agget((graph_t*)(job->gvc->g), "truecolor"); /* allow user to force truecolor */
84  bgcolor_str = agget((graph_t*)(job->gvc->g), "bgcolor");
85 
86  if (truecolor_str && truecolor_str[0])
87  truecolor_p = mapbool(truecolor_str);
88 
89  if (bgcolor_str && strcmp(bgcolor_str, "transparent") == 0) {
90  bg_transparent_p = TRUE;
92  truecolor_p = TRUE; /* force truecolor */
93  }
94 
95  if (GD_has_images(job->gvc->g))
96  truecolor_p = TRUE; /* force truecolor */
97 
98  if (job->external_context) {
99  if (job->common->verbose)
100  fprintf(stderr, "%s: using existing GD image\n", job->common->cmdname);
101  im = (gdImagePtr) (job->context);
102  } else {
103  if (job->width * job->height >= GD_XYMAX) {
104  double scale = sqrt(GD_XYMAX / (job->width * job->height));
105  job->width *= scale;
106  job->height *= scale;
107  job->zoom *= scale;
108  fprintf(stderr,
109  "%s: graph is too large for gd-renderer bitmaps. Scaling by %g to fit\n",
110  job->common->cmdname, scale);
111  }
112  if (truecolor_p) {
113  if (job->common->verbose)
114  fprintf(stderr,
115  "%s: allocating a %dK TrueColor GD image (%d x %d pixels)\n",
116  job->common->cmdname,
117  ROUND(job->width * job->height * 4 / 1024.),
118  job->width, job->height);
119  im = gdImageCreateTrueColor(job->width, job->height);
120  } else {
121  if (job->common->verbose)
122  fprintf(stderr,
123  "%s: allocating a %dK PaletteColor GD image (%d x %d pixels)\n",
124  job->common->cmdname,
125  ROUND(job->width * job->height / 1024.),
126  job->width, job->height);
127  im = gdImageCreate(job->width, job->height);
128  }
129  job->context = (void *) im;
130  }
131 
132  if (!im) {
133  job->common->errorfn("gdImageCreate returned NULL. Malloc problem?\n");
134  return;
135  }
136 
137  /* first color is the default background color */
138  /* - used for margins - if any */
139  transparent = gdImageColorResolveAlpha(im,
140  gdRedMax - 1, gdGreenMax,
141  gdBlueMax, gdAlphaTransparent);
142  gdImageColorTransparent(im, transparent);
143 
144  white = gdImageColorResolveAlpha(im,
145  gdRedMax, gdGreenMax, gdBlueMax,
146  gdAlphaOpaque);
147 
148  black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque);
149 
150  /* Blending must be off to lay a transparent basecolor.
151  Nothing to blend with anyway. */
152  gdImageAlphaBlending(im, FALSE);
153  gdImageFill(im, im->sx / 2, im->sy / 2, transparent);
154  /* Blend everything else together,
155  especially fonts over non-transparent backgrounds */
156  gdImageAlphaBlending(im, TRUE);
157 }
158 
159 extern int gvdevice_gd_putBuf (gdIOCtx *context, const void *buffer, int len);
160 extern void gvdevice_gd_putC (gdIOCtx *context, int C);
161 
162 static void gdgen_end_page(GVJ_t * job)
163 {
164  gdImagePtr im = (gdImagePtr) job->context;
165 
166  gdIOCtx ctx;
167 
168  ctx.putBuf = gvdevice_gd_putBuf;
169  ctx.putC = gvdevice_gd_putC;
170  ctx.tell = (void*)job; /* hide *job here */
171 
172  if (!im)
173  return;
174  if (job->external_context) {
175  /* leave image in memory to be handled by Gdtclft output routines */
176 #ifdef MYTRACE
177  fprintf(stderr, "gdgen_end_graph (to memory)\n");
178 #endif
179  } else {
180  /* Only save the alpha channel in outputs that support it if
181  the base color was transparent. Otherwise everything
182  was blended so there is no useful alpha info */
183  gdImageSaveAlpha(im, (basecolor == transparent));
184  switch (job->render.id) {
185  case FORMAT_GIF:
186 #ifdef HAVE_GD_GIF
187  gdImageTrueColorToPalette(im, 0, 256);
188  gdImageGifCtx(im, &ctx);
189 #endif
190  break;
191  case FORMAT_JPEG:
192 #ifdef HAVE_GD_JPEG
193  /*
194  * Write IM to OUTFILE as a JFIF-formatted JPEG image, using
195  * quality JPEG_QUALITY. If JPEG_QUALITY is in the range
196  * 0-100, increasing values represent higher quality but also
197  * larger image size. If JPEG_QUALITY is negative, the
198  * IJG JPEG library's default quality is used (which should
199  * be near optimal for many applications). See the IJG JPEG
200  * library documentation for more details. */
201 #define JPEG_QUALITY -1
202  gdImageJpegCtx(im, &ctx, JPEG_QUALITY);
203 #endif
204 
205  break;
206  case FORMAT_PNG:
207 #ifdef HAVE_GD_PNG
208  gdImagePngCtx(im, &ctx);
209 #endif
210  break;
211 
212 #ifdef HAVE_GD_GIF
213  case FORMAT_WBMP:
214  {
215  /* Use black for the foreground color for the B&W wbmp image. */
216  int black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque);
217  gdImageWBMPCtx(im, black, &ctx);
218  }
219  break;
220 #endif
221 
222  case FORMAT_GD:
223  gdImageGd(im, job->output_file);
224  break;
225 
226 #ifdef HAVE_LIBZ
227  case FORMAT_GD2:
228 #define GD2_CHUNKSIZE 128
229 #define GD2_RAW 1
230 #define GD2_COMPRESSED 2
231  gdImageGd2(im, job->output_file, GD2_CHUNKSIZE, GD2_COMPRESSED);
232  break;
233 #endif
234 
235  case FORMAT_XBM:
236 #if 0
237 /* libgd support only reading .xpm files */
238 #ifdef HAVE_GD_XPM
239  gdImageXbm(im, job->output_file);
240 #endif
241 #endif
242  break;
243  }
244  gdImageDestroy(im);
245 #ifdef MYTRACE
246  fprintf(stderr, "gdgen_end_graph (to file)\n");
247 #endif
248  job->context = NULL;
249  }
250 }
251 
252 static void gdgen_missingfont(char *err, char *fontreq)
253 {
254  static char *lastmissing = 0;
255  static int n_errors = 0;
256 
257  if (n_errors >= 20)
258  return;
259  if ((lastmissing == 0) || (strcmp(lastmissing, fontreq))) {
260 #ifdef HAVE_GD_FONTCONFIG
261 #if 0
262 /* FIXME - error function */
263  agerr(AGERR, "%s : %s\n", err, fontreq);
264 #endif
265 #else
266  char *p = getenv("GDFONTPATH");
267  if (!p)
268  p = DEFAULT_FONTPATH;
269 #if 0
270 /* FIXME - error function */
271  agerr(AGERR, "%s : %s in %s\n", err, fontreq, p);
272 #endif
273 #endif
274  if (lastmissing)
275  free(lastmissing);
276  lastmissing = strdup(fontreq);
277  n_errors++;
278 #if 0
279 /* FIXME - error function */
280  if (n_errors >= 20)
281  agerr(AGWARN, "(font errors suppressed)\n");
282 #endif
283  }
284 }
285 
286 /* fontsize at which text is omitted entirely */
287 #define FONTSIZE_MUCH_TOO_SMALL 0.15
288 /* fontsize at which text is rendered by a simple line */
289 #define FONTSIZE_TOO_SMALL 1.5
290 
291 #ifdef _WIN32
292 # define GD_IMPORT __declspec(dllimport)
293 #else
294 # define GD_IMPORT extern
295 #endif
297 
298 void gdgen_text(gdImagePtr im, pointf spf, pointf epf, int fontcolor, double fontsize, int fontdpi, double fontangle, char *fontname, char *str)
299 {
300  gdFTStringExtra strex;
301  point sp, ep; /* start point, end point, in pixels */
302 
303  PF2P(spf, sp);
304  PF2P(epf, ep);
305 
306  strex.flags = gdFTEX_RESOLUTION;
307  strex.hdpi = strex.vdpi = fontdpi;
308 
309  if (strstr(fontname, "/"))
310  strex.flags |= gdFTEX_FONTPATHNAME;
311  else
312  strex.flags |= gdFTEX_FONTCONFIG;
313 
314  if (fontsize <= FONTSIZE_MUCH_TOO_SMALL) {
315  /* ignore entirely */
316  } else if (fontsize <= FONTSIZE_TOO_SMALL) {
317  /* draw line in place of text */
318  gdImageLine(im, sp.x, sp.y, ep.x, ep.y, fontcolor);
319  } else {
320 #ifdef HAVE_GD_FREETYPE
321  char *err;
322  int brect[8];
323 #ifdef HAVE_GD_FONTCONFIG
324  char* fontlist = fontname;
325 #else
326  extern char *gd_alternate_fontlist(char *font);
327  char* fontlist = gd_alternate_fontlist(fontname);
328 #endif
329  err = gdImageStringFTEx(im, brect, fontcolor,
330  fontlist, fontsize, fontangle, sp.x, sp.y, str, &strex);
331 
332  if (err) {
333  /* revert to builtin fonts */
334  gdgen_missingfont(err, fontname);
335 #endif
336  sp.y += 2;
337  if (fontsize <= 8.5) {
338  gdImageString(im, gdFontTiny, sp.x, sp.y - 9, (unsigned char*)str, fontcolor);
339  } else if (fontsize <= 9.5) {
340  gdImageString(im, gdFontSmall, sp.x, sp.y - 12, (unsigned char*)str, fontcolor);
341  } else if (fontsize <= 10.5) {
342  gdImageString(im, gdFontMediumBold, sp.x, sp.y - 13, (unsigned char*)str, fontcolor);
343  } else if (fontsize <= 11.5) {
344  gdImageString(im, gdFontLarge, sp.x, sp.y - 14, (unsigned char*)str, fontcolor);
345  } else {
346  gdImageString(im, gdFontGiant, sp.x, sp.y - 15, (unsigned char*)str, fontcolor);
347  }
348 #ifdef HAVE_GD_FREETYPE
349  }
350 #endif
351  }
352 }
353 
354 extern char* gd_psfontResolve (PostscriptAlias* pa);
355 
356 static void gdgen_textspan(GVJ_t * job, pointf p, textspan_t * span)
357 {
358  gdImagePtr im = (gdImagePtr) job->context;
359  pointf spf, epf;
360  double spanwidth = span->size.x * job->zoom * job->dpi.x / POINTS_PER_INCH;
361  char* fontname;
362 #ifdef HAVE_GD_FONTCONFIG
363  PostscriptAlias *pA;
364 #endif
365 
366  if (!im)
367  return;
368 
369  switch (span->just) {
370  case 'l':
371  spf.x = 0.0;
372  break;
373  case 'r':
374  spf.x = -spanwidth;
375  break;
376  default:
377  case 'n':
378  spf.x = -spanwidth / 2;
379  break;
380  }
381  epf.x = spf.x + spanwidth;
382 
383  if (job->rotation) {
384  spf.y = -spf.x + p.y;
385  epf.y = epf.x + p.y;
386  epf.x = spf.x = p.x;
387  }
388  else {
389  spf.x += p.x;
390  epf.x += p.x;
391  epf.y = spf.y = p.y - span->yoffset_centerline * job->zoom * job->dpi.x / POINTS_PER_INCH;
392  }
393 
394 #ifdef HAVE_GD_FONTCONFIG
395  pA = span->font->postscript_alias;
396  if (pA)
397  fontname = gd_psfontResolve (pA);
398  else
399 #endif
400  fontname = span->font->name;
401 
402  gdgen_text(im, spf, epf,
403  job->obj->pencolor.u.index,
404  span->font->size * job->zoom,
405  job->dpi.x,
406  job->rotation ? (M_PI / 2) : 0,
407  fontname,
408  span->str);
409 }
410 
411 static int gdgen_set_penstyle(GVJ_t * job, gdImagePtr im, gdImagePtr* brush)
412 {
413  obj_state_t *obj = job->obj;
414  int i, pen, width, dashstyle[40];
415 
416  if (obj->pen == PEN_DASHED) {
417  for (i = 0; i < 10; i++)
418  dashstyle[i] = obj->pencolor.u.index;
419  for (; i < 20; i++)
420  dashstyle[i] = gdTransparent;
421  gdImageSetStyle(im, dashstyle, 20);
422  pen = gdStyled;
423  } else if (obj->pen == PEN_DOTTED) {
424  for (i = 0; i < 2; i++)
425  dashstyle[i] = obj->pencolor.u.index;
426  for (; i < 14; i++)
427  dashstyle[i] = gdTransparent;
428  gdImageSetStyle(im, dashstyle, 12);
429  pen = gdStyled;
430  } else {
431  pen = obj->pencolor.u.index;
432  }
433 
434  width = obj->penwidth * job->zoom;
435  if (width < PENWIDTH_NORMAL)
436  width = PENWIDTH_NORMAL; /* gd can't do thin lines */
437  gdImageSetThickness(im, width);
438  /* use brush instead of Thickness to improve end butts */
439  if (width != PENWIDTH_NORMAL) {
440  if (im->trueColor) {
441  *brush = gdImageCreateTrueColor(width,width);
442  }
443  else {
444  *brush = gdImageCreate(width, width);
445  gdImagePaletteCopy(*brush, im);
446  }
447  gdImageFilledRectangle(*brush, 0, 0, width - 1, width - 1,
448  obj->pencolor.u.index);
449  gdImageSetBrush(im, *brush);
450  if (pen == gdStyled)
451  pen = gdStyledBrushed;
452  else
453  pen = gdBrushed;
454  }
455 
456  return pen;
457 }
458 
459 static void
460 gdgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
461  int arrow_at_end, int filled)
462 {
463  obj_state_t *obj = job->obj;
464  gdImagePtr im = (gdImagePtr) job->context;
465  pointf p0, p1, V[4];
466  int i, j, step, pen;
467  boolean pen_ok, fill_ok;
468  gdImagePtr brush = NULL;
469  gdPoint F[4];
470 
471  if (!im)
472  return;
473 
474  pen = gdgen_set_penstyle(job, im, &brush);
475  pen_ok = (pen != gdImageGetTransparent(im));
476  fill_ok = (filled && obj->fillcolor.u.index != gdImageGetTransparent(im));
477 
478  if (pen_ok || fill_ok) {
479  V[3] = A[0];
480  PF2P(A[0], F[0]);
481  PF2P(A[n-1], F[3]);
482  for (i = 0; i + 3 < n; i += 3) {
483  V[0] = V[3];
484  for (j = 1; j <= 3; j++)
485  V[j] = A[i + j];
486  p0 = V[0];
487  for (step = 1; step <= BEZIERSUBDIVISION; step++) {
488  p1 = Bezier(V, 3, (double) step / BEZIERSUBDIVISION, NULL, NULL);
489  PF2P(p0, F[1]);
490  PF2P(p1, F[2]);
491  if (pen_ok)
492  gdImageLine(im, F[1].x, F[1].y, F[2].x, F[2].y, pen);
493  if (fill_ok)
494  gdImageFilledPolygon(im, F, 4, obj->fillcolor.u.index);
495  p0 = p1;
496  }
497  }
498  }
499  if (brush)
500  gdImageDestroy(brush);
501 }
502 
503 static gdPoint *points;
504 static int points_allocated;
505 
506 static void gdgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
507 {
508  obj_state_t *obj = job->obj;
509  gdImagePtr im = (gdImagePtr) job->context;
510  gdImagePtr brush = NULL;
511  int i;
512  int pen;
513  boolean pen_ok, fill_ok;
514 
515  if (!im)
516  return;
517 
518  pen = gdgen_set_penstyle(job, im, &brush);
519  pen_ok = (pen != gdImageGetTransparent(im));
520  fill_ok = (filled && obj->fillcolor.u.index != gdImageGetTransparent(im));
521 
522  if (pen_ok || fill_ok) {
523  if (n > points_allocated) {
524  points = realloc(points, n * sizeof(gdPoint));
525  points_allocated = n;
526  }
527  for (i = 0; i < n; i++) {
528  points[i].x = ROUND(A[i].x);
529  points[i].y = ROUND(A[i].y);
530  }
531  if (fill_ok)
532  gdImageFilledPolygon(im, points, n, obj->fillcolor.u.index);
533 
534  if (pen_ok)
535  gdImagePolygon(im, points, n, pen);
536  }
537  if (brush)
538  gdImageDestroy(brush);
539 }
540 
541 static void gdgen_ellipse(GVJ_t * job, pointf * A, int filled)
542 {
543  obj_state_t *obj = job->obj;
544  gdImagePtr im = (gdImagePtr) job->context;
545  double dx, dy;
546  int pen;
547  boolean pen_ok, fill_ok;
548  gdImagePtr brush = NULL;
549 
550  if (!im)
551  return;
552 
553  pen = gdgen_set_penstyle(job, im, &brush);
554  pen_ok = (pen != gdImageGetTransparent(im));
555  fill_ok = (filled && obj->fillcolor.u.index != gdImageGetTransparent(im));
556 
557  dx = 2 * (A[1].x - A[0].x);
558  dy = 2 * (A[1].y - A[0].y);
559 
560  if (fill_ok)
561  gdImageFilledEllipse(im, ROUND(A[0].x), ROUND(A[0].y),
562  ROUND(dx), ROUND(dy),
563  obj->fillcolor.u.index);
564  if (pen_ok)
565  gdImageArc(im, ROUND(A[0].x), ROUND(A[0].y), ROUND(dx), ROUND(dy),
566  0, 360, pen);
567  if (brush)
568  gdImageDestroy(brush);
569 }
570 
571 static void gdgen_polyline(GVJ_t * job, pointf * A, int n)
572 {
573  gdImagePtr im = (gdImagePtr) job->context;
574  pointf p, p1;
575  int i;
576  int pen;
577  boolean pen_ok;
578  gdImagePtr brush = NULL;
579 
580  if (!im)
581  return;
582 
583  pen = gdgen_set_penstyle(job, im, &brush);
584  pen_ok = (pen != gdImageGetTransparent(im));
585 
586  if (pen_ok) {
587  p = A[0];
588  for (i = 1; i < n; i++) {
589  p1 = A[i];
590  gdImageLine(im, ROUND(p.x), ROUND(p.y),
591  ROUND(p1.x), ROUND(p1.y), pen);
592  p = p1;
593  }
594  }
595  if (brush)
596  gdImageDestroy(brush);
597 }
598 
599 static gvrender_engine_t gdgen_engine = {
600  0, /* gdgen_begin_job */
601  0, /* gdgen_end_job */
602  0, /* gdgen_begin_graph */
603  0, /* gdgen_end_graph */
604  0, /* gdgen_begin_layer */
605  0, /* gdgen_end_layer */
606  gdgen_begin_page,
607  gdgen_end_page,
608  0, /* gdgen_begin_cluster */
609  0, /* gdgen_end_cluster */
610  0, /* gdgen_begin_nodes */
611  0, /* gdgen_end_nodes */
612  0, /* gdgen_begin_edges */
613  0, /* gdgen_end_edges */
614  0, /* gdgen_begin_node */
615  0, /* gdgen_end_node */
616  0, /* gdgen_begin_edge */
617  0, /* gdgen_end_edge */
618  0, /* gdgen_begin_anchor */
619  0, /* gdgen_end_anchor */
620  0, /* gdgen_begin_label */
621  0, /* gdgen_end_label */
622  gdgen_textspan,
623  gdgen_resolve_color,
624  gdgen_ellipse,
625  gdgen_polygon,
626  gdgen_bezier,
627  gdgen_polyline,
628  0, /* gdgen_comment */
629  0, /* gdgen_library_shape */
630 };
631 
632 static gvrender_features_t render_features_gd = {
633  GVRENDER_Y_GOES_DOWN, /* flags */
634  4., /* default pad - graph units */
635  NULL, /* knowncolors */
636  0, /* sizeof knowncolors */
637  RGBA_BYTE, /* color_type */
638 };
639 
640 static gvdevice_features_t device_features_gd = {
641  GVDEVICE_BINARY_FORMAT, /* flags */
642  {0.,0.}, /* default margin - points */
643  {0.,0.}, /* default page width, height - points */
644  {96.,96.}, /* default dpi */
645 };
646 
647 static gvdevice_features_t device_features_gd_tc = {
649  | GVDEVICE_DOES_TRUECOLOR,/* flags */
650  {0.,0.}, /* default margin - points */
651  {0.,0.}, /* default page width, height - points */
652  {96.,96.}, /* default dpi */
653 };
654 
655 static gvdevice_features_t device_features_gd_tc_no_writer = {
658  | GVDEVICE_NO_WRITER, /* flags */
659  {0.,0.}, /* default margin - points */
660  {0.,0.}, /* default page width, height - points */
661  {96.,96.}, /* default dpi */
662 };
663 
665  {FORMAT_GD, "gd", 1, &gdgen_engine, &render_features_gd},
666  {0, NULL, 0, NULL, NULL}
667 };
668 
670 #ifdef HAVE_GD_GIF
671  {FORMAT_GIF, "gif:gd", 1, NULL, &device_features_gd_tc}, /* pretend gif is truecolor because it supports transparency */
672  {FORMAT_WBMP, "wbmp:gd", 1, NULL, &device_features_gd},
673 #endif
674 
675 #ifdef HAVE_GD_JPEG
676  {FORMAT_JPEG, "jpe:gd", 1, NULL, &device_features_gd},
677  {FORMAT_JPEG, "jpeg:gd", 1, NULL, &device_features_gd},
678  {FORMAT_JPEG, "jpg:gd", 1, NULL, &device_features_gd},
679 #endif
680 
681 #ifdef HAVE_GD_PNG
682  {FORMAT_PNG, "png:gd", 1, NULL, &device_features_gd_tc},
683 #endif
684 
685  {FORMAT_GD, "gd:gd", 1, NULL, &device_features_gd_tc_no_writer},
686 
687 #ifdef HAVE_LIBZ
688  {FORMAT_GD2, "gd2:gd", 1, NULL, &device_features_gd_tc_no_writer},
689 #endif
690 
691 #if 0
692 /* libgd has no support for xbm as output */
693 #ifdef HAVE_GD_XPM
694  {FORMAT_XBM, "xbm:gd", 1, NULL, &device_features_gd},
695 #endif
696 #endif
697  {0, NULL, 0, NULL, NULL}
698 };
#define PENWIDTH_NORMAL
Definition: gvcjob.h:40
pointf size
Definition: textspan.h:64
Definition: cgraph.h:388
int rotation
Definition: gvcjob.h:328
union color_s::@10 u
void gdgen_text(gdImagePtr im, pointf spf, pointf epf, int fontcolor, double fontsize, int fontdpi, double fontangle, char *fontname, char *str)
Definition: gvrender_gd.c:298
#define FONTSIZE_MUCH_TOO_SMALL
Definition: gvrender_gd.c:287
GD_IMPORT gdFontPtr gdFontSmall
Definition: gvrender_gd.c:296
#define GVDEVICE_BINARY_FORMAT
Definition: gvcjob.h:93
void * context
Definition: gvcjob.h:304
pen_type pen
Definition: gvcjob.h:206
int index
Definition: color.h:42
double size
Definition: textspan.h:52
#define C
Definition: pack.c:29
#define ROUND(f)
Definition: arith.h:84
Definition: geom.h:28
#define PF2P(pf, p)
Definition: geom.h:72
char * gd_psfontResolve(PostscriptAlias *pa)
unsigned int width
Definition: gvcjob.h:336
gvplugin_installed_t gvdevice_gd_types2[]
Definition: gvrender_gd.c:669
GD_IMPORT gdFontPtr gdFontMediumBold
Definition: gvrender_gd.c:296
graph_t * g
Definition: gvcint.h:106
Definition: color.h:34
int agerr(agerrlevel_t level, const char *fmt,...)
Definition: agerror.c:141
gvcolor_t pencolor
Definition: gvcjob.h:203
Definition: gvcjob.h:271
char * name
Definition: textspan.h:49
int x
Definition: geom.h:26
char * cmdname
Definition: gvcommon.h:23
#define POINTS_PER_INCH
Definition: geom.h:62
Definition: cgraph.h:388
obj_state_t * obj
Definition: gvcjob.h:278
char * agget(void *obj, char *name)
Definition: attr.c:428
#define GVRENDER_Y_GOES_DOWN
Definition: gvcjob.h:96
#define GVDEVICE_NO_WRITER
Definition: gvcjob.h:95
pointf dpi
Definition: gvcjob.h:334
char * str
Definition: textspan.h:59
color_type_t type
Definition: color.h:44
gvplugin_active_render_t render
Definition: gvcjob.h:294
gvrender_features_t * features
Definition: gvcjob.h:140
double y
Definition: geom.h:28
gvplugin_installed_t gvrender_gd_types[]
Definition: gvrender_gd.c:664
GVCOMMON_t * common
Definition: gvcjob.h:276
double yoffset_centerline
Definition: textspan.h:63
PostscriptAlias * postscript_alias
Definition: textspan.h:51
GVC_t * gvc
Definition: gvcjob.h:272
#define GD_IMPORT
Definition: gvrender_gd.c:294
GD_IMPORT gdFontPtr gdFontGiant
Definition: gvrender_gd.c:296
if(aagss+aagstacksize-1<=aagssp)
Definition: grammar.c:1332
void(* errorfn)(const char *fmt,...)
Definition: gvcommon.h:26
format_type
int verbose
Definition: gvcommon.h:24
pointf Bezier(pointf *V, int degree, double t, pointf *Left, pointf *Right)
Definition: utils.c:221
#define NULL
Definition: logic.h:39
#define GD_XYMAX
Definition: gvrender_gd.c:74
Definition: geom.h:26
double x
Definition: geom.h:28
GD_IMPORT gdFontPtr gdFontTiny
Definition: gvrender_gd.c:296
void gvdevice_gd_putC(gdIOCtx *context, int C)
Definition: gvdevice_gd.c:27
boolean external_context
Definition: gvcjob.h:305
for(;;)
Definition: grammar.c:1846
char just
Definition: textspan.h:65
boolean mapbool(char *p)
Definition: utils.c:472
#define alpha
Definition: shapes.c:3902
#define BEZIERSUBDIVISION
Definition: gvrender_gd.c:48
GD_IMPORT gdFontPtr gdFontLarge
Definition: gvrender_gd.c:296
int gvdevice_gd_putBuf(gdIOCtx *context, const void *buffer, int len)
Definition: gvdevice_gd.c:21
#define M_PI
Definition: arith.h:77
agxbuf * str
Definition: htmlparse.c:85
#define GD_has_images(g)
Definition: types.h:373
gvcolor_t fillcolor
Definition: gvcjob.h:203
double penwidth
Definition: gvcjob.h:208
int y
Definition: geom.h:26
unsigned char rgba[4]
Definition: color.h:38
FILE * output_file
Definition: gvcjob.h:286
double zoom
Definition: gvcjob.h:327
unsigned int height
Definition: gvcjob.h:337
#define FALSE
Definition: cgraph.h:35
#define FONTSIZE_TOO_SMALL
Definition: gvrender_gd.c:289
#define GVDEVICE_DOES_TRUECOLOR
Definition: gvcjob.h:92
textfont_t * font
Definition: textspan.h:60
#define TRUE
Definition: cgraph.h:38