From 7937b409e7a6dea2c30e7cc045eb58a3146c7399 Mon Sep 17 00:00:00 2001 From: Pascal Massimino Date: Tue, 13 Dec 2011 14:02:04 -0800 Subject: [PATCH] simple WebP viewer, based on OpenGL Quite handy and simple (for now). It's not yet incorporated within the build system (autotools or makefile.unix), because it gets complicated with OpenGL. TODO(later). For now, there's some ready-to-use command line for compiling on Linux or Mac in the header of vwebp.c Later, this tool will be supplemented with support for animation, tiling, zooming, etc. Change-Id: I292972cea4862536afbe8c9ec444c590d152f086 --- README | 12 +++ examples/vwebp.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+) create mode 100644 examples/vwebp.c diff --git a/README b/README index c41d3961..1ea4d249 100644 --- a/README +++ b/README @@ -228,6 +228,18 @@ Use following options to convert into alternate image formats: -v ....... verbose (e.g. print encoding/decoding times) -noasm ....... disable all assembly optimizations. +Visualization tool: +=================== + +There's a little self-serve visualization tool called 'vwebp' under the +examples/ directory. It uses OpenGL to open a simple drawing window and show +a decoded WebP file. It's not yet integrated in the automake or makefile.unix +build system, but you can try to manually compile it using the recommendations +at the top of the source file. + +Usage: 'vwebp my_picture.webp' + + Encoding API: ============= diff --git a/examples/vwebp.c b/examples/vwebp.c new file mode 100644 index 00000000..4e98220f --- /dev/null +++ b/examples/vwebp.c @@ -0,0 +1,248 @@ +// Copyright 2011 Google Inc. +// +// This code is licensed under the same terms as WebM: +// Software License Agreement: http://www.webmproject.org/license/software/ +// Additional IP Rights Grant: http://www.webmproject.org/license/additional/ +// ----------------------------------------------------------------------------- +// +// Simple WebP file viewer. +// +// Compiling on linux: +// sudo apt-get install libglut3-dev mesa-common-dev +// gcc -o vwebp vwebp.c -O3 -lwebp -lglut -lGL +// Compiling on Mac + XCode: +// gcc -o vwebp vwebp.c -lwebp -framework GLUT -framework OpenGL +// +// Author: Skal (pascal.massimino@gmail.com) + +#include +#include +#include + +#include "webp/decode.h" + +#ifdef __APPLE__ +#include +#else +#include +#ifdef FREEGLUT +#include +#endif +#endif + +// Unfortunate global variables +static const WebPDecBuffer* kPic = NULL; +static const char* file_name = NULL; +static int print_info = 0; + +//------------------------------------------------------------------------------ +// Callbacks + +static void HandleKey(unsigned char key, int pos_x, int pos_y) { + (void)pos_x; + (void)pos_y; + if (key == 'q' || key == 'Q' || key == 27 /* Esc */) { +#ifdef FREEGLUT + glutLeaveMainLoop(); +#else + WebPFreeDecBuffer((WebPDecBuffer*)kPic); + kPic = NULL; + exit(0); +#endif + } else if (key == 'i') { + print_info = 1 - print_info; + glutPostRedisplay(); + } +} + +static void HandleReshape(int width, int height) { + // TODO(skal): proper handling of resize, esp. for large pictures. + // + key control of the zoom. + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +static void PrintString(const char* const text) { + void* const font = GLUT_BITMAP_9_BY_15; + int i; + for (i = 0; text[i]; ++i) { + glutBitmapCharacter(font, text[i]); + } +} + +static void HandleDisplay(void) { + if (kPic == NULL) return; + glClear(GL_COLOR_BUFFER_BIT); + glPushMatrix(); + glPixelZoom(1, -1); + glRasterPos2f(-1, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ROW_LENGTH, kPic->u.RGBA.stride / 4); + glDrawPixels(kPic->width, kPic->height, GL_RGBA, GL_UNSIGNED_BYTE, + (GLvoid*)kPic->u.RGBA.rgba); + if (print_info) { + char tmp[32]; + + glColor4f(0.0, 0.0, 0.0, 0.0); + glRasterPos2f(-0.95, 0.90); + PrintString(file_name); + + snprintf(tmp, sizeof(tmp), "Dimension:%d x %d", kPic->width, kPic->height); + glColor4f(0.0, 0.0, 0.0, 0.0); + glRasterPos2f(-0.95, 0.80); + PrintString(tmp); + } + glFlush(); +} + +static void Show(const WebPDecBuffer* const pic) { + glutInitDisplayMode(GLUT_RGBA); + glutInitWindowSize(pic->width, pic->height); + glutCreateWindow("WebP viewer"); + glutReshapeFunc(HandleReshape); + glutDisplayFunc(HandleDisplay); + glutIdleFunc(NULL); + glutKeyboardFunc(HandleKey); + glClearColor(0.0, 0.0, 0.0, 0.0); + HandleReshape(pic->width, pic->height); + glutMainLoop(); +} + +//------------------------------------------------------------------------------ +// File decoding + +static const char* const kStatusMessages[] = { + "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR", + "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA" +}; + +static int Decode(const char* const in_file, WebPDecoderConfig* const config) { + WebPDecBuffer* const output_buffer = &config->output; + WebPBitstreamFeatures* const bitstream = &config->input; + VP8StatusCode status = VP8_STATUS_OK; + int ok; + size_t data_size = 0; + void* data = NULL; + FILE* const in = fopen(in_file, "rb"); + + if (!in) { + fprintf(stderr, "cannot open input file '%s'\n", in_file); + return 0; + } + fseek(in, 0, SEEK_END); + data_size = ftell(in); + fseek(in, 0, SEEK_SET); + data = malloc(data_size); + if (data == NULL) return 0; + ok = (fread(data, data_size, 1, in) == 1); + fclose(in); + if (!ok) { + fprintf(stderr, "Could not read %zu bytes of data from file %s\n", + data_size, in_file); + free(data); + return 0; + } + + status = WebPGetFeatures((const uint8_t*)data, data_size, bitstream); + if (status != VP8_STATUS_OK) { + goto end; + } + + output_buffer->colorspace = MODE_RGBA; + status = WebPDecode((const uint8_t*)data, data_size, config); + + end: + free(data); + ok = (status == VP8_STATUS_OK); + if (!ok) { + fprintf(stderr, "Decoding of %s failed.\n", in_file); + fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]); + } + return ok; +} + +//------------------------------------------------------------------------------ +// Main + +static void Help(void) { + printf("Usage: vwebp in_file [options]\n\n" + "Decodes the WebP image file and visualize it using OpenGL\n" + "Options are:\n" + " -version .... print version number and exit.\n" + " -nofancy ..... don't use the fancy YUV420 upscaler.\n" + " -nofilter .... disable in-loop filtering.\n" + " -mt .......... use multi-threading\n" + " -crop ... crop output with the given rectangle\n" + " -scale .......... scale the output (*after* any cropping)\n" + " -h ....... this help message.\n" + ); +} + +int main(int argc, char *argv[]) { + WebPDecoderConfig config; + int c; + + if (!WebPInitDecoderConfig(&config)) { + fprintf(stderr, "Library version mismatch!\n"); + return -1; + } + + for (c = 1; c < argc; ++c) { + if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) { + Help(); + return 0; + } else if (!strcmp(argv[c], "-nofancy")) { + config.options.no_fancy_upsampling = 1; + } else if (!strcmp(argv[c], "-nofilter")) { + config.options.bypass_filtering = 1; + } else if (!strcmp(argv[c], "-version")) { + const int version = WebPGetDecoderVersion(); + printf("%d.%d.%d\n", + (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); + return 0; + } else if (!strcmp(argv[c], "-mt")) { + config.options.use_threads = 1; + } else if (!strcmp(argv[c], "-crop") && c < argc - 4) { + config.options.use_cropping = 1; + config.options.crop_left = strtol(argv[++c], NULL, 0); + config.options.crop_top = strtol(argv[++c], NULL, 0); + config.options.crop_width = strtol(argv[++c], NULL, 0); + config.options.crop_height = strtol(argv[++c], NULL, 0); + } else if (!strcmp(argv[c], "-scale") && c < argc - 2) { + config.options.use_scaling = 1; + config.options.scaled_width = strtol(argv[++c], NULL, 0); + config.options.scaled_height = strtol(argv[++c], NULL, 0); + } else if (argv[c][0] == '-') { + printf("Unknown option '%s'\n", argv[c]); + Help(); + return -1; + } else { + file_name = argv[c]; + } + } + + if (file_name == NULL) { + printf("missing input file!!\n"); + Help(); + return -1; + } + if (!Decode(file_name, &config)) { + return -1; + } + + kPic = &config.output; + printf("Displaying [%s]: %d x %d. Press Esc to exit, 'i' for info.\n", + file_name, kPic->width, kPic->height); + + glutInit(&argc, argv); + Show(kPic); + + // Should only be reached when using FREEGLUT: + WebPFreeDecBuffer(&config.output); + return 0; +} + +//------------------------------------------------------------------------------