]> git.eshelyaron.com Git - emacs.git/commitdiff
Add WebP image format support (Bug#51296)
authorStefan Kangas <stefan@marxist.se>
Fri, 22 Oct 2021 08:59:01 +0000 (10:59 +0200)
committerStefan Kangas <stefan@marxist.se>
Fri, 22 Oct 2021 08:59:01 +0000 (10:59 +0200)
* configure.ac (--with-webp): New option.
(HAVE_WEBP): New variable.
(emacs_config_features): Add webp.
* src/image.c (enum webp_keyword_index) [HAVE_WEBP]: New enum.
(webp_format) [HAVE_WEBP]: New variable.
(webp_image_p, init_webp_functions, webp_load) [HAVE_WEBP]: New
functions for WebP support.
(image_types) [HAVE_WEBP]: Define WebP format.
(syms_of_image) <Qwebp> [HAVE_WEBP]: New DEFSYM.  Add image type Qwebp.
* src/Makefile.in (LIBIMAGE): Add WEBP_LIBS.

* lisp/files.el (auto-mode-alist):
* lisp/image-file.el (image-file-name-extensions):
* lisp/image.el (image-type-header-regexps)
(image-type-file-name-regexps, image-type-auto-detectable): Add WebP
support.
* lisp/term/w32-win.el (dynamic-library-alist): Add the libwebp DLL.

* INSTALL:
* admin/CPP-DEFINES:
* doc/lispref/display.texi (Image Formats, Other Image Types):
* nt/INSTALL: Document WebP support.

* test/lisp/image-tests.el (image-find-image)
(image-type-from-file-name): Expand tests.
* test/src/image-tests.el (image-tests--files): Add WebP.
(image-tests-image-size/webp, image-tests-image-mask-p/webp)
(image-tests-image-metadata/webp): New tests.
* test/data/image/black.webp: New file.

15 files changed:
INSTALL
admin/CPP-DEFINES
configure.ac
doc/lispref/display.texi
etc/NEWS
lisp/files.el
lisp/image-file.el
lisp/image.el
lisp/term/w32-win.el
nt/INSTALL
src/Makefile.in
src/image.c
test/data/image/black.webp [new file with mode: 0644]
test/lisp/image-tests.el
test/src/image-tests.el

diff --git a/INSTALL b/INSTALL
index 6207f43cecb14f26cce356d0d796dcbdefb98700..21298422af7de1be5c2eed4d594b72f915ec4da3 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -187,6 +187,7 @@ X11 is being used.
   X libtiff for TIFF: http://www.simplesystems.org/libtiff/
   X libgif for GIF:   http://giflib.sourceforge.net/
     librsvg2 for SVG: https://wiki.gnome.org/Projects/LibRsvg
+    libwebp for WebP: https://developers.google.com/speed/webp/
 
 If you supply the appropriate --without-LIB option, 'configure' will
 omit the corresponding library from Emacs, even if that makes for a
@@ -313,6 +314,7 @@ or more of these options:
   --without-gif          for GIF image support
   --without-png          for PNG image support
   --without-rsvg         for SVG image support
+  --without-webp         for WebP image support
 
 Although ImageMagick support is disabled by default due to security
 and stability concerns, you can enable it with --with-imagemagick.
index 68c12438f5ac2d00ec67642e19f31d19bdd0f157..634d6f3f3bb26712539e719410647264e6778520 100644 (file)
@@ -287,6 +287,7 @@ HAVE_UTIMENSAT
 HAVE_UTMP_H
 HAVE_VFORK
 HAVE_VFORK_H
+HAVE_WEBP
 HAVE_WCHAR_H
 HAVE_WCHAR_T
 HAVE_WINDOW_SYSTEM
index 9ab0314428c95b21f19cf6beee72ece4bb9705e4..d091866b8724853cb69a50aaef612e0a13292ced 100644 (file)
@@ -447,6 +447,7 @@ OPTION_DEFAULT_ON([tiff],[don't compile with TIFF image support])
 OPTION_DEFAULT_ON([gif],[don't compile with GIF image support])
 OPTION_DEFAULT_ON([png],[don't compile with PNG image support])
 OPTION_DEFAULT_ON([rsvg],[don't compile with SVG image support])
+OPTION_DEFAULT_ON([webp],[don't compile with WebP image support])
 OPTION_DEFAULT_ON([lcms2],[don't compile with Little CMS support])
 OPTION_DEFAULT_ON([libsystemd],[don't compile with libsystemd support])
 OPTION_DEFAULT_ON([cairo],[don't compile with Cairo drawing])
@@ -2588,6 +2589,28 @@ if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${opsys}" =
   fi
 fi
 
+### Use -lwebp if available, unless '--with-webp=no'
+### mingw32 doesn't use -lwebp, since it loads the library dynamically.
+HAVE_WEBP=no
+if test "${with_webp}" != "no"; then
+   if test "$opsys" = mingw32; then
+      AC_CHECK_HEADER([webp/decode.h], [HAVE_WEBP=yes])
+   elif test "${HAVE_X11}" = "yes" || test "${HAVE_W32}" = "yes" \
+         || test "${HAVE_NS}" = "yes"; then
+      WEBP_REQUIRED=0.6.0
+      WEBP_MODULE="libwebp >= $WEBP_REQUIRED"
+
+      EMACS_CHECK_MODULES([WEBP], [$WEBP_MODULE])
+      AC_SUBST(WEBP_CFLAGS)
+      AC_SUBST(WEBP_LIBS)
+
+      if test $HAVE_WEBP = yes; then
+        AC_DEFINE(HAVE_WEBP, 1, [Define to 1 if using libwebp.])
+        CFLAGS="$CFLAGS $WEBP_CFLAGS"
+      fi
+   fi
+fi
+
 HAVE_IMAGEMAGICK=no
 if test "${HAVE_X11}" = "yes" || test "${HAVE_NS}" = "yes" || test "${HAVE_W32}" = "yes"; then
   if test "${with_imagemagick}" != "no"; then
@@ -5882,8 +5905,8 @@ emacs_config_features=
 for opt in ACL CAIRO DBUS FREETYPE GCONF GIF GLIB GMP GNUTLS GPM GSETTINGS \
  HARFBUZZ IMAGEMAGICK JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBSYSTEMD LIBXML2 \
  M17N_FLT MODULES NATIVE_COMP NOTIFY NS OLDXMENU PDUMPER PNG RSVG SECCOMP \
- SOUND THREADS TIFF \
TOOLKIT_SCROLL_BARS UNEXEC X11 XAW3D XDBE XFT XIM XPM XWIDGETS X_TOOLKIT \
+ SOUND THREADS TIFF TOOLKIT_SCROLL_BARS \
UNEXEC WEBP X11 XAW3D XDBE XFT XIM XPM XWIDGETS X_TOOLKIT \
  ZLIB; do
 
     case $opt in
@@ -5928,6 +5951,7 @@ AS_ECHO(["  Does Emacs use -lXaw3d?                                 ${HAVE_XAW3D
   Does Emacs use a gif library?                           ${HAVE_GIF} $LIBGIF
   Does Emacs use a png library?                           ${HAVE_PNG} $LIBPNG
   Does Emacs use -lrsvg-2?                                ${HAVE_RSVG}
+  Does Emacs use -lwebp?                                  ${HAVE_WEBP}
   Does Emacs use cairo?                                   ${HAVE_CAIRO}
   Does Emacs use -llcms2?                                 ${HAVE_LCMS2}
   Does Emacs use imagemagick?                             ${HAVE_IMAGEMAGICK}
index 16577d13c19eee14820fecd569168d380ece59aa..9c378a30277ea83bbae18e67adf36254c98044b7 100644 (file)
@@ -5264,13 +5264,13 @@ to modify the set of known names for these dynamic libraries.
   Supported image formats (and the required support libraries) include
 PBM and XBM (which do not depend on support libraries and are always
 available), XPM (@code{libXpm}), GIF (@code{libgif} or
-@code{libungif}), JPEG (@code{libjpeg}), TIFF
-(@code{libtiff}), PNG (@code{libpng}), and SVG (@code{librsvg}).
+@code{libungif}), JPEG (@code{libjpeg}), TIFF (@code{libtiff}), PNG
+(@code{libpng}), SVG (@code{librsvg}), and WebP (@code{libwebp}).
 
   Each of these image formats is associated with an @dfn{image type
 symbol}.  The symbols for the above formats are, respectively,
-@code{pbm}, @code{xbm}, @code{xpm}, @code{gif},
-@code{jpeg}, @code{tiff}, @code{png}, and @code{svg}.
+@code{pbm}, @code{xbm}, @code{xpm}, @code{gif}, @code{jpeg},
+@code{tiff}, @code{png}, @code{svg}, and @code{webp}.
 
   Furthermore, if you build Emacs with ImageMagick
 (@code{libMagickWand}) support, Emacs can display any image format
@@ -6274,6 +6274,9 @@ Image type @code{png}.
 @item TIFF
 Image type @code{tiff}.
 Supports the @code{:index} property.  @xref{Multi-Frame Images}.
+
+@item WebP
+Image type @code{webp}.
 @end table
 
 @node Defining Images
index c1b8adc5118acff54c2f7ce73347e04e2686e628..36d04aa2d83ccf930d1c4f24af0be075049a613a 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -61,6 +61,12 @@ Emacs previously didn't distinguish between the "regular" weight and
 the "medium" weight, but it now also supports the (heavier) "medium"
 weight.
 
++++
+** Support for the WebP image format.
+This support is built by default when the libwebp library is
+available.  To disable it, use the '--without-webp' configure flag.
+Image specifiers can now use ':type webp'.
+
 \f
 * Editing Changes in Emacs 29.1
 
index 99bff296f16220e242388f18da476699e42cfd3c..f0cfa2e39b343bf194c9fa6f8988e4bf865094ca 100644 (file)
@@ -2758,6 +2758,7 @@ since only a single case-insensitive search through the alist is made."
      ("\\.gif\\'" . image-mode)
      ("\\.png\\'" . image-mode)
      ("\\.jpe?g\\'" . image-mode)
+     ("\\.webp\\'" . image-mode)
      ("\\.te?xt\\'" . text-mode)
      ("\\.[tT]e[xX]\\'" . tex-mode)
      ("\\.ins\\'" . tex-mode)          ;Installation files for TeX packages.
index fbc9eaaf94ec812309e2f5fcd8bd1479484c8751..6df43f737ddb5d94b3e0a87a7680e4341860b708 100644 (file)
@@ -37,7 +37,7 @@
 
 ;;;###autoload
 (defcustom image-file-name-extensions
-  (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg"))
+  (purecopy '("png" "jpeg" "jpg" "gif" "tiff" "tif" "xbm" "xpm" "pbm" "pgm" "ppm" "pnm" "svg" "webp"))
   "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 2022b41d1f00855d8e18378c8ea1a7f7ca80ddce..5343e26d0328f4ef2ea696d8c49a49c2cf7a13f7 100644 (file)
@@ -48,6 +48,7 @@ static \\(unsigned \\)?char \\1_bits" . xbm)
     ("\\`\\(?:MM\0\\*\\|II\\*\0\\)" . tiff)
     ("\\`[\t\n\r ]*%!PS" . postscript)
     ("\\`\xff\xd8" . jpeg)    ; used to be (image-jpeg-p . jpeg)
+    ("\\`RIFF....WEBPVP8" . webp)
     (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
             (comment-re (concat "\\(?:!--" incomment-re "*-->[ \t\r\n]*<\\)")))
        (concat "\\(?:<\\?xml[ \t\r\n]+[^>]*>\\)?[ \t\r\n]*<"
@@ -67,6 +68,7 @@ a non-nil value, TYPE is the image's type.")
   '(("\\.png\\'" . png)
     ("\\.gif\\'" . gif)
     ("\\.jpe?g\\'" . jpeg)
+    ("\\.webp\\'" . webp)
     ("\\.bmp\\'" . bmp)
     ("\\.xpm\\'" . xpm)
     ("\\.pbm\\'" . pbm)
@@ -92,6 +94,7 @@ be of image type IMAGE-TYPE.")
     (jpeg . maybe)
     (tiff . maybe)
     (svg . maybe)
+    (webp . maybe)
     (postscript . nil))
   "Alist of (IMAGE-TYPE . AUTODETECT) pairs used to auto-detect image files.
 \(See `image-type-auto-detected-p').
index 5d1dc6066764cc8d124183150e84c660440f4be9..366992cbbf018c41f2822aac1265b70469aa6275 100644 (file)
@@ -274,6 +274,7 @@ See the documentation of `create-fontset-from-fontset-spec' for the format.")
             '(gif "libgif-6.dll" "giflib5.dll" "gif.dll")
         '(gif "libgif-5.dll" "giflib4.dll" "libungif4.dll" "libungif.dll")))
        '(svg "librsvg-2-2.dll")
+       '(libwebp "libwebp-7.dll" "libwebp.dll")
        '(gdk-pixbuf "libgdk_pixbuf-2.0-0.dll")
        '(glib "libglib-2.0-0.dll")
        '(gio "libgio-2.0-0.dll")
index 9f543151a94baf76c0869988b0d4c440a2fb1609..a39057c66c6c20d449c279584fb36c9a5e415cda 100644 (file)
@@ -488,6 +488,7 @@ build will run on Windows 9X and newer systems).
        Does Emacs use a gif library?                           yes
        Does Emacs use a png library?                           yes
        Does Emacs use -lrsvg-2?                                yes
+       Does Emacs use -lwebp?                                  yes
        Does Emacs use cairo?                                   no
        Does Emacs use -llcms2?                                 yes
        Does Emacs use imagemagick?                             no
@@ -597,8 +598,8 @@ build will run on Windows 9X and newer systems).
 * Optional image library support
 
   In addition to its "native" image formats (pbm and xbm), Emacs can
-  handle other image types: xpm, tiff, gif, png, jpeg and experimental
-  support for svg.
+  handle other image types: xpm, tiff, gif, png, jpeg, webp and
+  experimental support for svg.
 
   To build Emacs with support for them, the corresponding headers must
   be in the include path and libraries should be where the linker
@@ -736,6 +737,10 @@ build will run on Windows 9X and newer systems).
   without it by specifying the --without-rsvg switch to the configure
   script.
 
+  For WebP images you will need libwebp:
+
+    https://developers.google.com/speed/webp/
+
   Binaries for the other image libraries can be found on the
   ezwinports site or at the GnuWin32 project (the latter are generally
   very old, so not recommended).  Note specifically that, due to some
index 6d75e3537a6116e64b0e8ad003c0c0ad8e19ae41..7c977e34ea89c666dc6a6c8f555f6fc106a104a1 100644 (file)
@@ -124,7 +124,7 @@ LIB_MATH=@LIB_MATH@
 ## -lpthread, or empty.
 LIB_PTHREAD=@LIB_PTHREAD@
 
-LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@
+LIBIMAGE=@LIBTIFF@ @LIBJPEG@ @LIBPNG@ @LIBGIF@ @LIBXPM@ @WEBP_LIBS@
 
 XCB_LIBS=@XCB_LIBS@
 XFT_LIBS=@XFT_LIBS@
index ff05741b2cd2c705b9994f312ec0d1989206419a..fe0bb509c58132f2627f1171f399600430cb5a24 100644 (file)
@@ -8739,8 +8739,280 @@ gif_load (struct frame *f, struct image *img)
 #endif /* HAVE_GIF */
 
 
+#ifdef HAVE_WEBP
+
+\f
+/***********************************************************************
+                                WebP
+ ***********************************************************************/
+
+#include "webp/decode.h"
+
+/* Indices of image specification fields in webp_format, below.  */
+
+enum webp_keyword_index
+{
+  WEBP_TYPE,
+  WEBP_DATA,
+  WEBP_FILE,
+  WEBP_ASCENT,
+  WEBP_MARGIN,
+  WEBP_RELIEF,
+  WEBP_ALGORITHM,
+  WEBP_HEURISTIC_MASK,
+  WEBP_MASK,
+  WEBP_BACKGROUND,
+  WEBP_LAST
+};
+
+/* Vector of image_keyword structures describing the format
+   of valid user-defined image specifications.  */
+
+static const struct image_keyword webp_format[WEBP_LAST] =
+{
+  {":type",            IMAGE_SYMBOL_VALUE,                     1},
+  {":data",            IMAGE_STRING_VALUE,                     0},
+  {":file",            IMAGE_STRING_VALUE,                     0},
+  {":ascent",          IMAGE_ASCENT_VALUE,                     0},
+  {":margin",          IMAGE_NON_NEGATIVE_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}
+};
+
+/* Return true if OBJECT is a valid WebP image specification.  */
+
+static bool
+webp_image_p (Lisp_Object object)
+{
+  struct image_keyword fmt[WEBP_LAST];
+  memcpy (fmt, webp_format, sizeof fmt);
+
+  if (!parse_image_spec (object, fmt, WEBP_LAST, Qwebp))
+    return false;
+
+  /* Must specify either the :data or :file keyword.  */
+  return fmt[WEBP_FILE].count + fmt[WEBP_DATA].count == 1;
+}
+
+#ifdef WINDOWSNT
+
+/* WebP library details.  */
+
+DEF_DLL_FN (int, WebPGetInfo, (const uint8_t *, size_t, int *, int *));
+DEF_DLL_FN (VP8StatusCode, WebPGetFeatures, (const uint8_t *, size_t, WebPBitstreamFeatures *));
+DEF_DLL_FN (uint8_t *, WebPDecodeRGB, (const uint8_t *, size_t, int *, int *));
+DEF_DLL_FN (uint8_t *, WebPDecodeBGR, (const uint8_t *, size_t, int *, int *));
+DEF_DLL_FN (void, WebPFreeDecBuffer (WebPDecBuffer *));
+
+static bool
+init_webp_functions (void)
+{
+  HMODULE library;
+
+  if (!(library = w32_delayed_load (Qwebp)))
+    return false;
+
+  LOAD_DLL_FN (library, WebPGetInfo);
+  LOAD_DLL_FN (library, WebPGetFeatures);
+  LOAD_DLL_FN (library, WebPDecodeRGBA);
+  LOAD_DLL_FN (library, WebPDecodeRGB);
+  LOAD_DLL_FN (library, WebPFree);
+  return true;
+}
+
+#undef WebPGetInfo
+#undef WebPGetFeatures
+#undef WebPDecodeRGBA
+#undef WebPDecodeRGB
+#undef WebPFree
+
+#define WebPGetInfo fn_WebPGetInfo
+#define WebPGetFeatures fn_WebPGetFeatures
+#define WebPDecodeRGBA fn_WebPDecodeRGBA
+#define WebPDecodeRGB fn_WebPDecodeRGB
+#define WebPFree fn_WebPFree
+
+#endif /* WINDOWSNT */
+
+/* Load WebP image IMG for use on frame F.  Value is true if
+   successful.  */
+
+static bool
+webp_load (struct frame *f, struct image *img)
+{
+  ptrdiff_t size = 0;
+  uint8_t *contents;
+  Lisp_Object file;
+
+  /* Open the WebP file.  */
+  Lisp_Object specified_file = image_spec_value (img->spec, QCfile, NULL);
+  Lisp_Object specified_data = image_spec_value (img->spec, QCdata, NULL);
+
+  if (NILP (specified_data))
+    {
+      int fd;
+      file = image_find_image_fd (specified_file, &fd);
+      if (!STRINGP (file))
+       {
+         image_error ("Cannot find image file `%s'", specified_file);
+         return false;
+       }
+
+      contents = (uint8_t *) slurp_file (fd, &size);
+      if (contents == NULL)
+       {
+         image_error ("Error loading WebP image `%s'", file);
+         return false;
+       }
+    }
+  else
+    {
+      if (!STRINGP (specified_data))
+       {
+         image_error ("Invalid image data `%s'", specified_data);
+         return false;
+       }
+      contents = SDATA (specified_data);
+      size = SBYTES (specified_data);
+    }
+
+  /* Validate the WebP image header.  */
+  if (!WebPGetInfo (contents, size, NULL, NULL))
+    {
+      if (!NILP (specified_data))
+       image_error ("Not a WebP file: `%s'", file);
+      else
+       image_error ("Invalid header in WebP image data");
+      goto webp_error1;
+    }
+
+  /* Get WebP features.  */
+  WebPBitstreamFeatures features;
+  VP8StatusCode result = WebPGetFeatures (contents, size, &features);
+  switch (result)
+    {
+    case VP8_STATUS_OK:
+      break;
+    case VP8_STATUS_NOT_ENOUGH_DATA:
+    case VP8_STATUS_OUT_OF_MEMORY:
+    case VP8_STATUS_INVALID_PARAM:
+    case VP8_STATUS_BITSTREAM_ERROR:
+    case VP8_STATUS_UNSUPPORTED_FEATURE:
+    case VP8_STATUS_SUSPENDED:
+    case VP8_STATUS_USER_ABORT:
+    default:
+      /* Error out in all other cases.  */
+      if (!NILP (specified_data))
+       image_error ("Error when interpreting WebP image data: `%s'", file);
+      else
+       image_error ("Error when interpreting WebP image data");
+      goto webp_error1;
+    }
+
+  /* Decode WebP data.  */
+  uint8_t *decoded;
+  int width, height;
+  if (features.has_alpha)
+    /* Linear [r0, g0, b0, a0, r1, g1, b1, a1, ...] order.  */
+    decoded = WebPDecodeRGBA (contents, size, &width, &height);
+  else
+    /* Linear [r0, g0, b0, r1, g1, b1, ...] order.  */
+    decoded = WebPDecodeRGB (contents, size, &width, &height);
+
+  if (!(width <= INT_MAX && height <= INT_MAX
+       && check_image_size (f, width, height)))
+    {
+      image_size_error ();
+      goto webp_error2;
+    }
+
+  /* Create the x image and pixmap.  */
+  Emacs_Pix_Container ximg, mask_img;
+  if (!image_create_x_image_and_pixmap (f, img, width, height, 0, &ximg, false))
+    goto webp_error2;
+
+  /* Create an image and pixmap serving as mask if the WebP image
+     contains an alpha channel.  */
+  if (features.has_alpha
+      && !image_create_x_image_and_pixmap (f, img, width, height, 1, &mask_img, true))
+    {
+      image_destroy_x_image (ximg);
+      image_clear_image_1 (f, img, CLEAR_IMAGE_PIXMAP);
+      goto webp_error2;
+    }
+
+  /* Fill the X image and mask from WebP data.  */
+  init_color_table ();
+
+  uint8_t *p = decoded;
+  for (int y = 0; y < height; ++y)
+    {
+      for (int x = 0; x < width; ++x)
+       {
+         int r = *p++ << 8;
+         int g = *p++ << 8;
+         int b = *p++ << 8;
+         PUT_PIXEL (ximg, x, y, lookup_rgb_color (f, r, g, b));
+
+         /* An alpha channel associates variable transparency with an
+            image.  WebP allows up to 256 levels of partial transparency.
+            We handle this like with PNG (which see), using the frame's
+            background color to combine the image with.  */
+         if (features.has_alpha)
+           {
+             if (mask_img)
+               PUT_PIXEL (mask_img, x, y, *p > 0 ? PIX_MASK_DRAW : PIX_MASK_RETAIN);
+             ++p;
+           }
+       }
+    }
+
+#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 */
+
+  /* Put ximg into the image.  */
+  image_put_x_image (f, img, ximg, 0);
+
+  /* Same for the mask.  */
+  if (mask_img)
+    {
+      /* Fill in the background_transparent field while we have the
+        mask handy.  Casting avoids a GCC warning.  */
+      image_background_transparent (img, f, (Emacs_Pix_Context)mask_img);
+
+      image_put_x_image (f, img, mask_img, 1);
+    }
+
+  img->width = width;
+  img->height = height;
+
+  /* Clean up.  */
+  WebPFree (decoded);
+  if (NILP (specified_data))
+    xfree (contents);
+  return true;
+
+ webp_error2:
+  WebPFree (decoded);
+
+ webp_error1:
+  if (NILP (specified_data))
+    xfree (contents);
+  return false;
+}
+
+#endif /* HAVE_WEBP */
+
+
 #ifdef HAVE_IMAGEMAGICK
 
+\f
 /***********************************************************************
                                 ImageMagick
 ***********************************************************************/
@@ -10725,6 +10997,10 @@ static struct image_type const image_types[] =
 #if defined HAVE_XPM || defined HAVE_NS
  { SYMBOL_INDEX (Qxpm), xpm_image_p, xpm_load, image_clear_image,
    IMAGE_TYPE_INIT (init_xpm_functions) },
+#endif
+#if defined HAVE_WEBP
+ { SYMBOL_INDEX (Qwebp), webp_image_p, webp_load, image_clear_image,
+   IMAGE_TYPE_INIT (init_webp_functions) },
 #endif
  { SYMBOL_INDEX (Qxbm), xbm_image_p, xbm_load, image_clear_image },
  { SYMBOL_INDEX (Qpbm), pbm_image_p, pbm_load, image_clear_image },
@@ -10891,6 +11167,11 @@ non-numeric, there is no explicit limit on the size of images.  */);
   add_image_type (Qpng);
 #endif
 
+#if defined (HAVE_WEBP)
+  DEFSYM (Qwebp, "webp");
+  add_image_type (Qwebp);
+#endif
+
 #if defined (HAVE_IMAGEMAGICK)
   DEFSYM (Qimagemagick, "imagemagick");
   add_image_type (Qimagemagick);
diff --git a/test/data/image/black.webp b/test/data/image/black.webp
new file mode 100644 (file)
index 0000000..5dbe716
Binary files /dev/null and b/test/data/image/black.webp differ
index aa8600609c4c6d054466a62dbde286e81ba0f091..c34c152cc99e7d235a2418c394691286745f4bc8 100644 (file)
     (should (equal image '(image)))))
 
 (ert-deftest image-find-image ()
-  (find-image '((:type xpm :file "undo.xpm")))
-  (find-image '((:type png :file "newsticker/rss-feed.png" :ascent center))))
+  (should (listp (find-image '((:type xpm :file "undo.xpm")))))
+  (should (listp (find-image '((:type png :file "newsticker/rss-feed.png" :ascent center)))))
+  (should-not (find-image '((:type png :file "does-not-exist-foo-bar.png")))))
 
 (ert-deftest image-type-from-file-name ()
   (should (eq (image-type-from-file-name "foo.jpg") 'jpeg))
-  (should (eq (image-type-from-file-name "foo.png") 'png)))
+  (should (eq (image-type-from-file-name "foo.png") 'png))
+  (should (eq (image-type-from-file-name "foo.webp") 'webp)))
 
 (ert-deftest image-type/from-filename ()
   ;; On emba, `image-types' and `image-load-path' do not exist.
index d5e3a7cc5cafd955741c593aae6f8a0bf6c6ab6f..b921739a05659608a67b9edd0eceb53da1ca56d4 100644 (file)
@@ -44,6 +44,8 @@
     (tiff . ,(expand-file-name
               "nextstep/GNUstep/Emacs.base/Resources/emacs.tiff"
               source-directory))
+    (webp . ,(expand-file-name "test/data/image/black.webp"
+                               source-directory))
     (xbm . ,(find-image '((:file "gnus/gnus.xbm" :type xbm))))
     (xpm . ,(find-image '((:file "splash.xpm" :type xpm))))
     ;; TODO: gif
      (should (floatp a))
      (should (floatp b)))))
 
+(ert-deftest image-tests-image-size/webp ()
+  (image-skip-unless 'webp)
+  (pcase (image-size (create-image (cdr (assq 'webp image-tests--files))))
+    (`(,a . ,b)
+     (should (floatp a))
+     (should (floatp b)))))
+
 (ert-deftest image-tests-image-size/xbm ()
   (image-skip-unless 'xbm)
   (pcase (image-size (cdr (assq 'xbm image-tests--files)))
 (ert-deftest image-tests-image-mask-p/tiff ()
   (image-skip-unless 'tiff)
   (should-not (image-mask-p (create-image
-                            (cdr (assq 'tiff image-tests--files))))))
+                             (cdr (assq 'tiff image-tests--files))))))
+
+(ert-deftest image-tests-image-mask-p/webp ()
+  (image-skip-unless 'webp)
+  (should-not (image-mask-p (create-image
+                             (cdr (assq 'webp image-tests--files))))))
 
 (ert-deftest image-tests-image-mask-p/xbm ()
   (image-skip-unless 'xbm)
 (ert-deftest image-tests-image-metadata/tiff ()
   (image-skip-unless 'tiff)
   (should-not (image-metadata
-              (create-image (cdr (assq 'tiff image-tests--files))))))
+               (create-image (cdr (assq 'tiff image-tests--files))))))
+
+(ert-deftest image-tests-image-metadata/webp ()
+  (image-skip-unless 'webp)
+  (should-not (image-metadata
+               (create-image (cdr (assq 'webp image-tests--files))))))
 
 (ert-deftest image-tests-image-metadata/xbm ()
   (image-skip-unless 'xbm)