Graphviz 13.0.0~dev.20250424.1043
Loading...
Searching...
No Matches
gvloadimage_gs.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 <assert.h>
13#include <stdbool.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <sys/stat.h>
17#include <util/agxbuf.h>
18
20
21#include <ghostscript/iapi.h>
22#include <ghostscript/ierrors.h>
23#include <cairo/cairo.h>
24
25
31#ifndef e_VMerror
32#define e_VMerror gs_error_VMerror
33#endif
34
35#ifndef e_unregistered
36#define e_unregistered gs_error_unregistered
37#endif
38
39#ifndef e_invalidid
40#define e_invalidid gs_error_invalidid
41#endif
42
43enum {
45};
46
47typedef struct gs_s {
48 cairo_t* cr;
49 cairo_surface_t* surface;
50 cairo_pattern_t* pattern;
52
54{
55 gs_t *gs = us->data;
56
57 if (gs->pattern) cairo_pattern_destroy(gs->pattern);
58 if (gs->surface) cairo_surface_destroy(gs->surface);
59 free(gs);
60}
61
62static int gs_writer(void *caller_handle, const char *str, int len)
63{
64 GVJ_t *job = caller_handle;
65
66 if (job->common->verbose) {
67 assert(len >= 0);
68 return (int)fwrite(str, 1, (size_t)len, stderr);
69 }
70 return len;
71}
72
73static void gs_error(GVJ_t * job, const char *name, const char *funstr, int err)
74{
75 const char *errsrc;
76
77 assert (err < 0);
78
79 if (err >= e_VMerror)
80 errsrc = "PostScript Level 1";
81 else if (err >= e_unregistered)
82 errsrc = "PostScript Level 2";
83 else if (err >= e_invalidid)
84 errsrc = "DPS error";
85 else
86 errsrc = "Ghostscript internal error";
87
88 job->common->errorfn("%s: %s() returned: %d (%s)\n",
89 name, funstr, err, errsrc);
90}
91
92static int gvloadimage_process_file(GVJ_t *job, usershape_t *us, void *instance)
93{
94 int rc = 0, exit_code;
95
96 if (! gvusershape_file_access(us)) {
97 job->common->errorfn("Failure to read shape file\n");
98 return -1;
99 }
100 rc = gsapi_run_file(instance, us->name, -1, &exit_code);
101 if (rc) {
102 gs_error(job, us->name, "gsapi_run_file", rc);
103 }
105 return rc;
106}
107
108static int gvloadimage_process_surface(GVJ_t *job, usershape_t *us, gs_t *gs, void *instance)
109{
110 cairo_t *cr; /* temp cr for gs */
111 int rc, rc2;
112 char *gs_args[] = {
113 "dot", /* actual value of argv[0] doesn't matter */
114 "-dQUIET",
115 "-dNOPAUSE",
116 "-sDEVICE=cairo",
117 NULL,
118 NULL,
119 NULL,
120 };
121#define GS_ARGC sizeof(gs_args)/sizeof(gs_args[0])
122
123 gs->surface = cairo_surface_create_similar(
124 cairo_get_target(gs->cr),
125 CAIRO_CONTENT_COLOR_ALPHA,
126 (int)(us->x + us->w),
127 (int)(us->y + us->h));
128
129 cr = cairo_create(gs->surface); /* temp context for gs */
130
131 agxbuf width_height = {0};
132 agxbprint(&width_height, "-g%0.fx%0.f", us->x + us->w, us->y + us->h);
133 gs_args[5] = agxbuse(&width_height);
134 agxbuf dpi = {0};
135 agxbprint(&dpi, "-r%d", us->dpi);
136 gs_args[6] = agxbuse(&dpi);
137 agxbuf cairo_context = {0};
138 agxbprint(&cairo_context, "-sCairoContext=%p", cr);
139 gs_args[4] = agxbuse(&cairo_context);
140
141 rc = gsapi_init_with_args(instance, GS_ARGC, gs_args);
142 agxbfree(&cairo_context);
143 agxbfree(&dpi);
144 agxbfree(&width_height);
145
146 cairo_destroy(cr); /* finished with temp context */
147
148 if (rc)
149 gs_error(job, us->name, "gsapi_init_with_args", rc);
150 else
151 rc = gvloadimage_process_file(job, us, instance);
152
153 if (rc) {
154 cairo_surface_destroy(gs->surface);
155 gs->surface = NULL;
156 }
157
158 rc2 = gsapi_exit(instance);
159 if (rc2) {
160 gs_error(job, us->name, "gsapi_exit", rc2);
161 return rc2;
162 }
163
164 if (!rc)
165 gs->pattern = cairo_pattern_create_for_surface (gs->surface);
166
167 return rc;
168}
169
170static cairo_pattern_t* gvloadimage_gs_load(GVJ_t * job, usershape_t *us)
171{
172 gs_t *gs = NULL;
173 gsapi_revision_t gsapi_revision_info;
174 void *instance;
175 int rc;
176
177 assert(job);
178 assert(us);
179 assert(us->name);
180
181 if (us->data) {
183 && ((gs_t*)(us->data))->cr == job->context)
184 gs = us->data; /* use cached data */
185 else {
186 us->datafree(us); /* free incompatible cache data */
187 us->data = NULL;
188 }
189 }
190 if (!gs) {
191 gs = malloc(sizeof(gs_t));
192 if (!gs) {
193 job->common->errorfn("malloc() failure\n");
194 return NULL;
195 }
196 gs->cr = job->context;
197 gs->surface = NULL;
198 gs->pattern = NULL;
199
200 /* cache this - even if things go bad below - avoids repeats */
201 us->data = gs;
203
204#define GSAPI_REVISION_REQUIRED 863
205 rc = gsapi_revision(&gsapi_revision_info, sizeof(gsapi_revision_t));
206 if (rc && rc < (int)sizeof(gsapi_revision_t)) {
207 job->common->errorfn("gs revision - struct too short %d\n", rc);
208 return NULL;
209 }
210 if (gsapi_revision_info.revision < GSAPI_REVISION_REQUIRED) {
211 job->common->errorfn("gs revision - too old %d\n",
212 gsapi_revision_info.revision);
213 return NULL;
214 }
215
216 rc = gsapi_new_instance(&instance, job);
217 if (rc)
218 gs_error(job, us->name, "gsapi_new_instance", rc);
219 else {
220 rc = gsapi_set_stdio(instance, NULL, gs_writer, gs_writer);
221 if (rc)
222 gs_error(job, us->name, "gsapi_set_stdio", rc);
223 else
224 rc = gvloadimage_process_surface(job, us, gs, instance);
225 gsapi_delete_instance(instance);
226 }
227 }
228 return gs->pattern;
229}
230
231static void gvloadimage_gs_cairo(GVJ_t * job, usershape_t *us, boxf b, bool filled)
232{
233 (void)filled;
234
235 cairo_t *cr = job->context; // target context
236 cairo_pattern_t *pattern = gvloadimage_gs_load(job, us);
237
238 if (pattern) {
239 cairo_save(cr);
240 cairo_translate(cr, b.LL.x - us->x, -b.UR.y);
241 cairo_scale(cr, (b.UR.x - b.LL.x) / us->w, (b.UR.y - b.LL.y) / us->h);
242 cairo_set_source(cr, pattern);
243 cairo_paint(cr);
244 cairo_restore(cr);
245 }
246}
247
251
253 {FORMAT_PS_CAIRO, "ps:cairo", 1, &engine_cairo, NULL},
254 {FORMAT_EPS_CAIRO, "eps:cairo", 1, &engine_cairo, NULL},
255 {0, NULL, 0, NULL, NULL}
256};
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
static char * err
Definition delaunay.c:696
static double len(glCompPoint p)
Definition glutils.c:150
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)
#define e_invalidid
static gvloadimage_engine_t engine_cairo
static void gvloadimage_gs_cairo(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static void gs_error(GVJ_t *job, const char *name, const char *funstr, int err)
static int gvloadimage_process_surface(GVJ_t *job, usershape_t *us, gs_t *gs, void *instance)
#define GS_ARGC
#define GSAPI_REVISION_REQUIRED
static void gvloadimage_gs_free(usershape_t *us)
#define e_unregistered
static int gs_writer(void *caller_handle, const char *str, int len)
struct gs_s gs_t
static cairo_pattern_t * gvloadimage_gs_load(GVJ_t *job, usershape_t *us)
gvplugin_installed_t gvloadimage_gs_types[]
static int gvloadimage_process_file(GVJ_t *job, usershape_t *us, void *instance)
@ FORMAT_EPS_CAIRO
@ FORMAT_PS_CAIRO
#define e_VMerror
textitem scanner parser str
Definition htmlparse.y:224
void(* errorfn)(const char *fmt,...)
Definition gvcommon.h:24
int verbose
Definition gvcommon.h:22
void * context
Definition gvcjob.h:295
GVCOMMON_t * common
Definition gvcjob.h:267
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
cairo_pattern_t * pattern
cairo_surface_t * surface
cairo_t * cr
ingroup plugin_api
Definition gvplugin.h:35
double x
Definition geom.h:29
double y
Definition geom.h:29
const char * name
Definition usershape.h:54
void(* datafree)(usershape_t *us)
Definition usershape.h:65
void * data
Definition usershape.h:63
double x
Definition usershape.h:61
double y
Definition usershape.h:61
double h
Definition usershape.h:61
double w
Definition usershape.h:61