1/* $Id$ $Revision$ */
2/* vim:set shiftwidth=4 ts=8: */
3
4/*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14#include "config.h"
15
16#include <stdlib.h>
17#include <stddef.h>
18#include <string.h>
19
20#ifdef HAVE_PANGOCAIRO
21#include <cairo.h>
22#endif
23
24#include "gvplugin_loadimage.h"
25#include "gvio.h"
26#include "gd.h"
27
28typedef enum {
29 FORMAT_PNG_GD, FORMAT_GIF_GD, FORMAT_JPG_GD, FORMAT_GD_GD, FORMAT_GD2_GD, FORMAT_XPM_GD, FORMAT_WBMP_GD, FORMAT_XBM_GD,
30 FORMAT_PNG_PS, FORMAT_GIF_PS, FORMAT_JPG_PS, FORMAT_GD_PS, FORMAT_GD2_PS, FORMAT_XPM_PS, FORMAT_WBMP_PS, FORMAT_XBM_PS,
31 FORMAT_PNG_CAIRO, FORMAT_GIF_CAIRO, FORMAT_JPG_CAIRO, FORMAT_GD_CAIRO, FORMAT_GD2_CAIRO, FORMAT_XPM_CAIRO, FORMAT_WBMP_CAIRO, FORMAT_XBM_CAIRO,
32} format_type;
33
34
35static void gd_freeimage(usershape_t *us)
36{
37 gdImageDestroy((gdImagePtr)us->data);
38}
39
40static gdImagePtr gd_loadimage(GVJ_t * job, usershape_t *us)
41{
42 assert(job);
43 assert(us);
44 assert(us->name);
45
46 if (us->data) {
47 if (us->datafree != gd_freeimage) {
48 us->datafree(us); /* free incompatible cache data */
49 us->data = NULL;
50 us->datafree = NULL;
51 }
52 }
53 if (!us->data) { /* read file into cache */
54 if (!gvusershape_file_access(us))
55 return NULL;
56 switch (us->type) {
57#if 0
58 case FT_GD:
59 im = gdImageCreateFromGd(us->f);
60 break;
61 case FT_GD2:
62 im = gdImageCreateFromGd2(us->f);
63 break;
64#endif
65#ifdef HAVE_GD_PNG
66 case FT_PNG:
67 us->data = (void*)gdImageCreateFromPng(us->f);
68 break;
69#endif
70#ifdef HAVE_GD_GIF
71 case FT_GIF:
72 us->data = (void*)gdImageCreateFromGif(us->f);
73 break;
74#endif
75#ifdef HAVE_GD_JPEG
76 case FT_JPEG:
77 us->data = (void*)gdImageCreateFromJpeg(us->f);
78 break;
79#endif
80#if 0
81#ifdef HAVE_GD_XPM
82 case FT_XPM:
83 us->data = (void*)gdImageCreateFromXpm(us->f);
84 break;
85#endif
86#ifdef HAVE_GD_WBMP
87 case FT_WBMP:
88 us->data = (void*)gdImageCreateFromWbmp(us->f);
89 break;
90#endif
91#endif
92 default:
93 break;
94 }
95 if (us->data)
96 us->datafree = gd_freeimage;
97
98 gvusershape_file_release(us);
99 }
100 return (gdImagePtr)(us->data);
101}
102
103static gdImagePtr gd_rotateimage(gdImagePtr im, int rotation)
104{
105 gdImagePtr im2 = gdImageCreate(im->sy, im->sx);
106
107 gdImageCopyRotated(im2, im, im2->sx / 2., im2->sy / 2.,
108 0, 0, im->sx, im->sy, rotation);
109 gdImageDestroy(im);
110 return im2;
111}
112
113static void gd_loadimage_gd(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
114{
115 gdImagePtr im2, im = (gdImagePtr) job->context;
116
117 if ((im2 = gd_loadimage(job, us))) {
118 if (job->rotation)
119 im2 = gd_rotateimage(im2, job->rotation);
120 gdImageCopyResized(im, im2, ROUND(b.LL.x), ROUND(b.LL.y), 0, 0,
121 ROUND(b.UR.x - b.LL.x), ROUND(b.UR.y - b.LL.y), im2->sx, im2->sy);
122 }
123}
124
125#ifdef HAVE_PANGOCAIRO
126static void gd_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
127{
128 cairo_t *cr = (cairo_t *) job->context; /* target context */
129 unsigned int x, y, stride, width, height, px;
130 unsigned char *data;
131 cairo_surface_t *surface; /* source surface */
132 gdImagePtr im;
133
134 if ((im = gd_loadimage(job, us))) {
135 width = im->sx;
136 height = im->sy;
137// cairo_format_stride_for_width() not available prior to cairo-1.6.4 or so (fc9)
138//stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
139 stride = width*4;
140 data = malloc (stride * height);
141 surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
142 width, height, stride);
143
144 if (im->trueColor) {
145 if (im->saveAlphaFlag) {
146 for (y = 0; y < height; y++) {
147 for (x = 0; x < width; x++) {
148 px = gdImageTrueColorPixel(im, x, y);
149 *data++ = gdTrueColorGetBlue(px);
150 *data++ = gdTrueColorGetGreen(px);
151 *data++ = gdTrueColorGetRed(px);
152 *data++ = (0x7F-gdTrueColorGetAlpha(px)) << 1;
153 }
154 }
155 }
156 else {
157 for (y = 0; y < height; y++) {
158 for (x = 0; x < width; x++) {
159 px = gdImageTrueColorPixel(im, x, y);
160 *data++ = gdTrueColorGetBlue(px);
161 *data++ = gdTrueColorGetGreen(px);
162 *data++ = gdTrueColorGetRed(px);
163 *data++ = 0xFF;
164 }
165 }
166 }
167 }
168 else {
169 for (y = 0; y < height; y++) {
170 for (x = 0; x < width; x++) {
171 px = gdImagePalettePixel(im, x, y);
172 *data++ = im->blue[px];
173 *data++ = im->green[px];
174 *data++ = im->red[px];
175 *data++ = (px==im->transparent)?0x00:0xff;
176 }
177 }
178 }
179
180 cairo_save(cr);
181 cairo_translate(cr, b.LL.x, -b.UR.y);
182 cairo_scale(cr, (b.UR.x - b.LL.x)/(us->w), (b.UR.y - b.LL.y)/(us->h));
183 cairo_set_source_surface (cr, surface, 0, 0);
184 cairo_paint (cr);
185 cairo_restore(cr);
186
187 cairo_surface_destroy(surface);
188 }
189}
190#endif
191
192static void gd_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
193{
194 gdImagePtr im = NULL;
195 int X, Y, x, y, px;
196
197 if ((im = gd_loadimage(job, us))) {
198 X = im->sx;
199 Y = im->sy;
200
201 gvputs(job, "save\n");
202
203 /* define image data as string array (one per raster line) */
204 gvputs(job, "/myctr 0 def\n");
205 gvputs(job, "/myarray [\n");
206 if (im->trueColor) {
207 for (y = 0; y < Y; y++) {
208 gvputs(job, "<");
209 for (x = 0; x < X; x++) {
210 px = gdImageTrueColorPixel(im, x, y);
211 gvprintf(job, "%02x%02x%02x",
212 gdTrueColorGetRed(px),
213 gdTrueColorGetGreen(px),
214 gdTrueColorGetBlue(px));
215 }
216 gvputs(job, ">\n");
217 }
218 }
219 else {
220 for (y = 0; y < Y; y++) {
221 gvputs(job, "<");
222 for (x = 0; x < X; x++) {
223 px = gdImagePalettePixel(im, x, y);
224 gvprintf(job, "%02x%02x%02x",
225 im->red[px],
226 im->green[px],
227 im->blue[px]);
228 }
229 gvputs(job, ">\n");
230 }
231 }
232 gvputs(job, "] def\n");
233 gvputs(job,"/myproc { myarray myctr get /myctr myctr 1 add def } def\n");
234
235 /* this sets the position of the image */
236 gvprintf(job, "%g %g translate\n",
237 (b.LL.x + (b.UR.x - b.LL.x) * (1. - (job->dpi.x) / 96.) / 2.),
238 (b.LL.y + (b.UR.y - b.LL.y) * (1. - (job->dpi.y) / 96.) / 2.));
239
240 /* this sets the rendered size to fit the box */
241 gvprintf(job,"%g %g scale\n",
242 ((b.UR.x - b.LL.x) * (job->dpi.x) / 96.),
243 ((b.UR.y - b.LL.y) * (job->dpi.y) / 96.));
244
245 /* xsize ysize bits-per-sample [matrix] */
246 gvprintf(job, "%d %d 8 [%d 0 0 %d 0 %d]\n", X, Y, X, -Y, Y);
247
248 gvputs(job, "{myproc} false 3 colorimage\n");
249
250 gvputs(job, "restore\n");
251 }
252}
253
254static gvloadimage_engine_t engine = {
255 gd_loadimage_gd
256};
257
258static gvloadimage_engine_t engine_ps = {
259 gd_loadimage_ps
260};
261
262#ifdef HAVE_PANGOCAIRO
263static gvloadimage_engine_t engine_cairo = {
264 gd_loadimage_cairo
265};
266#endif
267
268gvplugin_installed_t gvloadimage_gd_types[] = {
269 {FORMAT_GD_GD, "gd:gd", 1, &engine, NULL},
270 {FORMAT_GD2_GD, "gd2:gd", 1, &engine, NULL},
271#ifdef HAVE_GD_GIF
272 {FORMAT_GIF_GD, "gif:gd", 1, &engine, NULL},
273#endif
274#ifdef HAVE_GD_JPEG
275 {FORMAT_JPG_GD, "jpeg:gd", 1, &engine, NULL},
276 {FORMAT_JPG_GD, "jpe:gd", 1, &engine, NULL},
277 {FORMAT_JPG_GD, "jpg:gd", 1, &engine, NULL},
278#endif
279#ifdef HAVE_GD_PNG
280 {FORMAT_PNG_GD, "png:gd", 1, &engine, NULL},
281#endif
282#ifdef HAVE_GD_WBMP
283 {FORMAT_WBMP_GD, "wbmp:gd", 1, &engine, NULL},
284#endif
285#ifdef HAVE_GD_XPM
286 {FORMAT_XBM_GD, "xbm:gd", 1, &engine, NULL},
287#endif
288
289 {FORMAT_GD_PS, "gd:ps", 1, &engine_ps, NULL},
290 {FORMAT_GD_PS, "gd:lasi", 1, &engine_ps, NULL},
291 {FORMAT_GD2_PS, "gd2:ps", 1, &engine_ps, NULL},
292 {FORMAT_GD2_PS, "gd2:lasi", 1, &engine_ps, NULL},
293#ifdef HAVE_GD_GIF
294 {FORMAT_GIF_PS, "gif:ps", 1, &engine_ps, NULL},
295 {FORMAT_GIF_PS, "gif:lasi", 1, &engine_ps, NULL},
296#endif
297#ifdef HAVE_GD_JPEG
298 {FORMAT_JPG_PS, "jpeg:ps", 1, &engine_ps, NULL},
299 {FORMAT_JPG_PS, "jpg:ps", 1, &engine_ps, NULL},
300 {FORMAT_JPG_PS, "jpe:ps", 1, &engine_ps, NULL},
301 {FORMAT_JPG_PS, "jpeg:lasi", 1, &engine_ps, NULL},
302 {FORMAT_JPG_PS, "jpg:lasi", 1, &engine_ps, NULL},
303 {FORMAT_JPG_PS, "jpe:lasi", 1, &engine_ps, NULL},
304#endif
305#ifdef HAVE_GD_PNG
306 {FORMAT_PNG_PS, "png:ps", 1, &engine_ps, NULL},
307 {FORMAT_PNG_PS, "png:lasi", 1, &engine_ps, NULL},
308#endif
309#ifdef HAVE_GD_WBMP
310 {FORMAT_WBMP_PS, "wbmp:ps", 1, &engine_ps, NULL},
311 {FORMAT_WBMP_PS, "wbmp:lasi", 1, &engine_ps, NULL},
312#endif
313#ifdef HAVE_GD_XPM
314 {FORMAT_XBM_PS, "xbm:ps", 1, &engine_ps, NULL},
315 {FORMAT_XBM_PS, "xbm:lasi", 1, &engine_ps, NULL},
316#endif
317
318#ifdef HAVE_PANGOCAIRO
319 {FORMAT_GD_CAIRO, "gd:cairo", 1, &engine_cairo, NULL},
320 {FORMAT_GD2_CAIRO, "gd2:cairo", 1, &engine_cairo, NULL},
321#ifdef HAVE_GD_GIF
322 {FORMAT_GIF_CAIRO, "gif:cairo", 1, &engine_cairo, NULL},
323#endif
324#ifdef HAVE_GD_JPEG
325 {FORMAT_JPG_CAIRO, "jpeg:cairo", 1, &engine_cairo, NULL},
326 {FORMAT_JPG_CAIRO, "jpg:cairo", 1, &engine_cairo, NULL},
327 {FORMAT_JPG_CAIRO, "jpe:cairo", 1, &engine_cairo, NULL},
328#endif
329#ifdef HAVE_GD_PNG
330 {FORMAT_PNG_CAIRO, "png:cairo", -1, &engine_cairo, NULL},
331#endif
332#ifdef HAVE_GD_WBMP
333 {FORMAT_WBMP_CAIRO, "wbmp:cairo", 1, &engine_cairo, NULL},
334#endif
335#ifdef HAVE_GD_XPM
336 {FORMAT_XBM_CAIRO, "xbm:cairo", 1, &engine_cairo, NULL},
337#endif
338#endif /* HAVE_PANGOCAIRO */
339 {0, NULL, 0, NULL, NULL}
340};
341