Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvloadimage_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
13#include <assert.h>
14#include <stdbool.h>
15#include <stdlib.h>
16#include <string.h>
17#include <util/alloc.h>
18
19#ifdef HAVE_PANGOCAIRO
20#include <cairo.h>
21#endif
22
24#include <gvc/gvio.h>
25#include <gd.h>
26
32
33
34static void gd_freeimage(usershape_t *us)
35{
36 gdImageDestroy(us->data);
37}
38
39static gdImagePtr gd_loadimage(GVJ_t * job, usershape_t *us)
40{
41 assert(job);
42 assert(us);
43 assert(us->name);
44
45 if (us->data) {
46 if (us->datafree != gd_freeimage) {
47 us->datafree(us); /* free incompatible cache data */
48 us->data = NULL;
49 us->datafree = NULL;
50 }
51 }
52 if (!us->data) { /* read file into cache */
54 return NULL;
55 switch (us->type) {
56#ifdef HAVE_GD_PNG
57 case FT_PNG:
58 us->data = gdImageCreateFromPng(us->f);
59 break;
60#endif
61#ifdef HAVE_GD_GIF
62 case FT_GIF:
63 us->data = gdImageCreateFromGif(us->f);
64 break;
65#endif
66#ifdef HAVE_GD_JPEG
67 case FT_JPEG:
68 us->data = gdImageCreateFromJpeg(us->f);
69 break;
70#endif
71 default:
72 break;
73 }
74 if (us->data)
76
78 }
79 return us->data;
80}
81
82static gdImagePtr gd_rotateimage(gdImagePtr im, int rotation)
83{
84 gdImagePtr im2 = gdImageCreate(im->sy, im->sx);
85
86 gdImageCopyRotated(im2, im, im2->sx / 2., im2->sy / 2.,
87 0, 0, im->sx, im->sy, rotation);
88 gdImageDestroy(im);
89 return im2;
90}
91
92static void gd_loadimage_gd(GVJ_t * job, usershape_t *us, boxf b, bool filled)
93{
94 (void)filled;
95
96 gdImagePtr im2, im = job->context;
97
98 if ((im2 = gd_loadimage(job, us))) {
99 if (job->rotation) {
100 im2 = gd_rotateimage(im2, job->rotation);
101 us->data = im2;
102 }
103 gdImageCopyResized(im, im2, ROUND(b.LL.x), ROUND(b.LL.y), 0, 0,
104 ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y), im2->sx, im2->sy);
105 }
106}
107
108#ifdef HAVE_PANGOCAIRO
109static void gd_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, bool filled)
110{
111 (void)filled;
112
113 cairo_t *cr = job->context; /* target context */
114 int x, y, width, height;
115 cairo_surface_t *surface; /* source surface */
116 gdImagePtr im;
117
118 if ((im = gd_loadimage(job, us))) {
119 width = im->sx;
120 height = im->sy;
121 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32,
122 width);
123 assert(stride >= 0);
124 assert(height >= 0);
125 unsigned char *data = gv_calloc((size_t)stride, (size_t)height);
126 surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
127 width, height, stride);
128 unsigned char *const orig_data = data;
129
130 if (im->trueColor) {
131 if (im->saveAlphaFlag) {
132 for (y = 0; y < height; y++) {
133 for (x = 0; x < width; x++) {
134 const int px = gdImageTrueColorPixel(im, x, y);
135 *data++ = (unsigned char)gdTrueColorGetBlue(px);
136 *data++ = (unsigned char)gdTrueColorGetGreen(px);
137 *data++ = (unsigned char)gdTrueColorGetRed(px);
138 // gd’s alpha is 7-bit, so scale up ×2 to our 8-bit
139 *data++ = (unsigned char)((0x7F - gdTrueColorGetAlpha(px)) << 1);
140 }
141 }
142 }
143 else {
144 for (y = 0; y < height; y++) {
145 for (x = 0; x < width; x++) {
146 const int px = gdImageTrueColorPixel(im, x, y);
147 *data++ = (unsigned char)gdTrueColorGetBlue(px);
148 *data++ = (unsigned char)gdTrueColorGetGreen(px);
149 *data++ = (unsigned char)gdTrueColorGetRed(px);
150 *data++ = 0xFF;
151 }
152 }
153 }
154 }
155 else {
156 for (y = 0; y < height; y++) {
157 for (x = 0; x < width; x++) {
158 const int px = gdImagePalettePixel(im, x, y);
159 *data++ = (unsigned char)im->blue[px];
160 *data++ = (unsigned char)im->green[px];
161 *data++ = (unsigned char)im->red[px];
162 *data++ = px == im->transparent ? 0x00 : 0xff;
163 }
164 }
165 }
166
167 cairo_save(cr);
168 cairo_translate(cr, b.LL.x, -b.UR.y);
169 cairo_scale(cr, (b.UR.x - b.LL.x) / us->w, (b.UR.y - b.LL.y) / us->h);
170 cairo_set_source_surface (cr, surface, 0, 0);
171 cairo_paint (cr);
172 cairo_restore(cr);
173
174 cairo_surface_destroy(surface);
175 free(orig_data);
176 }
177}
178#endif
179
180static void gd_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, bool filled)
181{
182 (void)filled;
183
184 gdImagePtr im = NULL;
185 int X, Y, x, y, px;
186
187 if ((im = gd_loadimage(job, us))) {
188 X = im->sx;
189 Y = im->sy;
190
191 gvputs(job, "save\n");
192
193 /* define image data as string array (one per raster line) */
194 gvputs(job, "/myctr 0 def\n");
195 gvputs(job, "/myarray [\n");
196 if (im->trueColor) {
197 for (y = 0; y < Y; y++) {
198 gvputs(job, "<");
199 for (x = 0; x < X; x++) {
200 px = gdImageTrueColorPixel(im, x, y);
201 gvprintf(job, "%02x%02x%02x",
202 gdTrueColorGetRed(px),
203 gdTrueColorGetGreen(px),
204 gdTrueColorGetBlue(px));
205 }
206 gvputs(job, ">\n");
207 }
208 }
209 else {
210 for (y = 0; y < Y; y++) {
211 gvputs(job, "<");
212 for (x = 0; x < X; x++) {
213 px = gdImagePalettePixel(im, x, y);
214 gvprintf(job, "%02x%02x%02x",
215 im->red[px],
216 im->green[px],
217 im->blue[px]);
218 }
219 gvputs(job, ">\n");
220 }
221 }
222 gvputs(job, "] def\n");
223 gvputs(job,"/myproc { myarray myctr get /myctr myctr 1 add def } def\n");
224
225 /* this sets the position of the image */
226 gvprintf(job, "%g %g translate\n",
227 b.LL.x + (b.UR.x - b.LL.x) * (1. - (job->dpi.x) / 96.) / 2.,
228 b.LL.y + (b.UR.y - b.LL.y) * (1. - (job->dpi.y) / 96.) / 2.);
229
230 /* this sets the rendered size to fit the box */
231 gvprintf(job,"%g %g scale\n",
232 (b.UR.x - b.LL.x) * (job->dpi.x) / 96.,
233 (b.UR.y - b.LL.y) * (job->dpi.y) / 96.);
234
235 /* xsize ysize bits-per-sample [matrix] */
236 gvprintf(job, "%d %d 8 [%d 0 0 %d 0 %d]\n", X, Y, X, -Y, Y);
237
238 gvputs(job, "{myproc} false 3 colorimage\n");
239
240 gvputs(job, "restore\n");
241 }
242}
243
247
251
252#ifdef HAVE_PANGOCAIRO
254 gd_loadimage_cairo
255};
256#endif
257
259 {FORMAT_GD_GD, "gd:gd", 1, &engine, NULL},
260 {FORMAT_GD2_GD, "gd2:gd", 1, &engine, NULL},
261#ifdef HAVE_GD_GIF
262 {FORMAT_GIF_GD, "gif:gd", 1, &engine, NULL},
263#endif
264#ifdef HAVE_GD_JPEG
265 {FORMAT_JPG_GD, "jpeg:gd", 1, &engine, NULL},
266 {FORMAT_JPG_GD, "jpe:gd", 1, &engine, NULL},
267 {FORMAT_JPG_GD, "jpg:gd", 1, &engine, NULL},
268#endif
269#ifdef HAVE_GD_PNG
270 {FORMAT_PNG_GD, "png:gd", 1, &engine, NULL},
271#endif
272#ifdef HAVE_GD_WBMP
273 {FORMAT_WBMP_GD, "wbmp:gd", 1, &engine, NULL},
274#endif
275#ifdef HAVE_GD_XPM
276 {FORMAT_XBM_GD, "xbm:gd", 1, &engine, NULL},
277#endif
278
279 {FORMAT_GD_PS, "gd:ps", 1, &engine_ps, NULL},
280 {FORMAT_GD_PS, "gd:lasi", 1, &engine_ps, NULL},
281 {FORMAT_GD2_PS, "gd2:ps", 1, &engine_ps, NULL},
282 {FORMAT_GD2_PS, "gd2:lasi", 1, &engine_ps, NULL},
283#ifdef HAVE_GD_GIF
284 {FORMAT_GIF_PS, "gif:ps", 1, &engine_ps, NULL},
285 {FORMAT_GIF_PS, "gif:lasi", 1, &engine_ps, NULL},
286#endif
287#ifdef HAVE_GD_JPEG
288 {FORMAT_JPG_PS, "jpeg:ps", 1, &engine_ps, NULL},
289 {FORMAT_JPG_PS, "jpg:ps", 1, &engine_ps, NULL},
290 {FORMAT_JPG_PS, "jpe:ps", 1, &engine_ps, NULL},
291 {FORMAT_JPG_PS, "jpeg:lasi", 1, &engine_ps, NULL},
292 {FORMAT_JPG_PS, "jpg:lasi", 1, &engine_ps, NULL},
293 {FORMAT_JPG_PS, "jpe:lasi", 1, &engine_ps, NULL},
294#endif
295#ifdef HAVE_GD_PNG
296 {FORMAT_PNG_PS, "png:ps", 1, &engine_ps, NULL},
297 {FORMAT_PNG_PS, "png:lasi", 1, &engine_ps, NULL},
298#endif
299#ifdef HAVE_GD_WBMP
300 {FORMAT_WBMP_PS, "wbmp:ps", 1, &engine_ps, NULL},
301 {FORMAT_WBMP_PS, "wbmp:lasi", 1, &engine_ps, NULL},
302#endif
303#ifdef HAVE_GD_XPM
304 {FORMAT_XBM_PS, "xbm:ps", 1, &engine_ps, NULL},
305 {FORMAT_XBM_PS, "xbm:lasi", 1, &engine_ps, NULL},
306#endif
307
308#ifdef HAVE_PANGOCAIRO
309 {FORMAT_GD_CAIRO, "gd:cairo", 1, &engine_cairo, NULL},
310 {FORMAT_GD2_CAIRO, "gd2:cairo", 1, &engine_cairo, NULL},
311#ifdef HAVE_GD_GIF
312 {FORMAT_GIF_CAIRO, "gif:cairo", 1, &engine_cairo, NULL},
313#endif
314#ifdef HAVE_GD_JPEG
315 {FORMAT_JPG_CAIRO, "jpeg:cairo", 1, &engine_cairo, NULL},
316 {FORMAT_JPG_CAIRO, "jpg:cairo", 1, &engine_cairo, NULL},
317 {FORMAT_JPG_CAIRO, "jpe:cairo", 1, &engine_cairo, NULL},
318#endif
319#ifdef HAVE_GD_PNG
320 {FORMAT_PNG_CAIRO, "png:cairo", -1, &engine_cairo, NULL},
321#endif
322#ifdef HAVE_GD_WBMP
323 {FORMAT_WBMP_CAIRO, "wbmp:cairo", 1, &engine_cairo, NULL},
324#endif
325#ifdef HAVE_GD_XPM
326 {FORMAT_XBM_CAIRO, "xbm:cairo", 1, &engine_cairo, NULL},
327#endif
328#endif /* HAVE_PANGOCAIRO */
329 {0, NULL, 0, NULL, NULL}
330};
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define ROUND(f)
Definition arith.h:48
#define Y(i)
Definition gdefs.h:3
#define X(prefix, name, str, type, subtype,...)
Definition gdefs.h:14
void free(void *)
node NULL
Definition grammar.y:163
void gvusershape_file_release(usershape_t *us)
bool gvusershape_file_access(usershape_t *us)
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 gvloadimage_engine_t engine_ps
static void gd_loadimage_ps(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static void gd_freeimage(usershape_t *us)
static gvloadimage_engine_t engine
gvplugin_installed_t gvloadimage_gd_types[]
static void gd_loadimage_gd(GVJ_t *job, usershape_t *us, boxf b, bool filled)
static gdImagePtr gd_loadimage(GVJ_t *job, usershape_t *us)
format_type
@ FORMAT_JPG_PS
@ FORMAT_GD_GD
@ FORMAT_WBMP_PS
@ FORMAT_GIF_GD
@ FORMAT_XBM_PS
@ FORMAT_XBM_GD
@ FORMAT_XPM_GD
@ FORMAT_WBMP_CAIRO
@ FORMAT_GD_PS
@ FORMAT_JPG_GD
@ FORMAT_PNG_GD
@ FORMAT_WBMP_GD
@ FORMAT_GD_CAIRO
@ FORMAT_XBM_CAIRO
@ FORMAT_GD2_CAIRO
@ FORMAT_GIF_CAIRO
@ FORMAT_GIF_PS
@ FORMAT_JPG_CAIRO
@ FORMAT_GD2_GD
@ FORMAT_XPM_PS
@ FORMAT_PNG_PS
@ FORMAT_PNG_CAIRO
@ FORMAT_GD2_PS
@ FORMAT_XPM_CAIRO
static gdImagePtr gd_rotateimage(gdImagePtr im, int rotation)
static gvloadimage_engine_t engine_cairo
int rotation
Definition gvcjob.h:319
pointf dpi
Definition gvcjob.h:325
void * context
Definition gvcjob.h:295
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
Definition legal.c:50
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
FILE * f
Definition usershape.h:58
void(* datafree)(usershape_t *us)
Definition usershape.h:65
void * data
Definition usershape.h:63
imagetype_t type
Definition usershape.h:59
double h
Definition usershape.h:61
double w
Definition usershape.h:61
@ FT_GIF
Definition usershape.h:25
@ FT_JPEG
Definition usershape.h:25
@ FT_PNG
Definition usershape.h:25