Graphviz 13.0.0~dev.20250210.0415
Loading...
Searching...
No Matches
gvloadimage_core.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
13#include <stdbool.h>
14#include <stdlib.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#ifdef HAVE_SYS_MMAN_H
18#include <sys/mman.h>
19#endif
20
22#include <common/utils.h>
23#include <gvc/gvio.h>
24#include "core_loadimage_xdot.h"
25#include "gvrender_core_svg.h"
26#include <util/agxbuf.h>
27#include <util/base64.h>
28
29extern shape_desc *find_user_shape(char *name);
30
31enum {
40};
41
44static const char *mime_type(imagetype_t file_type) {
45
46 if (file_type == FT_BMP) {
47 return "image/bmp";
48 }
49
50 if (file_type == FT_GIF) {
51 return "image/gif";
52 }
53
54 if (file_type == FT_PNG) {
55 return "image/png";
56 }
57
58 if (file_type == FT_JPEG) {
59 return "image/jpeg";
60 }
61
62 if (file_type == FT_PDF) {
63 return "application/pdf";
64 }
65
66 if (file_type == FT_PS || file_type == FT_EPS) {
67 return "application/postscript";
68 }
69
70 if (file_type == FT_SVG) {
71 return "image/svg+xml";
72 }
73
74 if (file_type == FT_XML) {
75 return "application/xml";
76 }
77
78 if (file_type == FT_WEBP) {
79 return "image/webp";
80 }
81
82 if (file_type == FT_TIFF) {
83 return "image/tiff";
84 }
85
86 // other types do not have a corresponding MIME type and so cannot be encoded
87 return NULL;
88}
89
90static void core_loadimage_svg(GVJ_t * job, usershape_t *us, boxf b, bool filled)
91{
92 (void)filled;
93
94 double width = (b.UR.x-b.LL.x);
95 double height = (b.UR.y-b.LL.y);
96 double originx = (b.UR.x+b.LL.x - width)/2;
97 double originy = (b.UR.y+b.LL.y + height)/2;
98 assert(job);
99 assert(us);
100 assert(us->name);
101
102 gvputs(job, "<image xlink:href=\"");
103
104 bool written = false;
105 const char *const mime = mime_type(us->type);
106 // OK to use SVG renderer’s constant `FORMAT_SVG_INLINE` here because we
107 // know we are using the SVG renderer if we reached this point
108 if (job->render.id == FORMAT_SVG_INLINE && mime != NULL &&
110
111 // give us a scope to be able to bail out midway
112 do {
113
114 // load the included image’s data
115 const int fd = fileno(us->f);
116 struct stat st;
117 if (fstat(fd, &st) < 0) {
118 break;
119 }
120 us->datasize = (size_t)st.st_size;
121#ifdef HAVE_SYS_MMAN_H
122 us->data = mmap(0, us->datasize, PROT_READ, MAP_PRIVATE, fd, 0);
123 if (us->data == MAP_FAILED) {
124 us->data = NULL;
125 break;
126 }
127#else
128 us->data = malloc(us->datasize);
129 if (us->datasize > 0 && us->data == NULL) {
130 break;
131 }
132 if (fread(us->data, us->datasize, 1, us->f) != 1) {
133 free(us->data);
134 us->data = NULL;
135 break;
136 }
137#endif
138 const size_t encoded_size = gv_base64_size(us->datasize);
139 char *const encoded = gv_base64(us->data, us->datasize);
140#ifdef HAVE_SYS_MMAN_H
141 munmap(us->data, us->datasize);
142#else
143 free(us->data);
144#endif
145 us->data = NULL;
146
147 gvprintf(job, "data:%s;base64,%.*s", mime, (int)encoded_size,
148 encoded);
149 free(encoded);
150
151 written = true;
152 } while (0);
153
155 }
156
157 if (!written) { // fallback to an external reference
158 gvputs(job, us->name);
159 }
160 if (job->rotation) {
161
162// FIXME - this is messed up >>>
163 gvprintf (job, "\" width=\"%gpx\" height=\"%gpx\" preserveAspectRatio=\"xMidYMid meet\" x=\"%g\" y=\"%g\"",
164 height, width, originx, -originy);
165 gvprintf (job, " transform=\"rotate(%d %g %g)\"",
166 job->rotation, originx, -originy);
167// <<<
168 }
169 else {
170 gvprintf (job, "\" width=\"%gpx\" height=\"%gpx\" preserveAspectRatio=\"xMinYMin meet\" x=\"%g\" y=\"%g\"",
171 width, height, originx, -originy);
172 }
173 gvputs(job, "/>\n");
174}
175
176static void core_loadimage_fig(GVJ_t * job, usershape_t *us, boxf bf, bool filled)
177{
178 (void)filled;
179
180 int object_code = 2; /* always 2 for polyline */
181 int sub_type = 5; /* always 5 for image */
182 int line_style = 0; /* solid, dotted, dashed */
183 int thickness = 0;
184 int pen_color = 0;
185 int fill_color = -1;
186 int depth = 1;
187 int pen_style = -1; /* not used */
188 int area_fill = 0;
189 double style_val = 0.0;
190 int join_style = 0;
191 int cap_style = 0;
192 int radius = 0;
193 int forward_arrow = 0;
194 int backward_arrow = 0;
195 int npoints = 5;
196 int flipped = 0;
197
198 assert(job);
199 assert(us);
200 assert(us->name);
201
202 gvprintf(job, "%d %d %d %d %d %d %d %d %d %.1f %d %d %d %d %d %d\n %d %s\n",
203 object_code, sub_type, line_style, thickness, pen_color,
204 fill_color, depth, pen_style, area_fill, style_val, join_style,
205 cap_style, radius, forward_arrow, backward_arrow, npoints,
206 flipped, us->name);
207 gvprintf(job," %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f\n",
208 bf.LL.x, bf.LL.y,
209 bf.LL.x, bf.UR.y,
210 bf.UR.x, bf.UR.y,
211 bf.UR.x, bf.LL.y,
212 bf.LL.x, bf.LL.y);
213}
214
215static void core_loadimage_vrml(GVJ_t * job, usershape_t *us, boxf b, bool filled)
216{
217 (void)b;
218 (void)filled;
219
220 assert(job);
221 assert(job->obj);
222 assert(us);
223 assert(us->name);
224
225 assert(job->obj->u.n);
226
227 gvprintf(job, "Shape {\n");
228 gvprintf(job, " appearance Appearance {\n");
229 gvprintf(job, " material Material {\n");
230 gvprintf(job, " ambientIntensity 0.33\n");
231 gvprintf(job, " diffuseColor 1 1 1\n");
232 gvprintf(job, " }\n");
233 gvprintf(job, " texture ImageTexture { url \"%s\" }\n", us->name);
234 gvprintf(job, " }\n");
235 gvprintf(job, "}\n");
236}
237
238static void ps_freeimage(usershape_t *us)
239{
240#ifdef HAVE_SYS_MMAN_H
241 munmap(us->data, us->datasize);
242#else
243 free(us->data);
244#endif
245}
246
247/* usershape described by a postscript file */
248static void core_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, bool filled)
249{
250 (void)filled;
251
252 assert(job);
253 assert(us);
254 assert(us->name);
255
256 if (us->data) {
257 if (us->datafree != ps_freeimage) {
258 us->datafree(us); /* free incompatible cache data */
259 us->data = NULL;
260 us->datafree = NULL;
261 us->datasize = 0;
262 }
263 }
264
265 if (!us->data) { /* read file into cache */
266 int fd;
267 struct stat statbuf;
268
270 return;
271 fd = fileno(us->f);
272 switch (us->type) {
273 case FT_PS:
274 case FT_EPS:
275 fstat(fd, &statbuf);
276 us->datasize = (size_t)statbuf.st_size;
277#ifdef HAVE_SYS_MMAN_H
278 us->data = mmap(0, us->datasize, PROT_READ, MAP_PRIVATE, fd, 0);
279 if (us->data == MAP_FAILED)
280 us->data = NULL;
281#else
282 us->data = malloc(statbuf.st_size);
283 if (us->data != NULL)
284 read(fd, us->data, statbuf.st_size);
285#endif
286 us->must_inline = true;
287 break;
288 default:
289 break;
290 }
291 if (us->data)
294 }
295
296 if (us->data) {
297 gvprintf(job, "gsave %g %g translate newpath\n",
298 b.LL.x - (double)(us->x), b.LL.y - (double)(us->y));
299 if (us->must_inline)
300 epsf_emit_body(job, us);
301 else
302 gvprintf(job, "user_shape_%d\n", us->macro_id);
303 gvprintf(job, "grestore\n");
304 }
305}
306
307/* usershape described by a member of a postscript library */
308static void core_loadimage_pslib(GVJ_t * job, usershape_t *us, boxf b, bool filled)
309{
310 int i;
311 pointf AF[4];
312 shape_desc *shape;
313
314 assert(job);
315 assert(us);
316 assert(us->name);
317
318 if ((shape = us->data)) {
319 AF[0] = b.LL;
320 AF[2] = b.UR;
321 AF[1].x = AF[0].x;
322 AF[1].y = AF[2].y;
323 AF[3].x = AF[2].x;
324 AF[3].y = AF[0].y;
325 if (filled) {
326 gvprintf(job, "[ ");
327 for (i = 0; i < 4; i++)
328 gvprintf(job, "%g %g ", AF[i].x, AF[i].y);
329 gvprintf(job, "%g %g ", AF[0].x, AF[0].y);
330 gvprintf(job, "] %d true %s\n", 4, us->name);
331 }
332 gvprintf(job, "[ ");
333 for (i = 0; i < 4; i++)
334 gvprintf(job, "%g %g ", AF[i].x, AF[i].y);
335 gvprintf(job, "%g %g ", AF[0].x, AF[0].y);
336 gvprintf(job, "] %d false %s\n", 4, us->name);
337 }
338}
339
340static void core_loadimage_tk(GVJ_t * job, usershape_t *us, boxf b, bool filled)
341{
342 (void)filled;
343
344 gvprintf (job, "image create photo \"photo_%s\" -file \"%s\"\n",
345 us->name, us->name);
346 gvprintf (job, "$c create image %.2f %.2f -image \"photo_%s\"\n",
347 (b.UR.x + b.LL.x) / 2, (b.UR.y + b.LL.y) / 2, us->name);
348}
349
350static void core_loadimage_null(GVJ_t *gvc, usershape_t *us, boxf b, bool filled)
351{
352 /* null function - basically suppress the missing loader message */
353 (void)gvc;
354 (void)us;
355 (void)b;
356 (void)filled;
357}
358
362
366
370
374
378
382
386
390
392 {FORMAT_PNG_SVG, "png:svg", 1, &engine_svg, NULL},
393 {FORMAT_GIF_SVG, "gif:svg", 1, &engine_svg, NULL},
394 {FORMAT_JPEG_SVG, "jpeg:svg", 1, &engine_svg, NULL},
395 {FORMAT_JPEG_SVG, "jpe:svg", 1, &engine_svg, NULL},
396 {FORMAT_JPEG_SVG, "jpg:svg", 1, &engine_svg, NULL},
397
398 {FORMAT_PNG_FIG, "png:fig", 1, &engine_fig, NULL},
399 {FORMAT_GIF_FIG, "gif:fig", 1, &engine_fig, NULL},
400 {FORMAT_JPEG_FIG, "jpeg:fig", 1, &engine_fig, NULL},
401 {FORMAT_JPEG_FIG, "jpe:fig", 1, &engine_fig, NULL},
402 {FORMAT_JPEG_FIG, "jpg:fig", 1, &engine_fig, NULL},
403
404 {FORMAT_PNG_VRML, "png:vrml", 1, &engine_vrml, NULL},
405 {FORMAT_GIF_VRML, "gif:vrml", 1, &engine_vrml, NULL},
406 {FORMAT_JPEG_VRML, "jpeg:vrml", 1, &engine_vrml, NULL},
407 {FORMAT_JPEG_VRML, "jpe:vrml", 1, &engine_vrml, NULL},
408 {FORMAT_JPEG_VRML, "jpg:vrml", 1, &engine_vrml, NULL},
409
410 {FORMAT_PS_PS, "eps:ps", 1, &engine_ps, NULL},
411 {FORMAT_PS_PS, "ps:ps", 1, &engine_ps, NULL},
412 {FORMAT_PSLIB_PS, "(lib):ps", 1, &engine_pslib, NULL}, /* for pslib */
413
414 {FORMAT_PNG_MAP, "png:map", 1, &engine_null, NULL},
415 {FORMAT_GIF_MAP, "gif:map", 1, &engine_null, NULL},
416 {FORMAT_JPEG_MAP, "jpeg:map", 1, &engine_null, NULL},
417 {FORMAT_JPEG_MAP, "jpe:map", 1, &engine_null, NULL},
418 {FORMAT_JPEG_MAP, "jpg:map", 1, &engine_null, NULL},
419 {FORMAT_PS_MAP, "ps:map", 1, &engine_null, NULL},
420 {FORMAT_PS_MAP, "eps:map", 1, &engine_null, NULL},
421 {FORMAT_SVG_MAP, "svg:map", 1, &engine_null, NULL},
422
423 {FORMAT_PNG_DOT, "png:dot", 1, &engine_null, NULL},
424 {FORMAT_GIF_DOT, "gif:dot", 1, &engine_null, NULL},
425 {FORMAT_JPEG_DOT, "jpeg:dot", 1, &engine_null, NULL},
426 {FORMAT_JPEG_DOT, "jpe:dot", 1, &engine_null, NULL},
427 {FORMAT_JPEG_DOT, "jpg:dot", 1, &engine_null, NULL},
428 {FORMAT_PS_DOT, "ps:dot", 1, &engine_null, NULL},
429 {FORMAT_PS_DOT, "eps:dot", 1, &engine_null, NULL},
430 {FORMAT_SVG_DOT, "svg:dot", 1, &engine_null, NULL},
431
432 {FORMAT_PNG_XDOT, "png:xdot", 1, &engine_xdot, NULL},
433 {FORMAT_GIF_XDOT, "gif:xdot", 1, &engine_xdot, NULL},
434 {FORMAT_JPEG_XDOT, "jpeg:xdot", 1, &engine_xdot, NULL},
435 {FORMAT_JPEG_XDOT, "jpe:xdot", 1, &engine_xdot, NULL},
436 {FORMAT_JPEG_XDOT, "jpg:xdot", 1, &engine_xdot, NULL},
437 {FORMAT_PS_XDOT, "ps:xdot", 1, &engine_xdot, NULL},
438 {FORMAT_PS_XDOT, "eps:xdot", 1, &engine_xdot, NULL},
439 {FORMAT_SVG_XDOT, "svg:xdot", 1, &engine_xdot, NULL},
440
441 {FORMAT_SVG_SVG, "svg:svg", 1, &engine_svg, NULL},
442
443 {FORMAT_GIF_TK, "gif:tk", 1, &engine_tk, NULL},
444
445 {0, NULL, 0, NULL, NULL}
446};
char * gv_base64(const unsigned char *source, size_t size)
Definition base64.c:14
size_t gv_base64_size(size_t source_size)
Definition base64.c:12
Base64 encoding.
void core_loadimage_xdot(GVJ_t *, usershape_t *, boxf, bool)
void * malloc(YYSIZE_T)
void free(void *)
node NULL
Definition grammar.y:163
void gvusershape_file_release(usershape_t *us)
bool gvusershape_file_access(usershape_t *us)
Agraph_t * read(FILE *f)
Definition gv.cpp:60
static GVC_t * gvc
Definition gv.cpp:23
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:264
void gvprintf(GVJ_t *job, const char *format,...)
Definition gvdevice.c:395
static void core_loadimage_ps(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static gvloadimage_engine_t engine_ps
static void core_loadimage_pslib(GVJ_t *job, usershape_t *us, boxf b, bool filled)
@ FORMAT_SVG_XDOT
@ FORMAT_PS_MAP
@ FORMAT_GIF_FIG
@ FORMAT_JPEG_SVG
@ FORMAT_PNG_SVG
@ FORMAT_PNG_DOT
@ FORMAT_GIF_MAP
@ FORMAT_SVG_SVG
@ FORMAT_PNG_VRML
@ FORMAT_PS_DOT
@ FORMAT_GIF_XDOT
@ FORMAT_SVG_MAP
@ FORMAT_JPEG_MAP
@ FORMAT_GIF_SVG
@ FORMAT_GIF_DOT
@ FORMAT_PSLIB_PS
@ FORMAT_JPEG_DOT
@ FORMAT_GIF_VRML
@ FORMAT_SVG_DOT
@ FORMAT_PNG_MAP
@ FORMAT_PS_XDOT
@ FORMAT_PNG_FIG
@ FORMAT_JPEG_FIG
@ FORMAT_JPEG_VRML
@ FORMAT_JPEG_XDOT
@ FORMAT_GIF_TK
@ FORMAT_PNG_XDOT
@ FORMAT_PS_PS
static gvloadimage_engine_t engine_null
static gvloadimage_engine_t engine_pslib
static void ps_freeimage(usershape_t *us)
static void core_loadimage_svg(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static gvloadimage_engine_t engine_svg
static gvloadimage_engine_t engine_vrml
static gvloadimage_engine_t engine_xdot
static void core_loadimage_fig(GVJ_t *job, usershape_t *us, boxf bf, bool filled)
static gvloadimage_engine_t engine_fig
gvplugin_installed_t gvloadimage_core_types[]
static void core_loadimage_tk(GVJ_t *job, usershape_t *us, boxf b, bool filled)
shape_desc * find_user_shape(char *name)
static gvloadimage_engine_t engine_tk
static void core_loadimage_null(GVJ_t *gvc, usershape_t *us, boxf b, bool filled)
static const char * mime_type(imagetype_t file_type)
static void core_loadimage_vrml(GVJ_t *job, usershape_t *us, boxf b, bool filled)
@ FORMAT_SVG_INLINE
void epsf_emit_body(GVJ_t *job, usershape_t *us)
int rotation
Definition gvcjob.h:319
obj_state_t * obj
Definition gvcjob.h:269
gvplugin_active_render_t render
Definition gvcjob.h:285
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
ingroup plugin_api
Definition gvplugin.h:35
union obj_state_s::@89 u
node_t * n
Definition gvcjob.h:188
double x
Definition geom.h:29
double y
Definition geom.h:29
const char * name
Definition usershape.h:54
FILE * f
Definition usershape.h:58
void(* datafree)(usershape_t *us)
Definition usershape.h:65
size_t datasize
Definition usershape.h:64
bool must_inline
Definition usershape.h:56
void * data
Definition usershape.h:63
imagetype_t type
Definition usershape.h:59
double x
Definition usershape.h:61
double y
Definition usershape.h:61
imagetype_t
Definition usershape.h:24
@ FT_BMP
Definition usershape.h:25
@ FT_PS
Definition usershape.h:26
@ FT_TIFF
Definition usershape.h:27
@ FT_EPS
Definition usershape.h:26
@ FT_SVG
Definition usershape.h:26
@ FT_WEBP
Definition usershape.h:27
@ FT_GIF
Definition usershape.h:25
@ FT_JPEG
Definition usershape.h:25
@ FT_PNG
Definition usershape.h:25
@ FT_XML
Definition usershape.h:26
@ FT_PDF
Definition usershape.h:26