unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* SVG and Emacs
@ 2004-09-20  1:02 Paul Pogonyshev
  2004-09-20 15:17 ` Richard Stallman
  0 siblings, 1 reply; 6+ messages in thread
From: Paul Pogonyshev @ 2004-09-20  1:02 UTC (permalink / raw)


There is an item in `etc/TODO' that says: ``Add support
for SVG (Scalable Vector Graphics) rendering to Emacs.''

Has anybody started on this?  If not, I may be willing
to have a try, provided that `librsvg' usage is acceptable.
That library (basically) requires GTK+, libart, libxml and
Xft2.  Doesn't mean that it cannot be used in Emacs
`--with-x', of course.

Paul

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: SVG and Emacs
  2004-09-20  1:02 SVG and Emacs Paul Pogonyshev
@ 2004-09-20 15:17 ` Richard Stallman
  2004-09-20 20:38   ` Paul Pogonyshev
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Stallman @ 2004-09-20 15:17 UTC (permalink / raw)
  Cc: emacs-devel

    Has anybody started on this?  If not, I may be willing
    to have a try, provided that `librsvg' usage is acceptable.
    That library (basically) requires GTK+, libart, libxml and
    Xft2.

It is rather a heavyweight solution.  Is there no library
for SVG which doesn't need these things?

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: SVG and Emacs
  2004-09-20 15:17 ` Richard Stallman
@ 2004-09-20 20:38   ` Paul Pogonyshev
  2004-09-22  7:11     ` Richard Stallman
  0 siblings, 1 reply; 6+ messages in thread
From: Paul Pogonyshev @ 2004-09-20 20:38 UTC (permalink / raw)
  Cc: emacs-devel


>     Has anybody started on this?  If not, I may be willing
>     to have a try, provided that `librsvg' usage is acceptable.
>     That library (basically) requires GTK+, libart, libxml and
>     Xft2.
>
> It is rather a heavyweight solution.  Is there no library
> for SVG which doesn't need these things?

I only know about librsvg and ksvg (KDE SVG library, must be
much heavier).

Actually, librsvg doesn't use full GTK+, only gdk-pixbuf,
GLib and Pango.  Maybe it could be made dynamically-loadable
(though I can't say I'm familiar with dynamic library loading).

Paul

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: SVG and Emacs
  2004-09-20 20:38   ` Paul Pogonyshev
@ 2004-09-22  7:11     ` Richard Stallman
  2004-09-25 20:31       ` Paul Pogonyshev
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Stallman @ 2004-09-22  7:11 UTC (permalink / raw)
  Cc: emacs-devel

    Actually, librsvg doesn't use full GTK+, only gdk-pixbuf,
    GLib and Pango.  Maybe it could be made dynamically-loadable
    (though I can't say I'm familiar with dynamic library loading).

Maybe that is ok.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: SVG and Emacs
  2004-09-22  7:11     ` Richard Stallman
@ 2004-09-25 20:31       ` Paul Pogonyshev
  2004-09-26  8:27         ` Richard Stallman
  0 siblings, 1 reply; 6+ messages in thread
From: Paul Pogonyshev @ 2004-09-25 20:31 UTC (permalink / raw)
  Cc: emacs-devel

RMS wrote:

>     Actually, librsvg doesn't use full GTK+, only gdk-pixbuf,
>     GLib and Pango.  Maybe it could be made dynamically-loadable
>     (though I can't say I'm familiar with dynamic library loading).
>
> Maybe that is ok.

Here is the first shot.  It is extremely non-portable, hackish and
ugly, but it works! :)

Do we want to continue in this direction?  If yes, then I'm open for
suggestions, especially on how to improve `configure.in' and
`Makefile.in' bits.  Portability is also a major issue.  I only work
under GNU/Linux and I don't really know how portable `librsvg' is,
in the first place.

Also, do we want to make SVG rendering dynamically loadable
(optionally?)  Actually, if we go on this, we can as well make all
the rest of image renderers load their libraries with dlopen().
From what I understood by looking at the code, the libraries are
already loaded dynamically under WinNT, so there must not be any
principal show-stoppers here.

Note that many ``1 ||'' in `image.c' are because I didn't run
Autoheader and so `HAVE_RSVG' didn't make its way to `config.h'.

Two side note on `configure.in':

* Many modules (i.e. image-rendering modules) that are built by
  default are mentioned as `--with-xxx  use -lxxx ...' in the help
  output.  It seems more logical to write
  `--without-xxx  don't use -lxxx ...'

* Maybe it is better to use AC_HELP_STRING()?

Paul


