|
View:
New views
20 Messages
—
Rating Filter:
Alert me
|
| < Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next > |
|
|
SVG support(again) ?There was a patch for SVG support in Emacs in 2004.
This patch seems to no longer apply. Has anyone adopted it for the current tree? If so, coculd it be applied? -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?joakim@... writes:
> There was a patch for SVG support in Emacs in 2004. > This patch seems to no longer apply. I've adapted the SVG patch by Paul Pogonyshev for current emacs CVS. All I did was find the right place to insert the hunks, since the emacs source has changed a lot since the original patch. I tried it briefly on a Fedora 7 box. It seems to work nicely. What must be done in order for this patch to be applied? The only odd thing I can see is three lines like: #if 1 || defined (HAVE_RSVG) that ought to be the same as: #if defined (HAVE_RSVG) which should be ok on any plattform, since HAVE_RSVG will be defined only if you have librsvg2. I did try the configure script generated by autoconf once withouth the lib and once with. I tried making a SVG picture with Inkscape, viewing it in emacs using image-dired, and then editing it a bit with nxml mode, and it seemed to work nicely. ? emacs_svg.patch Index: configure.in =================================================================== RCS file: /sources/emacs/emacs/configure.in,v retrieving revision 1.459 diff -r1.459 configure.in 112a113,114 > AC_ARG_WITH(rsvg, > [ --with-rsvg use -lrsvg-2 for displaying SVG images]) 116c118 < [ --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]) 2124a2127,2152 > ### 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 > > > echo " Does Emacs use -lrsvg-2? ${HAVE_RSVG}" =================================================================== RCS file: /sources/emacs/emacs/lisp/image-file.el,v retrieving revision 1.29 diff -r1.29 image-file.el 42c42 < '("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") Index: lisp/image.el =================================================================== RCS file: /sources/emacs/emacs/lisp/image.el,v retrieving revision 1.72 diff -r1.72 image.el 46c46,47 < ("\\`\xff\xd8" . (image-jpeg-p . jpeg))) --- > ("\\`\xff\xd8" . (image-jpeg-p . jpeg)) > ("\\`<\\?xml " . svg)) Index: src/Makefile.in =================================================================== RCS file: /sources/emacs/emacs/src/Makefile.in,v retrieving revision 1.346 diff -r1.346 Makefile.in 284c284 < 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_SOUND} ${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_SOUND} ${CFLAGS} 453c453 < LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM $(XFT_LIBS) --- > LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM @RSVG_LIBS@ LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM $(XFT_LIBS) Index: src/image.c =================================================================== RCS file: /sources/emacs/emacs/src/image.c,v retrieving revision 1.77 diff -r1.77 image.c 8201a8202,8474 > > /*********************************************************************** > 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) */ > > > > #if 1 || defined (HAVE_RSVG) > if (EQ (type, Qsvg)) > return CHECK_LIB_AVAILABLE (&svg_type, init_svg_functions, libraries); > #endif > > #if 1 || defined (HAVE_RSVG) > Qsvg = intern ("svg"); > staticpro (&Qsvg); > ADD_IMAGE_TYPE(Qsvg); > #endif > > > > Has anyone adopted it for the current tree? If so, coculd it be > applied? > > -- > Joakim Verona -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?joakim@... writes:
> joakim@... writes: > >> There was a patch for SVG support in Emacs in 2004. >> This patch seems to no longer apply. > > I've adapted the SVG patch by Paul Pogonyshev for current emacs CVS. > All I did was find the right place to insert the hunks, since the > emacs source has changed a lot since the original patch. > > I tried it briefly on a Fedora 7 box. It seems to work nicely. > > What must be done in order for this patch to be applied? > > The only odd thing I can see is three lines like: > > #if 1 || defined (HAVE_RSVG) > > that ought to be the same as: > > #if defined (HAVE_RSVG) No, it is the same as #if 1 period. -- David Kastrup, Kriemhildstr. 15, 44793 Bochum _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?David Kastrup wrote:
>> The only odd thing I can see is three lines like: >> >> #if 1 || defined (HAVE_RSVG) >> >> that ought to be the same as: >> >> #if defined (HAVE_RSVG) >> > > No, it is the same as > #if 1 > period. > Going back and looking at the original discussion from Sept 2004, the 1 || is there because he hadn't bothered with the configury stuff that would have made the HAVE_RSVG work. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?David Kastrup <dak@...> writes:
> joakim@... writes: > >> joakim@... writes: >> >>> There was a patch for SVG support in Emacs in 2004. >>> This patch seems to no longer apply. >> >> I've adapted the SVG patch by Paul Pogonyshev for current emacs CVS. >> All I did was find the right place to insert the hunks, since the >> emacs source has changed a lot since the original patch. >> >> I tried it briefly on a Fedora 7 box. It seems to work nicely. >> >> What must be done in order for this patch to be applied? >> >> The only odd thing I can see is three lines like: >> >> #if 1 || defined (HAVE_RSVG) >> >> that ought to be the same as: >> >> #if defined (HAVE_RSVG) > > No, it is the same as > #if 1 > period. Thanks! I suppose I should get more sleep. #if defined (HAVE_RSVG) seems to work though. Am I missing something else? > > -- > David Kastrup, Kriemhildstr. 15, 44793 Bochum -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Jason Rumney <jasonr@...> writes:
> Going back and looking at the original discussion from Sept 2004, the 1 > || is there because he hadn't bothered with the configury stuff that > would have made the HAVE_RSVG work. I think the configury stuff does work, but maybe it didnt originaly. This line in configure.in: echo " Does Emacs use -lrsvg-2? ${HAVE_RSVG}" corectly prints "yes" if librsvg2-devel is installed, but "no" if it isnt. The rest of the code gets to be correct if "#if 1 ..." is changed to "if defined(HAVE_RSVG)" in the patch. -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ? I've adapted the SVG patch by Paul Pogonyshev for current emacs CVS.
All I did was find the right place to insert the hunks, since the emacs source has changed a lot since the original patch. I tried it briefly on a Fedora 7 box. It seems to work nicely. What must be done in order for this patch to be applied? We have the legal papers. The code needs more comments. We also need the entry for etc/NEWS, and it would be nice to write text for the manual now. (I will polish it up once it is installed.) _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> writes:
> I've adapted the SVG patch by Paul Pogonyshev for current emacs CVS. > All I did was find the right place to insert the hunks, since the > emacs source has changed a lot since the original patch. > > I tried it briefly on a Fedora 7 box. It seems to work nicely. > > What must be done in order for this patch to be applied? > > We have the legal papers. The code needs more comments. We also need > the entry for etc/NEWS, and it would be nice to write text for the > manual now. (I will polish it up once it is installed.) - Is this text for NEWS ok? ** Support for SVG images Emacs now supports the SVG image format through librsvg2. - There appears to be only generic text in the emacs manual for image viewing, valid for all image types. Viewing SVG images is no different from viewing JPG images, so I think the manual doesnt need any particular updates for this patch. - I looked through the code briefly, and it didnt seem too bad on the commenting. Was it anything in particular you thought needed clarification? -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ? - Is this text for NEWS ok?
** Support for SVG images Emacs now supports the SVG image format through librsvg2. Yes, it is good enough. - I looked through the code briefly, and it didnt seem too bad on the commenting. Was it anything in particular you thought needed clarification? There are functions that don't even have a comment at the beginning to say what they do and how to call them. It needs a lot of improvement in comments. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?> - I looked through the code briefly, and it didnt seem too bad on the
> commenting. Was it anything in particular you thought needed clarification? > > There are functions that don't even have a comment at the beginning to > say what they do and how to call them. It needs a lot of improvement > in comments. This is why I like M-x checkdoc RET so much :) _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> writes:
> - Is this text for NEWS ok? > > ** Support for SVG images > > Emacs now supports the SVG image format through librsvg2. > > Yes, it is good enough. > > - I looked through the code briefly, and it didnt seem too bad on the > commenting. Was it anything in particular you thought needed clarification? > > There are functions that don't even have a comment at the beginning to > say what they do and how to call them. It needs a lot of improvement > in comments. I did some commenting in the SVG handler part of image.c below. The code seems to be mostly the same as for other image formats in image.c. Is it ok to discuss this part of the patch like this, and then I can supply a new combined patch for consideration? (again, I'm not the patchs original author, I'm just trying to help out to get it clean enough for inclusion.) /*********************************************************************** 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'. */ 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; } /* 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 (); 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 /* this loop handles opacity values, since emacs assumes non-transparent images. */ 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 _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ? /* 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. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> 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 _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?You're getting closer. There are enough comments now,
but they need to be formatted cleanly and consistently with the rest of Emacs. /* DEF_IMGLIB_FN() here in the future. Do you mean /* TO DO: use DEF_IMGLIB_FN here. It is vital to use words like "TO DO:" and "use", because following such patterns makes the meaning clear. (In GNU we don't write `()' after a function name.) Aside from that, it will be clean if you fill the comment lines to 70 character width. Also, please use two spaces at the end of a sentence, and please put a period and two spaces at the end of every comment that contents sentences. /* 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 */ should be /* Load SVG image IMG for use on frame F. Value is non-zero if successful. This function will go into the svg_type structure, and the prototype, so it needs to be compatible with that structure. */ contents = slurp_file (SDATA (file), &size); /* read the entire file into memory*/ That style makes lines wide and hard to read, so please put the comment on a separate line. It should start with a capital letter, and end with a period and two spaces. /* Read the entire file into memory. */ contents = slurp_file (SDATA (file), &size); /* 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 */ This should explain each of the arguments by name. Please also start it with a capital letter, and end it with a period, and avoid lines that are too long. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> writes:
> You're getting closer. There are enough comments now, > but they need to be formatted cleanly and consistently with the > rest of Emacs. > > /* DEF_IMGLIB_FN() here in the future. > > Do you mean > > /* TO DO: use DEF_IMGLIB_FN here. > > It is vital to use words like "TO DO:" and "use", > because following such patterns makes the meaning clear. > > (In GNU we don't write `()' after a function name.) > > Aside from that, it will be clean if you fill the comment lines > to 70 character width. > > Also, please use two spaces at the end of a sentence, > and please put a period and two spaces at the end of every comment > that contents sentences. > > /* 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 */ > > should be > > /* Load SVG image IMG for use on frame F. Value is non-zero if > successful. This function will go into the svg_type structure, and > the prototype, so it needs to be compatible with that structure. */ > > > contents = slurp_file (SDATA (file), &size); /* read the entire file into memory*/ > > That style makes lines wide and hard to read, so please put the comment > on a separate line. It should start with a capital letter, and end > with a period and two spaces. > > /* Read the entire file into memory. */ > contents = slurp_file (SDATA (file), &size); > > > /* 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 > */ > > This should explain each of the arguments by name. > Please also start it with a capital letter, and end it with a period, > and avoid lines that are too long. Ok, this is the next iteration. Thanks for your patience! /*********************************************************************** 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 = { /* An identifier showing that this is an image structure for the SVG format. */ &Qsvg, /* Handle to a function that can be used to identify a SVG file. */ svg_image_p, /* Handle to function used to load a SVG file. */ svg_load, /* Handle to function to free sresources for SVG. */ x_clear_image, /* An internal field to link to the next image type in a list of image types, will be filled in when registering the format. */ NULL }; /* 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> /* TO DO: define DEF_IMGLIB_FN here. This macro is used to handle loading of dynamic link library functions for various OS:es. Currently only librsvg2 is supported, 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 will 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; } /* Read the entire file into memory. */ contents = slurp_file (SDATA (file), &size); if (contents == NULL) { image_error ("Error loading SVG image `%s'", img->spec, Qnil); UNGCPRO; return 0; } /* If the file was slurped into memory properly, parse it. */ success_p = svg_load_image (f, img, contents, size); xfree (contents); UNGCPRO; } /* Else its not a file, its a lisp object. Load the image from a lisp object rather than a file. */ 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; } /* svg_load_image is a helper function for svg_load, which 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) /* Pointer to emacs frame sturcture. */ struct frame *f; /* Pointer to emacs image structure. */ struct image *img; /* String containing the SVG XML data to be parsed. */ unsigned char *contents; /* Size of data in bytes. */ 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 is a glib function that must be called prior to using gnome type library functions. */ g_type_init (); /* Make a handle to a new rsvg object. */ rsvg_handle = fn_rsvg_handle_new (); /* Parse the contents argument and fill in the rsvg_handle. */ fn_rsvg_handle_write (rsvg_handle, contents, size, &error); if (error) goto rsvg_error; /* The parsing is complete, rsvg_handle is ready to used, close it for further writes. */ fn_rsvg_handle_close (rsvg_handle, &error); if (error) goto rsvg_error; /* We can now get a valid pixel buffer from the svg file, if all went ok. */ pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle); eassert (pixbuf); /* Extract some meta data from the 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 (); /* TODO: The code is somewhat prepared for other environments than X, but is far from done. */ #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 so the user knows what is the actual problem with the image. */ image_error ("Error parsing SVG image `%s'", img->spec, Qnil); g_error_free (error); return 0; } #endif /* defined (HAVE_RSVG) */ -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?The code is now ready for installation. Thank you.
To install it requires a change log entry, and a NEWS entry. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> writes:
> The code is now ready for installation. Thank you. > To install it requires a change log entry, and a NEWS entry. Ok, heres a new version of the patch, and a NEWS entry that was agreed upon earlier. I suppose the committer provides a changelog entry? Please remember that Paul Pogonyshev is the author of the patch, I've just cleaned it up a bit. NEWS entry: ** Support for SVG images Emacs now supports the SVG image format through librsvg2. Patch: ? emacs_svg.patch Index: configure.in =================================================================== RCS file: /sources/emacs/emacs/configure.in,v retrieving revision 1.459 diff -u -p -r1.459 configure.in --- configure.in 26 Jul 2007 05:26:01 -0000 1.459 +++ configure.in 20 Aug 2007 08:47:43 -0000 @@ -110,10 +110,12 @@ AC_ARG_WITH(png, [ --with-png use -lpng for displaying PNG images]) AC_ARG_WITH(gpm, [ --with-gpm use -lgpm for mouse support on a GNU/Linux console]) +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]) @@ -2122,6 +2124,32 @@ fail; fi 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 USE_X_TOOLKIT=none @@ -3362,6 +3390,7 @@ echo " Does Emacs use -ljpeg? echo " Does Emacs use -ltiff? ${HAVE_TIFF}" echo " Does Emacs use a gif library? ${HAVE_GIF} $ac_gif_lib_name" echo " Does Emacs use -lpng? ${HAVE_PNG}" +echo " Does Emacs use -lrsvg-2? ${HAVE_RSVG}" echo " Does Emacs use -lgpm? ${HAVE_GPM}" echo " Does Emacs use X toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}" echo Index: lisp/image-file.el =================================================================== RCS file: /sources/emacs/emacs/lisp/image-file.el,v retrieving revision 1.29 diff -u -p -r1.29 image-file.el --- lisp/image-file.el 26 Jul 2007 05:26:26 -0000 1.29 +++ lisp/image-file.el 20 Aug 2007 08:48:30 -0000 @@ -39,7 +39,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'. Index: lisp/image.el =================================================================== RCS file: /sources/emacs/emacs/lisp/image.el,v retrieving revision 1.72 diff -u -p -r1.72 image.el --- lisp/image.el 26 Jul 2007 05:26:26 -0000 1.72 +++ lisp/image.el 20 Aug 2007 08:48:30 -0000 @@ -43,7 +43,8 @@ static char \\1_bits" . 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, Index: src/Makefile.in =================================================================== RCS file: /sources/emacs/emacs/src/Makefile.in,v retrieving revision 1.346 diff -u -p -r1.346 Makefile.in --- src/Makefile.in 26 Jul 2007 05:27:47 -0000 1.346 +++ src/Makefile.in 20 Aug 2007 08:49:46 -0000 @@ -281,7 +281,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_SOUND} ${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_SOUND} ${CFLAGS} .c.o: $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $< @@ -450,7 +450,7 @@ XFT_LIBS=@XFT_LIBS@ /* 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 $(XFT_LIBS) +LIBX= $(LIBXMENU) $(X11_LDFLAGS) $(LIBXT) LIBTIFF LIBJPEG LIBPNG LIBGIF LIBXPM @RSVG_LIBS@ LIB_X11_LIB LIBX11_MACHINE LIBX11_SYSTEM $(XFT_LIBS) #else /* not HAVE_X11 */ LIBX= $(LIBXMENU) LD_SWITCH_X_SITE -lX10 LIBX10_MACHINE LIBX10_SYSTEM #endif /* not HAVE_X11 */ Index: src/image.c =================================================================== RCS file: /sources/emacs/emacs/src/image.c,v retrieving revision 1.77 diff -u -p -r1.77 image.c --- src/image.c 7 Aug 2007 16:25:26 -0000 1.77 +++ src/image.c 20 Aug 2007 08:49:50 -0000 @@ -8199,6 +8199,329 @@ gif_load (f, img) #endif /* HAVE_GIF */ + +/*********************************************************************** + 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 = +{ + /* An identifier showing that this is an image structure for the SVG format. */ + &Qsvg, + /* Handle to a function that can be used to identify a SVG file. */ + svg_image_p, + /* Handle to function used to load a SVG file. */ + svg_load, + /* Handle to function to free sresources for SVG. */ + x_clear_image, + /* An internal field to link to the next image type in a list of + image types, will be filled in when registering the format. */ + NULL +}; + + +/* 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> + +/* TO DO: define DEF_IMGLIB_FN here. This macro is used to handle +loading of dynamic link library functions for various OS:es. +Currently only librsvg2 is supported, 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 will 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; + } + + /* Read the entire file into memory. */ + contents = slurp_file (SDATA (file), &size); + if (contents == NULL) + { + image_error ("Error loading SVG image `%s'", img->spec, Qnil); + UNGCPRO; + return 0; + } + /* If the file was slurped into memory properly, parse it. */ + success_p = svg_load_image (f, img, contents, size); + xfree (contents); + UNGCPRO; + } + /* Else its not a file, its a lisp object. Load the image from a + lisp object rather than a file. */ + 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; +} + +/* svg_load_image is a helper function for svg_load, which 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) + /* Pointer to emacs frame sturcture. */ + struct frame *f; + /* Pointer to emacs image structure. */ + struct image *img; + /* String containing the SVG XML data to be parsed. */ + unsigned char *contents; + /* Size of data in bytes. */ + 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 is a glib function that must be called prior to using + gnome type library functions. */ + g_type_init (); + /* Make a handle to a new rsvg object. */ + rsvg_handle = fn_rsvg_handle_new (); + + /* Parse the contents argument and fill in the rsvg_handle. */ + fn_rsvg_handle_write (rsvg_handle, contents, size, &error); + if (error) + goto rsvg_error; + + /* The parsing is complete, rsvg_handle is ready to used, close it + for further writes. */ + fn_rsvg_handle_close (rsvg_handle, &error); + if (error) + goto rsvg_error; + /* We can now get a valid pixel buffer from the svg file, if all + went ok. */ + pixbuf = fn_rsvg_handle_get_pixbuf (rsvg_handle); + eassert (pixbuf); + + /* Extract some meta data from the 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 (); + + /* TODO: The code is somewhat prepared for other environments than + X, but is far from done. */ +#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 so the user knows what is the actual + problem with the image. */ + image_error ("Error parsing SVG image `%s'", img->spec, Qnil); + g_error_free (error); + return 0; +} + +#endif /* defined (HAVE_RSVG) */ + + + /*********************************************************************** Ghostscript @@ -8591,6 +8914,11 @@ of `image-library-alist', which see). * return CHECK_LIB_AVAILABLE (&png_type, init_png_functions, libraries); #endif +#if 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); @@ -8733,6 +9061,13 @@ non-numeric, there is no explicit limit ADD_IMAGE_TYPE(Qpng); #endif +#if defined (HAVE_RSVG) + Qsvg = intern ("svg"); + staticpro (&Qsvg); + ADD_IMAGE_TYPE(Qsvg); +#endif + + defsubr (&Sinit_image_library); defsubr (&Sclear_image_cache); defsubr (&Simage_refresh); -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ? Ok, heres a new version of the patch, and a NEWS entry that was agreed
upon earlier. I suppose the committer provides a changelog entry? Please remember that Paul Pogonyshev is the author of the patch, I've just cleaned it up a bit. Can you please write the change log entry for it? It should reflect the authorship, both yours and his. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Richard Stallman <rms@...> writes:
> Ok, heres a new version of the patch, and a NEWS entry that was agreed > upon earlier. I suppose the committer provides a changelog entry? > Please remember that Paul Pogonyshev is the author of the patch, I've > just cleaned it up a bit. > > Can you please write the change log entry for it? > It should reflect the authorship, both yours and his. Ok, heres my attempt: 2007-08-21 Paul Pogonyshev <pogonyshev@...> * configure.in, image-file.el, image.el, * Makefile.in, image.c: Support the SVG image file format through librsvg2. Some additional code somments where written by Joakim Verona <joakim@...>. -- Joakim Verona _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
|
|
Re: SVG support(again) ?Thanks for this, I installed it. Let me know if I missed anything. _______________________________________________ Emacs-devel mailing list Emacs-devel@... http://lists.gnu.org/mailman/listinfo/emacs-devel |
| < Prev | 1 - 2 - 3 - 4 - 5 - 6 | Next > |
| Free embeddable forum powered by Nabble | Forum Help |