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