| 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 | |