unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: joakim@verona.se
To: emacs-devel <emacs-devel@gnu.org>
Subject: Re: SVG support(again) ?
Date: Sat, 18 Aug 2007 13:44:57 +0200	[thread overview]
Message-ID: <m3r6m1cbie.fsf@kurono.home> (raw)
In-Reply-To: <E1ILpku-0002ZE-Vq@fencepost.gnu.org> (Richard Stallman's message of "Thu\, 16 Aug 2007 20\:32\:00 -0400")

Richard Stallman <rms@gnu.org> writes:

>     /* Structure describing the image type `svg'.  */
>
>     static struct image_type svg_type =
>     {
>       &Qsvg,
>       svg_image_p,
>       svg_load,
>       x_clear_image,
>       NULL
>     };
>
> How about adding another comment for each field explaining what
> the field means and why this particular value is used.
>
>     /* DEF_IMGLIB_FN() here? */
>
> I don't understand that comment -- if you do, could you make
> it less terse, and clear?
>
>     /* helper function for svg_load, does the actual loading
>      given contents and size, apart from frame and image structures, passed from svg_load
>
>      Uses librsvg to do most of the image processing.
>
>      Returns non-zero when sucessful
>     */
>
> That is terse and cryptic.  Could you rewrite it to be clear
> and format it the way we like to do?
>
> The code of svg_load_image needs more comments explaining what the
> parts of the code do.

Here is a new try. I believe this is quite readable now.
Note that some of the difficulty in understanding this code comes from
reading it in isolation from the other code im image.c. I tried
adding some helpful pointers to other emacs code.


/***********************************************************************
				 SVG
 ***********************************************************************/

#if defined (HAVE_RSVG)

/* Function prototypes.  */

static int svg_image_p P_ ((Lisp_Object object));
static int svg_load P_ ((struct frame *f, struct image *img));

static int svg_load_image P_ ((struct frame *, struct image *,
			       unsigned char *, unsigned int));

/* The symbol `svg' identifying images of this type. */

Lisp_Object Qsvg;

/* Indices of image specification fields in svg_format, below.  */

enum svg_keyword_index
{
  SVG_TYPE,
  SVG_DATA,
  SVG_FILE,
  SVG_ASCENT,
  SVG_MARGIN,
  SVG_RELIEF,
  SVG_ALGORITHM,
  SVG_HEURISTIC_MASK,
  SVG_MASK,
  SVG_BACKGROUND,
  SVG_LAST
};

/* Vector of image_keyword structures describing the format
   of valid user-defined image specifications.  */

static struct image_keyword svg_format[SVG_LAST] =
{
  {":type",		IMAGE_SYMBOL_VALUE,			1},
  {":data",		IMAGE_STRING_VALUE,			0},
  {":file",		IMAGE_STRING_VALUE,			0},
  {":ascent",		IMAGE_ASCENT_VALUE,			0},
  {":margin",		IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,	0},
  {":relief",		IMAGE_INTEGER_VALUE,			0},
  {":conversion",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
  {":heuristic-mask",	IMAGE_DONT_CHECK_VALUE_TYPE,		0},
  {":mask",		IMAGE_DONT_CHECK_VALUE_TYPE,		0},
  {":background",	IMAGE_STRING_OR_NIL_VALUE,		0}
};

/* Structure describing the image type `svg'.  Its the same type of
   structure defined for all image formats, handled by emacs image functions.
   see struct image_type in dispextern.h
*/

static struct image_type svg_type =
{
  &Qsvg, /* an identifier showing that this is an image structure for the SVG format*/
  svg_image_p, /* handle to a function that can be used to identify a svg file*/
  svg_load, /* handle to function used to load a svg file*/
  x_clear_image,/* handle to function to free sresources for SVG*/
  NULL /* an internal field to link to the next image type in a list of image types, will be filled in when registering the format*/
};


/* Return non-zero if OBJECT is a valid SVG image specification.
   do this by calling parse_image_spec and supplying the keywords that identify the SVG format
 */

static int
svg_image_p (object)
     Lisp_Object object;
{
  struct image_keyword fmt[SVG_LAST];
  bcopy (svg_format, fmt, sizeof fmt);

  if (!parse_image_spec (object, fmt, SVG_LAST, Qsvg))
    return 0;

  /* Must specify either the :data or :file keyword.  */
  return fmt[SVG_FILE].count + fmt[SVG_DATA].count == 1;
}

#include <librsvg/rsvg.h>

/* DEF_IMGLIB_FN() here in the future.
this macro is used to handle loading of dynamic link library functions for various OS:es.
currently only librsvg2 is supportedd, which is only available for X, so its not strictly necessary yet.
The current code is thought to be compatible with this scheme because of the defines below, should librsvg2 become available on more plattforms.
*/

#define fn_rsvg_handle_new		rsvg_handle_new
#define fn_rsvg_handle_set_size_callback rsvg_handle_set_size_callback
#define fn_rsvg_handle_write		rsvg_handle_write
#define fn_rsvg_handle_close		rsvg_handle_close
#define fn_rsvg_handle_get_pixbuf	rsvg_handle_get_pixbuf
#define fn_rsvg_handle_free		rsvg_handle_free

#define fn_gdk_pixbuf_get_width		gdk_pixbuf_get_width
#define fn_gdk_pixbuf_get_height	gdk_pixbuf_get_height
#define fn_gdk_pixbuf_get_pixels	gdk_pixbuf_get_pixels
#define fn_gdk_pixbuf_get_rowstride	gdk_pixbuf_get_rowstride
#define fn_gdk_pixbuf_get_colorspace	gdk_pixbuf_get_colorspace
#define fn_gdk_pixbuf_get_n_channels	gdk_pixbuf_get_n_channels
#define fn_gdk_pixbuf_get_has_alpha	gdk_pixbuf_get_has_alpha
#define fn_gdk_pixbuf_get_bits_per_sample gdk_pixbuf_get_bits_per_sample


/* Load SVG image IMG for use on frame F.  Value is non-zero if
   successful. this function wil go into the svg_type structure, and
   the prototype thus needs to be compatible with that structure */

static int
svg_load (f, img)
     struct frame *f;
     struct image *img;
{
  int success_p = 0;
  Lisp_Object file_name;

  /* If IMG->spec specifies a file name, create a non-file spec from it.  */
  file_name = image_spec_value (img->spec, QCfile, NULL);
  if (STRINGP (file_name))
    {
      Lisp_Object file;
      unsigned char *contents;
      int size;
      struct gcpro gcpro1;

      file = x_find_image_file (file_name);
      GCPRO1 (file);
      if (!STRINGP (file))
      {
        image_error ("Cannot find image file `%s'", file_name, Qnil);
        UNGCPRO;
        return 0;
      }

      contents = slurp_file (SDATA (file), &size); /* read the entire file into memory*/
      if (contents == NULL)
      {
        image_error ("Error loading SVG image `%s'", img->spec, Qnil);
        UNGCPRO;
        return 0;
      }

      success_p = svg_load_image (f, img, contents, size); /* if the file was slurped into memory properly, parse it*/
      xfree (contents);
      UNGCPRO;
    }
  else/*its not a file, its a lisp object*/
    {
      Lisp_Object data;

      data = image_spec_value (img->spec, QCdata, NULL);
      success_p = svg_load_image (f, img, SDATA (data), SBYTES (data));
    }

  return success_p;
}

/* helper function for svg_load, does the actual loading
 given contents and size, apart from frame and image structures, passed from svg_load

 Uses librsvg to do most of the image processing.
 
 Returns non-zero when sucessful
*/
static int
svg_load_image (f, img, contents, size)
     struct frame *f;
     struct image *img;
     unsigned char *contents;
     unsigned int size;
{
  RsvgHandle *rsvg_handle;
  GError *error = NULL;
  GdkPixbuf *pixbuf;
  int width;
  int height;
  const guint8 *pixels;
  int rowstride;
  XImagePtr ximg;
  XColor background;
  int x;
  int y;

  g_type_init (); /*glib function that must be called prior to using gnome type library functions*/
  rsvg_handle = fn_rsvg_handle_new ();/* make a handle to a new rsvg object*/

  fn_rsvg_handle_write (rsvg_handle, contents, size, &error);/*parse "contents" and fill in the rsvg_handle*/
  if (error)
    goto rsvg_error;

  fn_rsvg_handle_close (rsvg_handle, &error);/*the parsing is complete, rsvg_handle is ready to use*/
  if (error)
    goto rsvg_error;

  pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle);/* we can now get a valid pixel buffer from the svg file, if all went ok*/
  eassert (pixbuf);

  /* extract some meta data from he svg handle*/
  width     = fn_gdk_pixbuf_get_width (pixbuf);
  height    = fn_gdk_pixbuf_get_height (pixbuf);
  pixels    = fn_gdk_pixbuf_get_pixels (pixbuf);
  rowstride = fn_gdk_pixbuf_get_rowstride (pixbuf);

  /*validate the svg meta data*/
  eassert (fn_gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
  eassert (fn_gdk_pixbuf_get_n_channels (pixbuf) == 4);
  eassert (fn_gdk_pixbuf_get_has_alpha (pixbuf));
  eassert (fn_gdk_pixbuf_get_bits_per_sample (pixbuf) == 8);

  /* try to create a x pixmap to hold the svg pixmap*/
  if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap)) {
    g_object_unref (pixbuf);
    return 0;
  }

  init_color_table ();

#ifdef HAVE_X_WINDOWS

  background.pixel = FRAME_BACKGROUND_PIXEL (f);
  x_query_color (f, &background);

  /* svg pixmaps specify transparency in the last byte, so right shift 8 bits to get rid of it, since emacs doesnt support transparency*/
  background.red   >>= 8;
  background.green >>= 8;
  background.blue  >>= 8;

#else /* not HAVE_X_WINDOWS */
#error FIXME
#endif

  /* this loop handles opacity values, since emacs assumes
     non-transparent images.  Each pixel must be "flattened" by
     calculating he resulting color, given the transparency of the
     pixel, and the image background color.
   */
  for (y = 0; y < height; ++y)
    {
      for (x = 0; x < width; ++x)
	{
	  unsigned red;
	  unsigned green;
	  unsigned blue;
	  unsigned opacity;

	  red     = *pixels++;
	  green   = *pixels++;
	  blue    = *pixels++;
	  opacity = *pixels++;

	  red   = ((red * opacity)
		   + (background.red * ((1 << 8) - opacity)));
	  green = ((green * opacity)
		   + (background.green * ((1 << 8) - opacity)));
	  blue  = ((blue * opacity)
		   + (background.blue * ((1 << 8) - opacity)));

	  XPutPixel (ximg, x, y, lookup_rgb_color (f, red, green, blue));
	}

      pixels += rowstride - 4 * width;
    }

#ifdef COLOR_TABLE_SUPPORT
  /* Remember colors allocated for this image.  */
  img->colors = colors_in_color_table (&img->ncolors);
  free_color_table ();
#endif /* COLOR_TABLE_SUPPORT */

  g_object_unref (pixbuf);

  /* Put the image into the pixmap, then free the X image and its buffer. */
  x_put_x_image (f, ximg, img->pixmap, width, height);
  x_destroy_x_image (ximg);

  img->width  = width;
  img->height = height;

  return 1;

 rsvg_error:
  /* FIXME: Use error->message. */
  image_error ("Error parsing SVG image `%s'", img->spec, Qnil);
  g_error_free (error);
  return 0;
}

