* OF THIS SOFTWARE.
*/
+#include "../config.h"
+
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <jpeglib.h>
#include <png.h>
+#ifdef HAVE_WEBP
+#include <webp/decode.h>
+#endif
+
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
void
width, height, stride);
}
+#ifdef HAVE_WEBP
+
+static cairo_surface_t *
+load_webp(FILE *fp)
+{
+ WebPDecoderConfig config;
+ uint8_t buffer[16 * 1024];
+ int len;
+ VP8StatusCode status;
+ WebPIDecoder *idec;
+
+ if (!WebPInitDecoderConfig(&config)) {
+ fprintf(stderr, "Library version mismatch!\n");
+ return NULL;
+ }
+
+ /* webp decoding api doesn't seem to specify a min size that's
+ usable for GetFeatures, but 256 works... */
+ len = fread(buffer, 1, 256, fp);
+ status = WebPGetFeatures(buffer, len, &config.input);
+ if (status != VP8_STATUS_OK) {
+ fprintf(stderr, "failed to parse webp header\n");
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ config.output.colorspace = MODE_BGRA;
+ config.output.u.RGBA.stride =
+ cairo_format_stride_for_width(CAIRO_FORMAT_RGB24,
+ config.input.width);
+ config.output.u.RGBA.size =
+ config.output.u.RGBA.stride * config.input.height;
+ config.output.u.RGBA.rgba =
+ malloc(config.output.u.RGBA.stride * config.input.height);
+ config.output.is_external_memory = 1;
+ if (!config.output.u.RGBA.rgba) {
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ rewind(fp);
+ idec = WebPINewDecoder(&config.output);
+ if (!idec) {
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+
+ while (!feof(fp)) {
+ len = fread(buffer, 1, sizeof buffer, fp);
+ status = WebPIAppend(idec, buffer, len);
+ if (status != VP8_STATUS_OK) {
+ fprintf(stderr, "webp decode status %d\n", status);
+ WebPIDelete(idec);
+ WebPFreeDecBuffer(&config.output);
+ return NULL;
+ }
+ }
+
+ WebPIDelete(idec);
+ WebPFreeDecBuffer(&config.output);
+
+ return cairo_image_surface_create_for_data (config.output.u.RGBA.rgba,
+ CAIRO_FORMAT_RGB24,
+ config.input.width,
+ config.input.height,
+ config.output.u.RGBA.stride);
+}
+
+#endif
+
+
+struct image_loader {
+ char header[4];
+ int header_size;
+ cairo_surface_t *(*load)(FILE *fp);
+};
+
+static const struct image_loader loaders[] = {
+ { { 0x89, 'P', 'N', 'G' }, 4, load_png },
+ { { 0xff, 0xd8 }, 2, load_jpeg },
+#ifdef HAVE_WEBP
+ { { 'R', 'I', 'F', 'F' }, 4, load_webp }
+#endif
+};
+
cairo_surface_t *
load_image(const char *filename)
{
cairo_surface_t *surface;
- static const unsigned char png_header[] = { 0x89, 'P', 'N', 'G' };
- static const unsigned char jpeg_header[] = { 0xff, 0xd8 };
unsigned char header[4];
FILE *fp;
+ int i;
fp = fopen(filename, "rb");
if (fp == NULL)
fread(header, sizeof header, 1, fp);
rewind(fp);
- if (memcmp(header, png_header, sizeof png_header) == 0)
- surface = load_png(fp);
- else if (memcmp(header, jpeg_header, sizeof jpeg_header) == 0)
- surface = load_jpeg(fp);
- else {
+ for (i = 0; i < ARRAY_LENGTH(loaders); i++) {
+ if (memcmp(header, loaders[i].header,
+ loaders[i].header_size) == 0) {
+ surface = loaders[i].load(fp);
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ if (i == ARRAY_LENGTH(loaders)) {
fprintf(stderr, "unrecognized file header for %s: "
"0x%02x 0x%02x 0x%02x 0x%02x\n",
filename, header[0], header[1], header[2], header[3]);
surface = NULL;
}
- fclose(fp);
-
return surface;
}
[have_poppler=yes], [have_poppler=no])
PKG_CHECK_MODULES(CAIRO_EGL, [cairo-egl >= 1.11.3 $cairo_modules],
[have_cairo_egl=yes], [have_cairo_egl=no])
-
AS_IF([test "x$have_cairo_egl" = "xyes"],
[AC_DEFINE([HAVE_CAIRO_EGL], [1], [Have cairo-egl])],
[AC_MSG_WARN([Cairo-EGL not found - clients will use cairo image])])
+ PKG_CHECK_MODULES(WEBP, [libwebp], [have_webp=yes], [have_webp=no])
+ AS_IF([test "x$have_webp" = "xyes"],
+ [AC_DEFINE([HAVE_WEBP], [1], [Have webp])])
+ CLIENT_LIBS="$CLIENT_LIBS $WEBP_LIBS"
+ CLIENT_CFLAGS="$CLIENT_CFLAGS $WEBP_CFLAGS"
+
AC_CHECK_LIB([jpeg], [jpeg_CreateDecompress], have_jpeglib=yes)
if test x$have_jpeglib == xyes; then
CLIENT_LIBS="$CLIENT_LIBS -ljpeg"