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 "gvplugin_device.h"
17#include "gvio.h"
18
19#include "gd.h"
20
21int gvdevice_gd_putBuf (gdIOCtx *context, const void *buffer, int len)
22{
23 return gvwrite((GVJ_t *)(context->tell), buffer, len);
24}
25
26/* used by gif output */
27void gvdevice_gd_putC (gdIOCtx *context, int C)
28{
29 char c = C;
30
31 gvwrite((GVJ_t *)(context->tell), &c, 1);
32}
33
34#ifdef HAVE_PANGOCAIRO
35typedef enum {
36 FORMAT_GIF,
37 FORMAT_JPEG,
38 FORMAT_PNG,
39 FORMAT_WBMP,
40 FORMAT_GD,
41 FORMAT_GD2,
42 FORMAT_XBM,
43} format_type;
44
45static void gd_format(GVJ_t * job)
46{
47 gdImagePtr im;
48 unsigned int x, y, color, alpha;
49 unsigned int *data = (unsigned int*)(job->imagedata);
50 unsigned int width = job->width;
51 unsigned int height = job->height;
52 gdIOCtx ctx;
53
54 ctx.putBuf = gvdevice_gd_putBuf;
55 ctx.putC = gvdevice_gd_putC;
56 ctx.tell = (void*)job; /* hide *job here */
57
58 im = gdImageCreateTrueColor(width, height);
59 switch (job->device.id) {
60#ifdef HAVE_GD_PNG
61 case FORMAT_PNG:
62 for (y = 0; y < height; y++) {
63 for (x = 0; x < width; x++) {
64 color = *data++;
65 /* gd's max alpha is 127 */
66 /* so right-shift 25 to lose lsb of alpha */
67 alpha = (color >> 25) & 0x7f;
68 im->tpixels[y][x] = (color & 0xffffff) | ((0x7f - alpha) << 24);
69 }
70 }
71 break;
72#endif
73 default:
74/* pick an off-white color, so that transparent backgrounds look white in jpgs */
75#define TRANSPARENT 0x7ffffffe
76
77 gdImageColorTransparent(im, TRANSPARENT);
78 gdImageAlphaBlending(im, FALSE);
79 for (y = 0; y < height; y++) {
80 for (x = 0; x < width; x++) {
81 color = *data++;
82 /* gd's max alpha is 127 */
83 /* so right-shift 25 to lose lsb of alpha */
84 if ((alpha = (color >> 25) & 0x7f) >= 0x20)
85 /* if not > 75% transparent */
86 im->tpixels[y][x] = (color & 0xffffff) | ((0x7f - alpha) << 24);
87 else
88 im->tpixels[y][x] = TRANSPARENT;
89 }
90 }
91 break;
92 }
93
94 switch (job->device.id) {
95#ifdef HAVE_GD_GIF
96 case FORMAT_GIF:
97 gdImageTrueColorToPalette(im, 0, 256);
98 gdImageGifCtx(im, &ctx);
99 break;
100#endif
101
102#ifdef HAVE_GD_JPEG
103 case FORMAT_JPEG:
104 /*
105 * Write IM to OUTFILE as a JFIF-formatted JPEG image, using
106 * quality JPEG_QUALITY. If JPEG_QUALITY is in the range
107 * 0-100, increasing values represent higher quality but also
108 * larger image size. If JPEG_QUALITY is negative, the
109 * IJG JPEG library's default quality is used (which should
110 * be near optimal for many applications). See the IJG JPEG
111 * library documentation for more details.
112 */
113#define JPEG_QUALITY -1
114 gdImageJpegCtx(im, &ctx, JPEG_QUALITY);
115 break;
116#endif
117
118#ifdef HAVE_GD_PNG
119 case FORMAT_PNG:
120 gdImageTrueColorToPalette(im, 0, 256);
121 gdImagePngCtx(im, &ctx);
122 break;
123#endif
124
125 case FORMAT_GD:
126 gdImageGd(im, job->output_file);
127 break;
128
129 case FORMAT_GD2:
130#define GD2_CHUNKSIZE 128
131#define GD2_RAW 1
132#define GD2_COMPRESSED 2
133 gdImageGd2(im, job->output_file, GD2_CHUNKSIZE, GD2_COMPRESSED);
134 break;
135
136#ifdef HAVE_GD_GIF
137 case FORMAT_WBMP:
138 {
139 /* Use black for the foreground color for the B&W wbmp image. */
140 int black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque);
141 gdImageWBMPCtx(im, black, &ctx);
142 }
143 break;
144#endif
145
146#if 0
147/* libgd only supports reading of xpm files */
148#ifdef HAVE_GD_XPM
149 case FORMAT_XBM:
150 gdImageXbm(im, job->output_file);
151#endif
152#endif
153 break;
154 default:
155 break;
156 }
157
158 gdImageDestroy(im);
159}
160
161static gvdevice_engine_t gd_engine = {
162 NULL, /* gd_initialize */
163 gd_format,
164 NULL, /* gd_finalize */
165};
166
167static gvdevice_features_t device_features_gd = {
168 GVDEVICE_BINARY_FORMAT
169 | GVDEVICE_DOES_TRUECOLOR,/* flags */
170 {0.,0.}, /* default margin - points */
171 {0.,0.}, /* default page width, height - points */
172 {96.,96.}, /* dpi */
173};
174
175static gvdevice_features_t device_features_gd_no_writer = {
176 GVDEVICE_BINARY_FORMAT
177 | GVDEVICE_NO_WRITER
178 | GVDEVICE_DOES_TRUECOLOR,/* flags */
179 {0.,0.}, /* default margin - points */
180 {0.,0.}, /* default page width, height - points */
181 {96.,96.}, /* dpi */
182};
183#endif
184
185gvplugin_installed_t gvdevice_gd_types[] = {
186#ifdef HAVE_PANGOCAIRO
187
188#ifdef HAVE_GD_GIF
189 {FORMAT_GIF, "gif:cairo", 10, &gd_engine, &device_features_gd},
190 {FORMAT_WBMP, "wbmp:cairo", 5, &gd_engine, &device_features_gd},
191#endif
192
193#ifdef HAVE_GD_JPEG
194 {FORMAT_JPEG, "jpe:cairo", 5, &gd_engine, &device_features_gd},
195 {FORMAT_JPEG, "jpeg:cairo", 5, &gd_engine, &device_features_gd},
196 {FORMAT_JPEG, "jpg:cairo", 5, &gd_engine, &device_features_gd},
197#endif
198
199#ifdef HAVE_GD_PNG
200 {FORMAT_PNG, "png:cairo", 5, &gd_engine, &device_features_gd},
201#endif
202
203 {FORMAT_GD, "gd:cairo", 5, &gd_engine, &device_features_gd_no_writer},
204 {FORMAT_GD2, "gd2:cairo", 5, &gd_engine, &device_features_gd_no_writer},
205
206#if 0
207/* libgd only supports reading of xpm files */
208#ifdef HAVE_GD_XPM
209 {FORMAT_XBM, "xbm:cairo", 5, &gd_engine, &device_features_gd},
210#endif
211#endif
212
213#endif
214 {0, NULL, 0, NULL, NULL}
215};
216