Mercurial > emacs
comparison src/image.c @ 82518:b6db95f12a9d
Paul Pogonyshev <pogonyshev at gmx.net>
Add support for SVG images.
Some additional comments by Joakim Verona <joakim@verona.se>.
author | Glenn Morris <rgm@gnu.org> |
---|---|
date | Wed, 22 Aug 2007 04:01:39 +0000 |
parents | 7bec7031afab |
children | ece5e5e6398e |
comparison
equal
deleted
inserted
replaced
82517:2282e35e680f | 82518:b6db95f12a9d |
---|---|
8197 #endif /* MAC_OS */ | 8197 #endif /* MAC_OS */ |
8198 | 8198 |
8199 #endif /* HAVE_GIF */ | 8199 #endif /* HAVE_GIF */ |
8200 | 8200 |
8201 | 8201 |
8202 | |
8203 /*********************************************************************** | |
8204 SVG | |
8205 ***********************************************************************/ | |
8206 | |
8207 #if defined (HAVE_RSVG) | |
8208 | |
8209 /* Function prototypes. */ | |
8210 | |
8211 static int svg_image_p P_ ((Lisp_Object object)); | |
8212 static int svg_load P_ ((struct frame *f, struct image *img)); | |
8213 | |
8214 static int svg_load_image P_ ((struct frame *, struct image *, | |
8215 unsigned char *, unsigned int)); | |
8216 | |
8217 /* The symbol `svg' identifying images of this type. */ | |
8218 | |
8219 Lisp_Object Qsvg; | |
8220 | |
8221 /* Indices of image specification fields in svg_format, below. */ | |
8222 | |
8223 enum svg_keyword_index | |
8224 { | |
8225 SVG_TYPE, | |
8226 SVG_DATA, | |
8227 SVG_FILE, | |
8228 SVG_ASCENT, | |
8229 SVG_MARGIN, | |
8230 SVG_RELIEF, | |
8231 SVG_ALGORITHM, | |
8232 SVG_HEURISTIC_MASK, | |
8233 SVG_MASK, | |
8234 SVG_BACKGROUND, | |
8235 SVG_LAST | |
8236 }; | |
8237 | |
8238 /* Vector of image_keyword structures describing the format | |
8239 of valid user-defined image specifications. */ | |
8240 | |
8241 static struct image_keyword svg_format[SVG_LAST] = | |
8242 { | |
8243 {":type", IMAGE_SYMBOL_VALUE, 1}, | |
8244 {":data", IMAGE_STRING_VALUE, 0}, | |
8245 {":file", IMAGE_STRING_VALUE, 0}, | |
8246 {":ascent", IMAGE_ASCENT_VALUE, 0}, | |
8247 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0}, | |
8248 {":relief", IMAGE_INTEGER_VALUE, 0}, | |
8249 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8250 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8251 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}, | |
8252 {":background", IMAGE_STRING_OR_NIL_VALUE, 0} | |
8253 }; | |
8254 | |
8255 /* Structure describing the image type `svg'. Its the same type of | |
8256 structure defined for all image formats, handled by emacs image | |
8257 functions. See struct image_type in dispextern.h. */ | |
8258 | |
8259 static struct image_type svg_type = | |
8260 { | |
8261 /* An identifier showing that this is an image structure for the SVG format. */ | |
8262 &Qsvg, | |
8263 /* Handle to a function that can be used to identify a SVG file. */ | |
8264 svg_image_p, | |
8265 /* Handle to function used to load a SVG file. */ | |
8266 svg_load, | |
8267 /* Handle to function to free sresources for SVG. */ | |
8268 x_clear_image, | |
8269 /* An internal field to link to the next image type in a list of | |
8270 image types, will be filled in when registering the format. */ | |
8271 NULL | |
8272 }; | |
8273 | |
8274 | |
8275 /* Return non-zero if OBJECT is a valid SVG image specification. Do | |
8276 this by calling parse_image_spec and supplying the keywords that | |
8277 identify the SVG format. */ | |
8278 | |
8279 static int | |
8280 svg_image_p (object) | |
8281 Lisp_Object object; | |
8282 { | |
8283 struct image_keyword fmt[SVG_LAST]; | |
8284 bcopy (svg_format, fmt, sizeof fmt); | |
8285 | |
8286 if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg)) | |
8287 return 0; | |
8288 | |
8289 /* Must specify either the :data or :file keyword. */ | |
8290 return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1; | |
8291 } | |
8292 | |
8293 #include <librsvg/rsvg.h> | |
8294 | |
8295 /* TO DO: define DEF_IMGLIB_FN here. This macro is used to handle | |
8296 loading of dynamic link library functions for various OS:es. | |
8297 Currently only librsvg2 is supported, which is only available for X, | |
8298 so its not strictly necessary yet. The current code is thought to be | |
8299 compatible with this scheme because of the defines below, should | |
8300 librsvg2 become available on more plattforms. */ | |
8301 | |
8302 #define fn_rsvg_handle_new rsvg_handle_new | |
8303 #define fn_rsvg_handle_set_size_callback rsvg_handle_set_size_callback | |
8304 #define fn_rsvg_handle_write rsvg_handle_write | |
8305 #define fn_rsvg_handle_close rsvg_handle_close | |
8306 #define fn_rsvg_handle_get_pixbuf rsvg_handle_get_pixbuf | |
8307 #define fn_rsvg_handle_free rsvg_handle_free | |
8308 | |
8309 #define fn_gdk_pixbuf_get_width gdk_pixbuf_get_width | |
8310 #define fn_gdk_pixbuf_get_height gdk_pixbuf_get_height | |
8311 #define fn_gdk_pixbuf_get_pixels gdk_pixbuf_get_pixels | |
8312 #define fn_gdk_pixbuf_get_rowstride gdk_pixbuf_get_rowstride | |
8313 #define fn_gdk_pixbuf_get_colorspace gdk_pixbuf_get_colorspace | |
8314 #define fn_gdk_pixbuf_get_n_channels gdk_pixbuf_get_n_channels | |
8315 #define fn_gdk_pixbuf_get_has_alpha gdk_pixbuf_get_has_alpha | |
8316 #define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample | |
8317 | |
8318 | |
8319 /* Load SVG image IMG for use on frame F. Value is non-zero if | |
8320 successful. this function will go into the svg_type structure, and | |
8321 the prototype thus needs to be compatible with that structure. */ | |
8322 | |
8323 static int | |
8324 svg_load (f, img) | |
8325 struct frame *f; | |
8326 struct image *img; | |
8327 { | |
8328 int success_p = 0; | |
8329 Lisp_Object file_name; | |
8330 | |
8331 /* If IMG->spec specifies a file name, create a non-file spec from it. */ | |
8332 file_name = image_spec_value (img->spec, QCfile, NULL); | |
8333 if (STRINGP (file_name)) | |
8334 { | |
8335 Lisp_Object file; | |
8336 unsigned char *contents; | |
8337 int size; | |
8338 struct gcpro gcpro1; | |
8339 | |
8340 file = x_find_image_file (file_name); | |
8341 GCPRO1 (file); | |
8342 if (!STRINGP (file)) | |
8343 { | |
8344 image_error ("Cannot find image file `%s'", file_name, Qnil); | |
8345 UNGCPRO; | |
8346 return 0; | |
8347 } | |
8348 | |
8349 /* Read the entire file into memory. */ | |
8350 contents = slurp_file (SDATA (file), &size); | |
8351 if (contents == NULL) | |
8352 { | |
8353 image_error ("Error loading SVG image `%s'", img->spec, Qnil); | |
8354 UNGCPRO; | |
8355 return 0; | |
8356 } | |
8357 /* If the file was slurped into memory properly, parse it. */ | |
8358 success_p = svg_load_image (f, img, contents, size); | |
8359 xfree (contents); | |
8360 UNGCPRO; | |
8361 } | |
8362 /* Else its not a file, its a lisp object. Load the image from a | |
8363 lisp object rather than a file. */ | |
8364 else | |
8365 { | |
8366 Lisp_Object data; | |
8367 | |
8368 data = image_spec_value (img->spec, QCdata, NULL); | |
8369 success_p = svg_load_image (f, img, SDATA (data), SBYTES (data)); | |
8370 } | |
8371 | |
8372 return success_p; | |
8373 } | |
8374 | |
8375 /* svg_load_image is a helper function for svg_load, which does the actual | |
8376 loading given contents and size, apart from frame and image | |
8377 structures, passed from svg_load. | |
8378 | |
8379 Uses librsvg to do most of the image processing. | |
8380 | |
8381 Returns non-zero when sucessful. */ | |
8382 static int | |
8383 svg_load_image (f, img, contents, size) | |
8384 /* Pointer to emacs frame sturcture. */ | |
8385 struct frame *f; | |
8386 /* Pointer to emacs image structure. */ | |
8387 struct image *img; | |
8388 /* String containing the SVG XML data to be parsed. */ | |
8389 unsigned char *contents; | |
8390 /* Size of data in bytes. */ | |
8391 unsigned int size; | |
8392 { | |
8393 RsvgHandle *rsvg_handle; | |
8394 GError *error = NULL; | |
8395 GdkPixbuf *pixbuf; | |
8396 int width; | |
8397 int height; | |
8398 const guint8 *pixels; | |
8399 int rowstride; | |
8400 XImagePtr ximg; | |
8401 XColor background; | |
8402 int x; | |
8403 int y; | |
8404 | |
8405 /* g_type_init is a glib function that must be called prior to using | |
8406 gnome type library functions. */ | |
8407 g_type_init (); | |
8408 /* Make a handle to a new rsvg object. */ | |
8409 rsvg_handle = fn_rsvg_handle_new (); | |
8410 | |
8411 /* Parse the contents argument and fill in the rsvg_handle. */ | |
8412 fn_rsvg_handle_write (rsvg_handle, contents, size, &error); | |
8413 if (error) | |
8414 goto rsvg_error; | |
8415 | |
8416 /* The parsing is complete, rsvg_handle is ready to used, close it | |
8417 for further writes. */ | |
8418 fn_rsvg_handle_close (rsvg_handle, &error); | |
8419 if (error) | |
8420 goto rsvg_error; | |
8421 /* We can now get a valid pixel buffer from the svg file, if all | |
8422 went ok. */ | |
8423 pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle); | |
8424 eassert (pixbuf); | |
8425 | |
8426 /* Extract some meta data from the svg handle. */ | |
8427 width = fn_gdk_pixbuf_get_width (pixbuf); | |
8428 height = fn_gdk_pixbuf_get_height (pixbuf); | |
8429 pixels = fn_gdk_pixbuf_get_pixels (pixbuf); | |
8430 rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf); | |
8431 | |
8432 /* Validate the svg meta data. */ | |
8433 eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB); | |
8434 eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4); | |
8435 eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf)); | |
8436 eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8); | |
8437 | |
8438 /* Try to create a x pixmap to hold the svg pixmap. */ | |
8439 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) { | |
8440 g_object_unref (pixbuf); | |
8441 return 0; | |
8442 } | |
8443 | |
8444 init_color_table (); | |
8445 | |
8446 /* TODO: The code is somewhat prepared for other environments than | |
8447 X, but is far from done. */ | |
8448 #ifdef HAVE_X_WINDOWS | |
8449 | |
8450 background.pixel = FRAME_BACKGROUND_PIXEL (f); | |
8451 x_query_color (f, &background); | |
8452 | |
8453 /* SVG pixmaps specify transparency in the last byte, so right shift | |
8454 8 bits to get rid of it, since emacs doesnt support | |
8455 transparency. */ | |
8456 background.red >>= 8; | |
8457 background.green >>= 8; | |
8458 background.blue >>= 8; | |
8459 | |
8460 #else /* not HAVE_X_WINDOWS */ | |
8461 #error FIXME | |
8462 #endif | |
8463 | |
8464 /* This loop handles opacity values, since Emacs assumes | |
8465 non-transparent images. Each pixel must be "flattened" by | |
8466 calculating he resulting color, given the transparency of the | |
8467 pixel, and the image background color. */ | |
8468 for (y = 0; y < height; ++y) | |
8469 { | |
8470 for (x = 0; x < width; ++x) | |
8471 { | |
8472 unsigned red; | |
8473 unsigned green; | |
8474 unsigned blue; | |
8475 unsigned opacity; | |
8476 | |
8477 red = *pixels++; | |
8478 green = *pixels++; | |
8479 blue = *pixels++; | |
8480 opacity = *pixels++; | |
8481 | |
8482 red = ((red * opacity) | |
8483 + (background.red * ((1 << 8) - opacity))); | |
8484 green = ((green * opacity) | |
8485 + (background.green * ((1 << 8) - opacity))); | |
8486 blue = ((blue * opacity) | |
8487 + (background.blue * ((1 << 8) - opacity))); | |
8488 | |
8489 XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue)); | |
8490 } | |
8491 | |
8492 pixels += rowstride - 4 * width; | |
8493 } | |
8494 | |
8495 #ifdef COLOR_TABLE_SUPPORT | |
8496 /* Remember colors allocated for this image. */ | |
8497 img->colors = colors_in_color_table (&img->ncolors); | |
8498 free_color_table (); | |
8499 #endif /* COLOR_TABLE_SUPPORT */ | |
8500 | |
8501 g_object_unref (pixbuf); | |
8502 | |
8503 /* Put the image into the pixmap, then free the X image and its | |
8504 buffer. */ | |
8505 x_put_x_image (f, ximg, img->pixmap, width, height); | |
8506 x_destroy_x_image (ximg); | |
8507 | |
8508 img->width = width; | |
8509 img->height = height; | |
8510 | |
8511 return 1; | |
8512 | |
8513 rsvg_error: | |
8514 /* FIXME: Use error->message so the user knows what is the actual | |
8515 problem with the image. */ | |
8516 image_error ("Error parsing SVG image `%s'", img->spec, Qnil); | |
8517 g_error_free (error); | |
8518 return 0; | |
8519 } | |
8520 | |
8521 #endif /* defined (HAVE_RSVG) */ | |
8522 | |
8523 | |
8524 | |
8202 | 8525 |
8203 /*********************************************************************** | 8526 /*********************************************************************** |
8204 Ghostscript | 8527 Ghostscript |
8205 ***********************************************************************/ | 8528 ***********************************************************************/ |
8206 | 8529 |
8589 #if defined (HAVE_PNG) || defined (MAC_OS) | 8912 #if defined (HAVE_PNG) || defined (MAC_OS) |
8590 if (EQ (type, Qpng)) | 8913 if (EQ (type, Qpng)) |
8591 return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries); | 8914 return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries); |
8592 #endif | 8915 #endif |
8593 | 8916 |
8917 #if defined (HAVE_RSVG) | |
8918 if (EQ (type, Qsvg)) | |
8919 return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries); | |
8920 #endif | |
8921 | |
8594 #ifdef HAVE_GHOSTSCRIPT | 8922 #ifdef HAVE_GHOSTSCRIPT |
8595 if (EQ (type, Qpostscript)) | 8923 if (EQ (type, Qpostscript)) |
8596 return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries); | 8924 return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries); |
8597 #endif | 8925 #endif |
8598 | 8926 |
8731 Qpng = intern ("png"); | 9059 Qpng = intern ("png"); |
8732 staticpro (&Qpng); | 9060 staticpro (&Qpng); |
8733 ADD_IMAGE_TYPE(Qpng); | 9061 ADD_IMAGE_TYPE(Qpng); |
8734 #endif | 9062 #endif |
8735 | 9063 |
9064 #if defined (HAVE_RSVG) | |
9065 Qsvg = intern ("svg"); | |
9066 staticpro (&Qsvg); | |
9067 ADD_IMAGE_TYPE(Qsvg); | |
9068 #endif | |
9069 | |
9070 | |
8736 defsubr (&Sinit_image_library); | 9071 defsubr (&Sinit_image_library); |
8737 defsubr (&Sclear_image_cache); | 9072 defsubr (&Sclear_image_cache); |
8738 defsubr (&Simage_refresh); | 9073 defsubr (&Simage_refresh); |
8739 defsubr (&Simage_size); | 9074 defsubr (&Simage_size); |
8740 defsubr (&Simage_mask_p); | 9075 defsubr (&Simage_mask_p); |