GRASS Programmer's Manual
6.4.2(2012)
|
00001 00015 #include "cairodriver.h" 00016 00017 #if CAIRO_HAS_PS_SURFACE 00018 #include <cairo-ps.h> 00019 #endif 00020 #if CAIRO_HAS_PDF_SURFACE 00021 #include <cairo-pdf.h> 00022 #endif 00023 #if CAIRO_HAS_SVG_SURFACE 00024 #include <cairo-svg.h> 00025 #endif 00026 #if CAIRO_HAS_XLIB_XRENDER_SURFACE 00027 #include <cairo-xlib.h> 00028 #include <cairo-xlib-xrender.h> 00029 #endif 00030 00031 #include <unistd.h> 00032 #ifndef __MINGW32__ 00033 #include <fcntl.h> 00034 #include <sys/types.h> 00035 #include <sys/stat.h> 00036 #include <sys/mman.h> 00037 #endif 00038 00039 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE 00040 #include <X11/X.h> 00041 #include <X11/Xlib.h> 00042 #include <X11/Xutil.h> 00043 #endif 00044 00045 /* globals */ 00046 char *file_name; 00047 int file_type; 00048 int is_vector; 00049 int width, height, stride; 00050 unsigned char *grid; 00051 int modified; 00052 int auto_write; 00053 int mapped; 00054 00055 /* background color */ 00056 double bgcolor_r, bgcolor_g, bgcolor_b, bgcolor_a; 00057 00058 /* cairo objects */ 00059 cairo_surface_t *surface; 00060 cairo_t *cairo; 00061 00062 static void init_cairo(void); 00063 static int ends_with(const char *string, const char *suffix); 00064 static void map_file(void); 00065 00066 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE 00067 static int init_xlib(void) 00068 { 00069 Display *dpy; 00070 Drawable win; 00071 unsigned long xid; 00072 XVisualInfo templ; 00073 XVisualInfo *vinfo; 00074 int count; 00075 Window root; 00076 unsigned int depth; 00077 int si; 00078 unsigned int ui; 00079 Visual *visual; 00080 char *p; 00081 00082 p = getenv("GRASS_CAIRO_DRAWABLE"); 00083 if (!p || sscanf(p, "%li", &xid) != 1) 00084 G_fatal_error("invalid Drawable XID: %s", p); 00085 win = xid; 00086 00087 dpy = XOpenDisplay(NULL); 00088 if (!dpy) 00089 G_fatal_error("Unable to open display"); 00090 00091 p = getenv("GRASS_CAIRO_VISUAL"); 00092 if (!p || sscanf(p, "%li", &xid) != 1) 00093 G_fatal_error("invalid Visual XID: %s", p); 00094 templ.visualid = xid; 00095 00096 vinfo = XGetVisualInfo(dpy, VisualIDMask, &templ, &count); 00097 if (!vinfo || !count) 00098 G_fatal_error("Unable to obtain visual"); 00099 visual = vinfo[0].visual; 00100 00101 if (!XGetGeometry 00102 (dpy, win, &root, &si, &si, &width, &height, &ui, &depth)) 00103 G_fatal_error("Unable to query drawable"); 00104 00105 surface = cairo_xlib_surface_create(dpy, win, visual, width, height); 00106 00107 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) 00108 G_fatal_error("Failed to initialize Xlib surface"); 00109 00110 cairo = cairo_create(surface); 00111 00112 file_name = "<X11>"; 00113 file_type = FTYPE_X11; 00114 00115 screen_right = screen_left + width; 00116 screen_bottom = screen_top + height; 00117 00118 return 0; 00119 } 00120 #endif 00121 00122 static int init_file(void) 00123 { 00124 int do_read = 0; 00125 int do_map = 0; 00126 char *p; 00127 00128 /* set image properties */ 00129 width = screen_right - screen_left; 00130 height = screen_bottom - screen_top; 00131 stride = width * 4; 00132 00133 /* get file name */ 00134 p = getenv("GRASS_CAIROFILE"); 00135 if (!p || strlen(p) == 0) 00136 p = DEFAULT_FILE_NAME; 00137 00138 file_name = p; 00139 00140 /* get file type (from extension) */ 00141 if (file_type == FTYPE_X11) ; /* skip */ 00142 else if (ends_with(file_name, ".ppm")) 00143 file_type = FTYPE_PPM; 00144 else if (ends_with(file_name, ".bmp")) 00145 file_type = FTYPE_BMP; 00146 #if CAIRO_HAS_PNG_FUNCTIONS 00147 else if (ends_with(file_name, ".png")) 00148 file_type = FTYPE_PNG; 00149 #endif 00150 #if CAIRO_HAS_PDF_SURFACE 00151 else if (ends_with(file_name, ".pdf")) 00152 file_type = FTYPE_PDF; 00153 #endif 00154 #if CAIRO_HAS_PS_SURFACE 00155 else if (ends_with(file_name, ".ps")) 00156 file_type = FTYPE_PS; 00157 #endif 00158 #if CAIRO_HAS_SVG_SURFACE 00159 else if (ends_with(file_name, ".svg")) 00160 file_type = FTYPE_SVG; 00161 #endif 00162 else 00163 G_fatal_error("Unknown file extension: %s", p); 00164 G_debug(1, "File type: %s (%d)", file_name, file_type); 00165 00166 switch (file_type) { 00167 case FTYPE_PDF: 00168 case FTYPE_PS: 00169 case FTYPE_SVG: 00170 is_vector = 1; 00171 break; 00172 } 00173 00174 p = getenv("GRASS_CAIRO_MAPPED"); 00175 do_map = p && strcmp(p, "TRUE") == 0 && ends_with(file_name, ".bmp"); 00176 00177 p = getenv("GRASS_CAIRO_READ"); 00178 do_read = p && strcmp(p, "TRUE") == 0; 00179 00180 if (is_vector) { 00181 do_read = do_map = 0; 00182 bgcolor_a = 1.0; 00183 } 00184 00185 if (do_read && access(file_name, 0) != 0) 00186 do_read = 0; 00187 00188 G_message 00189 ("cairo: collecting to file: %s,\n GRASS_WIDTH=%d, GRASS_HEIGHT=%d", 00190 file_name, width, height); 00191 00192 if (do_read && do_map) 00193 map_file(); 00194 00195 if (!mapped && !is_vector) 00196 grid = G_malloc(height * stride); 00197 00198 init_cairo(); 00199 00200 if (!do_read && !is_vector) { 00201 Cairo_Erase(); 00202 modified = 1; 00203 } 00204 00205 if (do_read && !mapped) 00206 read_image(); 00207 00208 if (do_map && !mapped) { 00209 write_image(); 00210 map_file(); 00211 init_cairo(); 00212 } 00213 00214 return 0; 00215 } 00216 00217 int Cairo_Graph_set(int argc, char **argv) 00218 { 00219 char *p; 00220 00221 G_gisinit("Cairo driver"); 00222 G_debug(1, "Cairo_Graph_set"); 00223 00224 /* get background color */ 00225 p = getenv("GRASS_BACKGROUNDCOLOR"); 00226 if (p && *p) { 00227 unsigned int red, green, blue; 00228 00229 if (sscanf(p, "%02x%02x%02x", &red, &green, &blue) == 3) { 00230 bgcolor_r = CAIROCOLOR(red); 00231 bgcolor_g = CAIROCOLOR(green); 00232 bgcolor_b = CAIROCOLOR(blue); 00233 } 00234 else 00235 G_fatal_error("Unknown background color: %s", p); 00236 } 00237 else 00238 bgcolor_r = bgcolor_g = bgcolor_b = 1.0; 00239 00240 /* get background transparency setting */ 00241 p = getenv("GRASS_TRANSPARENT"); 00242 if (p && strcmp(p, "TRUE") == 0) 00243 bgcolor_a = 0.0; 00244 else 00245 bgcolor_a = 1.0; 00246 00247 p = getenv("GRASS_AUTO_WRITE"); 00248 auto_write = p && strcmp(p, "TRUE") == 0; 00249 00250 #if defined(USE_X11) && CAIRO_HAS_XLIB_SURFACE 00251 p = getenv("GRASS_CAIRO_DRAWABLE"); 00252 if (p) 00253 return init_xlib(); 00254 #endif 00255 return init_file(); 00256 } 00257 00258 void Cairo_Graph_close(void) 00259 { 00260 G_debug(1, "Cairo_Graph_close"); 00261 00262 write_image(); 00263 00264 if (cairo) { 00265 cairo_destroy(cairo); 00266 cairo = NULL; 00267 } 00268 if (surface) { 00269 cairo_surface_destroy(surface); 00270 surface = NULL; 00271 } 00272 } 00273 00274 static void init_cairo(void) 00275 { 00276 G_debug(1, "init_cairo"); 00277 00278 /* create cairo surface */ 00279 switch (file_type) { 00280 case FTYPE_PPM: 00281 case FTYPE_BMP: 00282 case FTYPE_PNG: 00283 surface = 00284 (cairo_surface_t *) cairo_image_surface_create_for_data(grid, 00285 CAIRO_FORMAT_ARGB32, 00286 width, 00287 height, 00288 stride); 00289 break; 00290 #if CAIRO_HAS_PDF_SURFACE 00291 case FTYPE_PDF: 00292 surface = 00293 (cairo_surface_t *) cairo_pdf_surface_create(file_name, 00294 (double)width, 00295 (double)height); 00296 break; 00297 #endif 00298 #if CAIRO_HAS_PS_SURFACE 00299 case FTYPE_PS: 00300 surface = 00301 (cairo_surface_t *) cairo_ps_surface_create(file_name, 00302 (double)width, 00303 (double)height); 00304 break; 00305 #endif 00306 #if CAIRO_HAS_SVG_SURFACE 00307 case FTYPE_SVG: 00308 surface = 00309 (cairo_surface_t *) cairo_svg_surface_create(file_name, 00310 (double)width, 00311 (double)height); 00312 break; 00313 #endif 00314 default: 00315 G_fatal_error("Unknown Cairo surface type"); 00316 break; 00317 } 00318 00319 if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) 00320 G_fatal_error("Failed to initialize Cairo surface"); 00321 00322 cairo = cairo_create(surface); 00323 } 00324 00325 /* Returns TRUE if string ends with suffix (case insensitive) */ 00326 static int ends_with(const char *string, const char *suffix) 00327 { 00328 if (strlen(string) < strlen(suffix)) 00329 return FALSE; 00330 00331 return G_strcasecmp(suffix, 00332 string + strlen(string) - strlen(suffix)) == 0; 00333 } 00334 00335 static void map_file(void) 00336 { 00337 #ifndef __MINGW32__ 00338 size_t size = HEADER_SIZE + width * height * sizeof(unsigned int); 00339 void *ptr; 00340 int fd; 00341 00342 fd = open(file_name, O_RDWR); 00343 if (fd < 0) 00344 return; 00345 00346 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t) 0); 00347 if (ptr == MAP_FAILED) 00348 return; 00349 00350 if (grid) { 00351 cairo_destroy(cairo); 00352 cairo_surface_destroy(surface); 00353 G_free(grid); 00354 } 00355 grid = (unsigned char *)ptr + HEADER_SIZE; 00356 00357 close(fd); 00358 00359 mapped = 1; 00360 #endif 00361 }