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 | |
23 | typedef enum { |
24 | FORMAT_PNG_CAIRO, FORMAT_PNG_PS, |
25 | } format_type; |
26 | |
27 | static cairo_status_t |
28 | reader (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 | |
37 | static void cairo_freeimage(usershape_t *us) |
38 | { |
39 | cairo_surface_destroy((cairo_surface_t*)(us->data)); |
40 | } |
41 | |
42 | static 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 | |
83 | static 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 | |
104 | static 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 | |
166 | static gvloadimage_engine_t engine_cairo = { |
167 | pango_loadimage_cairo |
168 | }; |
169 | |
170 | static gvloadimage_engine_t engine_ps = { |
171 | pango_loadimage_ps |
172 | }; |
173 | |
174 | gvplugin_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 | |