#endif	/* defined (HAVE_RSVG) */



-- 
Joakim Verona

  reply	other threads:[~2007-08-18 11:44 UTC|newest]

Thread overview: 106+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-08 23:56 SVG support(again) ? joakim
2007-08-09 21:17 ` joakim
2007-08-09 21:36   ` David Kastrup
2007-08-09 21:45     ` Jason Rumney
2007-08-09 21:58       ` joakim
2007-08-09 21:48     ` joakim
2007-08-11  5:05   ` Richard Stallman
2007-08-14 11:57     ` joakim
2007-08-14 23:26       ` Richard Stallman
2007-08-15  7:11         ` Mathias Dahl
2007-08-16  9:03         ` joakim
2007-08-17  0:32           ` Richard Stallman
2007-08-18 11:44             ` joakim [this message]
2007-08-19  0:45               ` Richard Stallman
2007-08-19 12:35                 ` joakim
2007-08-19 22:30                   ` Richard Stallman
2007-08-20  9:31                     ` joakim
2007-08-21 14:45                       ` Richard Stallman
2007-08-21 14:59                         ` joakim
2007-08-22  4:12                           ` Glenn Morris
2007-08-22  7:23                             ` joakim
2007-08-29 16:27                             ` svn icons in the toolbar (was: SVG support(again) ?) Leo
2007-08-30  5:08                               ` svn icons in the toolbar Jan Djärv
2007-08-30 20:44                                 ` Leo
2007-08-31  5:59                                   ` Jan Djärv
2007-08-31  7:07                                   ` Benjamin Hawkes-Lewis
2007-09-01 13:57                                     ` Leo
2007-08-30 20:50                                 ` Richard Stallman
2007-09-02  0:33                                   ` Leo
2007-09-03  3:04                                     ` Richard Stallman
2007-09-03  6:26                                       ` Jan Djärv
2007-09-04  0:56                                         ` Richard Stallman
2007-09-03  7:08                                       ` Benjamin Hawkes-Lewis
2007-09-03  7:53                                         ` joakim
2007-09-03  7:55                                           ` Leo
2007-09-03 17:38                                           ` David Reitter
2007-09-04  0:56                                         ` Richard Stallman
2007-09-04  4:01                                           ` tomas
2007-09-04 22:57                                             ` Richard Stallman
2007-09-05  3:31                                               ` tomas
2007-09-04  4:54                                           ` YAMAMOTO Mitsuharu
2007-09-04  6:06                                             ` David Kastrup
2007-09-04 22:57                                             ` Richard Stallman
2007-09-05  0:20                                               ` YAMAMOTO Mitsuharu
2007-09-05 20:02                                                 ` Richard Stallman
2007-09-05 20:40                                                   ` Chong Yidong
2007-09-05 22:54                                                   ` Leo
2007-09-06  6:02                                                     ` Jan Djärv
2007-09-06  6:00                                                   ` Jan Djärv
2007-09-07  6:32                                                     ` Richard Stallman
2007-09-07  7:04                                                       ` Leo
2007-09-07  8:12                                                         ` Jan Djärv
2007-09-07 10:22                                                           ` Leo
2007-09-08  7:01                                                         ` Richard Stallman
2007-09-07  7:10                                                       ` Jan Djärv
2007-09-08  7:00                                                         ` Richard Stallman
2007-09-03  7:54                                       ` Leo
2007-09-02  4:32                                 ` Leo
2007-09-02  8:07                                   ` Benjamin Hawkes-Lewis
2007-09-02  9:04                                     ` Jan Djärv
2007-09-02  8:23                                   ` Jan Djärv
2007-09-02  9:06                                     ` Leo
2007-09-02 13:29                                       ` Jan Djärv
2007-09-02 13:52                                         ` Leo
2007-09-02 14:04                                         ` Redundant icon in tool-bar (was: svn icons in the toolbar) Leo
2007-09-02 15:39                                           ` Redundant icon in tool-bar Jan Djärv
2007-09-02 16:00                                             ` Leo
2007-09-02 14:09                                         ` svn icons in the toolbar Leo
2007-09-02 15:43                                           ` Jan Djärv
2007-09-02 16:00                                             ` Leo
2007-09-02 17:28                                               ` Jan Djärv
2007-09-05 23:53                                                 ` Leo
2007-09-26 20:11                                                   ` gmm-tool-bar-style (was: svn icons in the toolbar) Reiner Steib
2007-09-02 17:46                                         ` svn icons in the toolbar Jan Djärv
2007-09-02 17:58                                           ` Leo
2007-09-21 10:24                                             ` Leo
2007-09-21 11:13                                               ` Jan Djärv
2007-09-21 11:17                                                 ` Leo
2007-09-21 12:08                                                   ` Jan Djärv
2007-09-21 12:45                                                     ` Leo
2007-09-21 13:08                                                       ` Jan Djärv
2007-09-21 14:18                                                         ` Leo
2007-09-21 15:14                                                           ` Jan Djärv
2007-09-21 16:03                                                             ` Leo
2007-09-18 21:55                                           ` Stephen Berman
2007-09-19  6:26                                             ` Jan Djärv
2007-09-19  9:10                                               ` Stephen Berman
2007-09-19  9:20                                               ` Stephen Berman
2007-09-19  9:54                                                 ` Leo
2007-09-19 10:08                                                   ` Jan Djärv
2007-09-19 10:40                                                   ` Stephen Berman
2007-09-19 10:02                                                 ` Jan Djärv
2007-09-19 10:41                                                   ` Stephen Berman
2007-09-20 16:35                                                 ` Richard Stallman
2007-09-24 15:56                                                   ` Stephen Berman
2007-09-25 10:44                                                     ` Richard Stallman
2007-09-25 11:43                                                       ` Frank Schmitt
2007-09-25 13:54                                                         ` Stephen Berman
2007-09-26  6:17                                                           ` Jan Djärv
2007-09-26 16:29                                                             ` Richard Stallman
2007-09-26 16:43                                                     ` Dan Nicolaescu
2007-09-19 21:22                                               ` Stephen Berman
2007-09-20  6:24                                                 ` Jan Djärv
2007-09-24 15:56                                                   ` Stephen Berman
2007-09-24 16:04                                                     ` Jan Djärv
2007-11-04 13:24                                                 ` Stephen Berman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=m3r6m1cbie.fsf@kurono.home \
    --to=joakim@verona.se \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).