diff --git a/configure.ac b/configure.ac index 91f368d9..a0aca45a 100644 --- a/configure.ac +++ b/configure.ac @@ -679,6 +679,17 @@ AC_ARG_ENABLE([tiff], WM_IMGFMT_CHECK_TIFF +dnl WEBP Support +dnl =========== +AC_ARG_ENABLE([webp], + [AS_HELP_STRING([--disable-webp], [disable WEBP support through libwebp])], + [AS_CASE(["$enableval"], + [yes|no], [], + [AC_MSG_ERROR([bad value $enableval for --enable-webp])] )], + [enable_webp=auto]) +WM_IMGFMT_CHECK_WEBP + + dnl PPM Support dnl =========== # The PPM format is always enabled because we have built-in support for the format diff --git a/m4/wm_imgfmt_check.m4 b/m4/wm_imgfmt_check.m4 index 02245d28..ad37993a 100644 --- a/m4/wm_imgfmt_check.m4 +++ b/m4/wm_imgfmt_check.m4 @@ -174,6 +174,29 @@ AC_DEFUN_ONCE([WM_IMGFMT_CHECK_TIFF], ]) dnl AC_DEFUN +# WM_IMGFMT_CHECK_WEBP +# ------------------- +# +# Check for WEBP file support through 'libwebp' +# The check depends on variable 'enable_webp' being either: +# yes - detect, fail if not found +# no - do not detect, disable support +# auto - detect, disable if not found +# +# When found, append appropriate stuff in GFXLIBS, and append info to +# the variable 'supported_gfx' +# When not found, append info to variable 'unsupported' +AC_DEFUN_ONCE([WM_IMGFMT_CHECK_WEBP], +[WM_LIB_CHECK([WEBP], ["-lwebp"], [VP8DecodeLayer], [$XLFLAGS $XLIBS], + [wm_save_CFLAGS="$CFLAGS" + AS_IF([wm_fn_lib_try_compile "webp/decode.h" "" "return 0" ""], + [], + [AC_MSG_ERROR([found $CACHEVAR but could not find appropriate header - are you missing libwebp-dev package?])]) + CFLAGS="$wm_save_CFLAGS"], + [supported_gfx], [GFXLIBS])dnl +]) dnl AC_DEFUN + + # WM_IMGFMT_CHECK_XPM # ------------------- # diff --git a/wrlib/Makefile.am b/wrlib/Makefile.am index db766ae2..48af352a 100644 --- a/wrlib/Makefile.am +++ b/wrlib/Makefile.am @@ -60,6 +60,10 @@ else libwraster_la_SOURCES += load_xpm_normalized.c endif +if USE_WEBP +libwraster_la_SOURCES += load_webp.c +endif + AM_CPPFLAGS = $(DFLAGS) @HEADER_SEARCH_PATH@ libwraster_la_LIBADD = @LIBRARY_SEARCH_PATH@ @GFXLIBS@ @XLIBS@ @LIBXMU@ -lm diff --git a/wrlib/imgformat.h b/wrlib/imgformat.h index 07b021a4..43df3ec9 100644 --- a/wrlib/imgformat.h +++ b/wrlib/imgformat.h @@ -38,12 +38,13 @@ typedef enum { IM_PNG = 3, IM_PPM = 4, IM_JPEG = 5, - IM_GIF = 6 + IM_GIF = 6, + IM_WEBP = 7 } WRImgFormat; /* How many image types we have. */ /* Increase this when adding new image types! */ -#define IM_TYPES 6 +#define IM_TYPES 7 /* * Function for Loading in a specific format @@ -68,6 +69,10 @@ RImage *RLoadJPEG(const char *file); RImage *RLoadGIF(const char *file, int index); #endif +#ifdef USE_WEBP +RImage *RLoadWEBP(const char *file); +#endif + /* * Function for Saving in a specific format */ diff --git a/wrlib/load.c b/wrlib/load.c index 73b2d95a..641cfae6 100644 --- a/wrlib/load.c +++ b/wrlib/load.c @@ -3,6 +3,7 @@ * Raster graphics library * * Copyright (c) 1997-2003 Alfredo K. Kojima + * Copyright (c) 2014 Window Maker Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -93,6 +94,9 @@ char **RSupportedFileFormats(void) #endif #ifdef USE_GIF tmp[i++] = "GIF"; +#endif +#ifdef USE_WEBP + tmp[i++] = "WEBP"; #endif tmp[i] = NULL; @@ -192,6 +196,12 @@ RImage *RLoadImage(RContext * context, const char *file, int index) break; #endif /* USE_GIF */ +#ifdef USE_WEBP + case IM_WEBP: + image = RLoadWEBP(file); + break; +#endif /* USE_WEBP */ + case IM_PPM: image = RLoadPPM(file); break; @@ -266,6 +276,11 @@ char *RGetImageFileFormat(const char *file) return "GIF"; #endif /* USE_GIF */ +#ifdef USE_WEBP + case IM_WEBP: + return "WEBP"; +#endif /* USE_WEBP */ + case IM_PPM: return "PPM"; @@ -329,5 +344,14 @@ static WRImgFormat identFile(const char *path) (buffer[4] == '7' || buffer[4] == '9') && buffer[5] == 'a') return IM_GIF; + /* check for WEBP */ + if (buffer[ 0] == 'R' && buffer[ 1] == 'I' && buffer[ 2] == 'F' && buffer[ 3] == 'F' && + buffer[ 8] == 'W' && buffer[ 9] == 'E' && buffer[10] == 'B' && buffer[11] == 'P' && + buffer[12] == 'V' && buffer[13] == 'P' && buffer[14] == '8' && + (buffer[15] == ' ' /* Simple File Format (Lossy) */ + || buffer[15] == 'L' /* Simple File Format (Lossless) */ + || buffer[15] == 'X')) /* Extended File Format */ + return IM_WEBP; + return IM_UNKNOWN; } diff --git a/wrlib/load_webp.c b/wrlib/load_webp.c new file mode 100644 index 00000000..f45ea8f8 --- /dev/null +++ b/wrlib/load_webp.c @@ -0,0 +1,138 @@ +/* load_webp.c - load WEBP image from file + * + * Raster graphics library + * + * Copyright (c) 2014 Window Maker Team + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include "wraster.h" +#include "imgformat.h" + + +RImage *RLoadWEBP(const char *file_name) +{ + FILE *file; + RImage *image = NULL; + char buffer[20]; + int raw_data_size; + int r; + uint8_t *raw_data; + WebPBitstreamFeatures features; + uint8_t *ret = NULL; + + file = fopen(file_name, "rb"); + if (!file) { + RErrorCode = RERR_OPEN; + return NULL; + } + + if (!fread(buffer, sizeof(buffer), 1, file)) { + RErrorCode = RERR_BADIMAGEFILE; + fclose(file); + return NULL; + } + + if (!(buffer[ 0] == 'R' && buffer[ 1] == 'I' && buffer[ 2] == 'F' && buffer[ 3] == 'F' && + buffer[ 8] == 'W' && buffer[ 9] == 'E' && buffer[10] == 'B' && buffer[11] == 'P' && + buffer[12] == 'V' && buffer[13] == 'P' && buffer[14] == '8' && +#if WEBP_DECODER_ABI_VERSION < 0x0003 /* old versions don't support WEBPVP8X and WEBPVP8L */ + buffer[15] == ' ')) { +#else + (buffer[15] == ' ' || buffer[15] == 'X' || buffer[15] == 'L'))) { +#endif + RErrorCode = RERR_BADFORMAT; + fclose(file); + return NULL; + } + + fseek(file, 0L, SEEK_END); + raw_data_size = ftell(file); + + if (raw_data_size <= 0) { + fprintf(stderr, "wrlib: Failed to find the WEBP file size for \"%s\"\n", file_name); + RErrorCode = RERR_BADIMAGEFILE; + fclose(file); + return NULL; + } + + raw_data = (uint8_t *) malloc(raw_data_size); + + if (!raw_data) { + RErrorCode = RERR_NOMEMORY; + fclose(file); + return NULL; + } + + fseek(file, 0L, SEEK_SET); + r = fread(raw_data, 1, raw_data_size, file); + fclose(file); + + if (r != raw_data_size) { + RErrorCode = RERR_READ; + free(raw_data); + return NULL; + } + + if (WebPGetFeatures(raw_data, raw_data_size, &features) != VP8_STATUS_OK) { + fprintf(stderr, "wrlib: WebPGetFeatures has failed on \"%s\"\n", file_name); + RErrorCode = RERR_BADIMAGEFILE; + free(raw_data); + return NULL; + } + + if (features.has_alpha) { + image = RCreateImage(features.width, features.height, True); + if (!image) { + RErrorCode = RERR_NOMEMORY; + free(raw_data); + return NULL; + } + ret = WebPDecodeRGBAInto(raw_data, raw_data_size, image->data, + features.width * features.height * 4, + features.width * 4); + } else { + image = RCreateImage(features.width, features.height, False); + if (!image) { + RErrorCode = RERR_NOMEMORY; + free(raw_data); + return NULL; + } + ret = WebPDecodeRGBInto(raw_data, raw_data_size, image->data, + features.width * features.height * 3, + features.width * 3); + } + + free(raw_data); + + if (!ret) { + fprintf(stderr, "wrlib: Failed to decode WEBP from file \"%s\"\n", file_name); + RErrorCode = RERR_BADIMAGEFILE; + RReleaseImage(image); + return NULL; + } + + return image; +}