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