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
18#include "gvplugin_loadimage.h"
19#include "gvio.h"
20
21#include <cairo.h>
22
23typedef enum {
24 FORMAT_PNG_CAIRO, FORMAT_PNG_PS,
25} format_type;
26
27static cairo_status_t
28reader (void *closure, unsigned char *data, unsigned int length)
29{
30 assert(closure);
31 if (length == fread(data, 1, length, (FILE *)closure)
32 || feof((FILE *)closure))
33 return CAIRO_STATUS_SUCCESS;
34 return CAIRO_STATUS_READ_ERROR;
35}
36
37static void cairo_freeimage(usershape_t *us)
38{
39 cairo_surface_destroy((cairo_surface_t*)(us->data));
40}
41
42static cairo_surface_t* cairo_loadimage(GVJ_t * job, usershape_t *us)
43{
44 cairo_surface_t *surface = NULL; /* source surface */
45
46 assert(job);
47 assert(us);
48 assert(us->name);
49 assert(us->name[0]);
50
51 if (us->data) {
52 if (us->datafree == cairo_freeimage)
53 surface = (cairo_surface_t*)(us->data); /* use cached data */
54 else {
55 us->datafree(us); /* free incompatible cache data */
56 us->datafree = NULL;
57 us->data = NULL;
58 }
59 }
60 if (!surface) { /* read file into cache */
61 if (!gvusershape_file_access(us))
62 return NULL;
63 assert(us->f);
64 switch (us->type) {
65#ifdef CAIRO_HAS_PNG_FUNCTIONS
66 case FT_PNG:
67 surface = cairo_image_surface_create_from_png_stream(reader, us->f);
68 cairo_surface_reference(surface);
69 break;
70#endif
71 default:
72 surface = NULL;
73 }
74 if (surface) {
75 us->data = (void*)surface;
76 us->datafree = cairo_freeimage;
77 }
78 gvusershape_file_release(us);
79 }
80 return surface;
81}
82
83static void pango_loadimage_cairo(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
84{
85 cairo_t *cr = (cairo_t *) job->context; /* target context */
86 cairo_surface_t *surface; /* source surface */
87
88 assert(job);
89 assert(us);
90 assert(us->name);
91 assert(us->name[0]);
92
93 surface = cairo_loadimage(job, us);
94 if (surface) {
95 cairo_save(cr);
96 cairo_translate(cr, b.LL.x, -b.UR.y);
97 cairo_scale(cr, (b.UR.x - b.LL.x)/(us->w), (b.UR.y - b.LL.y)/(us->h));
98 cairo_set_source_surface (cr, surface, 0, 0);
99 cairo_paint (cr);
100 cairo_restore(cr);
101 }
102}
103
104static void pango_loadimage_ps(GVJ_t * job, usershape_t *us, boxf b, boolean filled)
105{
106 cairo_surface_t *surface; /* source surface */
107 cairo_format_t format;
108 int X, Y, x, y, stride;
109 unsigned char *data, *ix, alpha, red, green, blue;
110
111 surface = cairo_loadimage(job, us);
112 if (surface) {
113 format = cairo_image_surface_get_format(surface);
114 if ((format != CAIRO_FORMAT_ARGB32) && (format != CAIRO_FORMAT_RGB24))
115 return;
116
117 X = cairo_image_surface_get_width(surface);
118 Y = cairo_image_surface_get_height(surface);
119 stride = cairo_image_surface_get_stride(surface);
120 data = cairo_image_surface_get_data(surface);
121
122 gvputs(job, "save\n");
123
124 /* define image data as string array (one per raster line) */
125 /* see parallel code in gd_loadimage_ps(). FIXME: refactor... */
126 gvputs(job, "/myctr 0 def\n");
127 gvputs(job, "/myarray [\n");
128 for (y = 0; y < Y; y++) {
129 gvputs(job, "<");
130 ix = data + y * stride;
131 for (x = 0; x < X; x++) {
132 /* FIXME - this code may have endian problems */
133 blue = *ix++;
134 green = *ix++;
135 red = *ix++;
136 alpha = *ix++;
137 if (alpha < 0x7f)
138 gvputs(job, "ffffff");
139 else
140 gvprintf(job, "%02x%02x%02x", red, green, blue);
141 }
142 gvputs(job, ">\n");
143 }
144 gvputs(job, "] def\n");
145 gvputs(job,"/myproc { myarray myctr get /myctr myctr 1 add def } def\n");
146
147 /* this sets the position of the image */
148 gvprintf(job, "%g %g translate\n",
149 (b.LL.x + (b.UR.x - b.LL.x) * (1. - (job->dpi.x) / 96.) / 2.),
150 (b.LL.y + (b.UR.y - b.LL.y) * (1. - (job->dpi.y) / 96.) / 2.));
151
152 /* this sets the rendered size to fit the box */
153 gvprintf(job,"%g %g scale\n",
154 ((b.UR.x - b.LL.x) * 72. / 96.),
155 ((b.UR.y - b.LL.y) * 72. / 96.));
156
157 /* xsize ysize bits-per-sample [matrix] */
158 gvprintf(job, "%d %d 8 [%d 0 0 %d 0 %d]\n", X, Y, X, -Y, Y);
159
160 gvputs(job, "{myproc} false 3 colorimage\n");
161
162 gvputs(job, "restore\n");
163 }
164}
165
166static gvloadimage_engine_t engine_cairo = {
167 pango_loadimage_cairo
168};
169
170static gvloadimage_engine_t engine_ps = {
171 pango_loadimage_ps
172};
173
174gvplugin_installed_t gvloadimage_pango_types[] = {
175 {FORMAT_PNG_CAIRO, "png:cairo", 1, &engine_cairo, NULL},
176 {FORMAT_PNG_PS, "png:lasi", 2, &engine_ps, NULL},
177 {FORMAT_PNG_PS, "png:ps", 2, &engine_ps, NULL},
178 {0, NULL, 0, NULL, NULL}
179};
180