--- configure.in	04 May 2004 19:24:09 -0200	1.367
+++ configure.in	25 Sep 2004 16:16:10 -0200	
@@ -109,10 +109,12 @@ AC_ARG_WITH(gif,
 [  --with-gif              use -lungif for displaying GIF images])
 AC_ARG_WITH(png,
 [  --with-png              use -lpng for displaying PNG images])
+AC_ARG_WITH(rsvg,
+[  --with-rsvg             use -lrsvg-2 for displaying SVG images])
 AC_ARG_WITH(gtk,
 [  --with-gtk              use GTK (same as --with-x-toolkit=gtk)])
 AC_ARG_WITH(pkg-config-prog,
-[  --with-pkg-config-prog  Path to pkg-config to use for finding GTK])
+[  --with-pkg-config-prog  path to pkg-config to use for finding GTK and librsvg])
 AC_ARG_WITH(toolkit-scroll-bars,
 [  --without-toolkit-scroll-bars
                           don't use Motif or Xaw3d scroll bars])
@@ -1926,6 +1928,31 @@ AC_DEFUN([PKG_CHECK_MODULES], [
   fi
 ])
 
+### Use -lrsvg-2 if available, unless `--with-rsvg=no' is specified.
+HAVE_RSVG=no
+if test "${HAVE_X11}" = "yes"; then
+  if test "${with_rsvg}" != "no"; then
+    dnl Check if `--with-pkg-config-prog' has been given.
+    if test "X${with_pkg_config_prog}" != X; then
+      PKG_CONFIG="${with_pkg_config_prog}"
+    fi
+
+    RSVG_REQUIRED=2.0.0
+    RSVG_MODULE="librsvg-2.0 >= $RSVG_REQUIRED"
+
+    PKG_CHECK_MODULES(RSVG, $RSVG_MODULE, :, :)
+    AC_SUBST(RSVG_CFLAGS)
+    AC_SUBST(RSVG_LIBS)
+
+    if test ".${RSVG_CFLAGS}" != "."; then
+      HAVE_RSVG=yes
+      AC_DEFINE(HAVE_RSVG, 1, [Define to 1 if using librsvg.])
+      CFLAGS="$CFLAGS $RSVG_CFLAGS"
+      LIBS="$RSVG_LIBS $LIBS"
+    fi
+  fi
+fi
+
 HAVE_GTK=no
 if test "${with_gtk}" = "yes" || test "$USE_X_TOOLKIT" = "gtk"; then
   if test "$USE_X_TOOLKIT" != "none" && test "$USE_X_TOOLKIT" != "maybe"; then
@@ -3035,6 +3062,7 @@ echo "  Does Emacs use -ljpeg?          
 echo "  Does Emacs use -ltiff?                                  ${HAVE_TIFF}"
 echo "  Does Emacs use -lungif?                                 ${HAVE_GIF}"
 echo "  Does Emacs use -lpng?                                   ${HAVE_PNG}"
+echo "  Does Emacs use -lrsvg-2?                                ${HAVE_RSVG}"
 echo "  Does Emacs use X toolkit scroll bars?                   ${USE_TOOLKIT_SCROLL_BARS}"
 echo
 
--- lisp/image-file.el	01 Sep 2003 13:45:13 -0200	1.19
+++ lisp/image-file.el	25 Sep 2004 17:54:33 -0200	
@@ -38,7 +38,7 @@
 
 ;;;###autoload
 (defcustom image-file-name-extensions
-  '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm")
+  '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg")
   "*A list of image-file filename extensions.
 Filenames having one of these extensions are considered image files,
 in addition to those matching `image-file-name-regexps'.
--- lisp/image.el	21 Jun 2004 19:52:28 -0200	1.42
+++ lisp/image.el	25 Sep 2004 17:58:38 -0200	
@@ -40,7 +40,8 @@
     ("\\`[\t\n\r ]*#define" . xbm)
     ("\\`\\(MM\0\\*\\|II\\*\0\\)" . tiff)
     ("\\`[\t\n\r ]*%!PS" . postscript)
-    ("\\`\xff\xd8" . (image-jpeg-p . jpeg)))
+    ("\\`\xff\xd8" . (image-jpeg-p . jpeg))
+    ("\\`<\\?xml " . svg))
   "Alist of (REGEXP . IMAGE-TYPE) pairs used to auto-detect image types.
 When the first bytes of an image file match REGEXP, it is assumed to
 be of image type IMAGE-TYPE if IMAGE-TYPE is a symbol.  If not a symbol,
