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