--- src/image.c	30 Jun 2004 11:11:36 -0200	1.16
+++ src/image.c	25 Sep 2004 18:16:31 -0200	
@@ -7589,6 +7589,277 @@ gif_load (f, img)
 
 #endif /* HAVE_GIF */
 
+ 
+/***********************************************************************
+				 SVG
+ ***********************************************************************/
+
+#if 1 || 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'.  */
+
+static struct image_type svg_type =
+{
+  &Qsvg,
+  svg_image_p,
+  svg_load,
+  x_clear_image,
+  NULL
+};
+
+
+/* Return non-zero if OBJECT is a valid SVG image specification.  */
+
+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? */
+
+#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.  */
+
+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);
+      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);
+      xfree (contents);
+      UNGCPRO;
+    }
+  else
+    {
+      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;
+}
+
+
+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 ();
+  rsvg_handle = fn_rsvg_handle_new ();
+
+  fn_rsvg_handle_write (rsvg_handle, contents, size, &error);
+  if (error)
+    goto rsvg_error;
+
+  fn_rsvg_handle_close (rsvg_handle, &error);
+  if (error)
+    goto rsvg_error;
+
+  pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle);
+  eassert (pixbuf);
+
+  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);
+
+  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);
+
+  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);
+
+  background.red   >>= 8;
+  background.green >>= 8;
+  background.blue  >>= 8;
+
+#else /* not HAVE_X_WINDOWS */
+#error FIXME
+#endif
+
+  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) */
+
 
  
 /***********************************************************************
@@ -7976,6 +8247,11 @@ of `image-library-alist', which see).  *
     return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries);
 #endif
 
+#if 1 || defined (HAVE_RSVG)
+  if (EQ (type, Qsvg))
+    return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries);
+#endif
+
 #ifdef HAVE_GHOSTSCRIPT
   if (EQ (type, Qpostscript))
     return CHECK_LIB_AVAILABLE (&gs_type, init_gs_functions, libraries);
@@ -8082,6 +8358,12 @@ To check whether it is really supported,
   ADD_IMAGE_TYPE(Qpng);
 #endif
 
+#if 1 || defined (HAVE_RSVG)
+  Qsvg = intern ("svg");
+  staticpro (&Qsvg);
+  ADD_IMAGE_TYPE(Qsvg);
+#endif
+
   defsubr (&Sinit_image_library);
   defsubr (&Sclear_image_cache);
   defsubr (&Simage_size);
--- src/Makefile.in	10 Sep 2004 21:26:00 -0200	1.300
+++ src/Makefile.in	25 Sep 2004 16:25:50 -0200	
@@ -280,7 +280,7 @@ TOOLKIT_DEFINES =
 
 /* C_SWITCH_X_SITE must come before C_SWITCH_X_MACHINE and C_SWITCH_X_SYSTEM
    since it may have -I options that should override those two.  */
-ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS}
+ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(TOOLKIT_DEFINES) $(MYCPPFLAGS) -I. -I${srcdir} C_SWITCH_MACHINE C_SWITCH_SYSTEM C_SWITCH_SITE @RSVG_CFLAGS@ C_SWITCH_X_SITE C_SWITCH_X_MACHINE C_SWITCH_X_SYSTEM C_SWITCH_SYSTEM_TEMACS ${CFLAGS}
 .c.o:
 	$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<
 
@@ -444,7 +444,7 @@ LIBXT=$(LIBW)
 /* LD_SWITCH_X_DEFAULT comes after everything else that specifies
    options for where to find X libraries, but before those libraries.  */
 X11_LDFLAGS = LD_SWITCH_X_SITE LD_SWITCH_X_DEFAULT
-LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM
+LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM @RSVG_LIBS@ LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM
 #else /* not HAVE_X11 */
 LIBX= $(LIBXMENU) LD_SWITCH_X_SITE -lX10 LIBX10_MACHINE LIBX10_SYSTEM
 #endif /* not HAVE_X11 */

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: SVG and Emacs
  2004-09-25 20:31       ` Paul Pogonyshev
@ 2004-09-26  8:27         ` Richard Stallman
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Stallman @ 2004-09-26  8:27 UTC (permalink / raw)
  Cc: emacs-devel

    Here is the first shot.  It is extremely non-portable, hackish and
    ugly, but it works! :)

I don't have time to read the code, but I am please that the
amount of new code is so small.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2004-09-26  8:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-20  1:02 SVG and Emacs Paul Pogonyshev
2004-09-20 15:17 ` Richard Stallman
2004-09-20 20:38   ` Paul Pogonyshev
2004-09-22  7:11     ` Richard Stallman
2004-09-25 20:31       ` Paul Pogonyshev
2004-09-26  8:27         ` Richard Stallman

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