10406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Copyright 2010 Google Inc. All Rights Reserved.
29aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
30406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Use of this source code is governed by a BSD-style license
40406ce1417f76f2034833414dcecc9f56253640cVikas Arora// that can be found in the COPYING file in the root of the source
50406ce1417f76f2034833414dcecc9f56253640cVikas Arora// tree. An additional intellectual property rights grant can be found
60406ce1417f76f2034833414dcecc9f56253640cVikas Arora// in the file PATENTS. All contributing project authors may
70406ce1417f76f2034833414dcecc9f56253640cVikas Arora// be found in the AUTHORS file in the root of the source tree.
89aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// -----------------------------------------------------------------------------
99aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
100406ce1417f76f2034833414dcecc9f56253640cVikas Arora//  Command-line tool for decoding a WebP image.
119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
129aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Author: Skal (pascal.massimino@gmail.com)
139aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
149aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <assert.h>
159aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <stdio.h>
169aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <stdlib.h>
179aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <string.h>
189aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
190406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_CONFIG_H
200406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include "config.h"
210406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
220406ce1417f76f2034833414dcecc9f56253640cVikas Arora
230406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef WEBP_HAVE_PNG
240406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include <png.h>
250406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
260406ce1417f76f2034833414dcecc9f56253640cVikas Arora
270406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_WINCODEC_H
280406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef __MINGW32__
290406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define INITGUID  // Without this GUIDs are declared extern and fail to link
300406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
310406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define CINTERFACE
320406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define COBJMACROS
330406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define _WIN32_IE 0x500  // Workaround bug in shlwapi.h when compiling C++
340406ce1417f76f2034833414dcecc9f56253640cVikas Arora                         // code with COBJMACROS.
350406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include <shlwapi.h>
360406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include <windows.h>
370406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include <wincodec.h>
380406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
390406ce1417f76f2034833414dcecc9f56253640cVikas Arora
409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include "webp/decode.h"
410406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include "./example_util.h"
420406ce1417f76f2034833414dcecc9f56253640cVikas Arora#include "./stopwatch.h"
439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
440406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int verbose = 0;
450406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifndef WEBP_DLL
469aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#if defined(__cplusplus) || defined(c_plusplus)
479aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldextern "C" {
489aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
499aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
500406ce1417f76f2034833414dcecc9f56253640cVikas Aroraextern void* VP8GetCPUInfo;   // opaque forward declaration.
510406ce1417f76f2034833414dcecc9f56253640cVikas Arora
520406ce1417f76f2034833414dcecc9f56253640cVikas Arora#if defined(__cplusplus) || defined(c_plusplus)
530406ce1417f76f2034833414dcecc9f56253640cVikas Arora}    // extern "C"
540406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
550406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif  // WEBP_DLL
560406ce1417f76f2034833414dcecc9f56253640cVikas Arora
570406ce1417f76f2034833414dcecc9f56253640cVikas Arora//------------------------------------------------------------------------------
580406ce1417f76f2034833414dcecc9f56253640cVikas Arora
590406ce1417f76f2034833414dcecc9f56253640cVikas Arora// Output types
600406ce1417f76f2034833414dcecc9f56253640cVikas Aroratypedef enum {
610406ce1417f76f2034833414dcecc9f56253640cVikas Arora  PNG = 0,
620406ce1417f76f2034833414dcecc9f56253640cVikas Arora  PAM,
630406ce1417f76f2034833414dcecc9f56253640cVikas Arora  PPM,
640406ce1417f76f2034833414dcecc9f56253640cVikas Arora  PGM,
650406ce1417f76f2034833414dcecc9f56253640cVikas Arora  YUV,
660406ce1417f76f2034833414dcecc9f56253640cVikas Arora  ALPHA_PLANE_ONLY  // this is for experimenting only
670406ce1417f76f2034833414dcecc9f56253640cVikas Arora} OutputFileFormat;
680406ce1417f76f2034833414dcecc9f56253640cVikas Arora
690406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_WINCODEC_H
700406ce1417f76f2034833414dcecc9f56253640cVikas Arora
710406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define IFS(fn)                                                     \
720406ce1417f76f2034833414dcecc9f56253640cVikas Arora  do {                                                              \
730406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (SUCCEEDED(hr)) {                                            \
740406ce1417f76f2034833414dcecc9f56253640cVikas Arora      hr = (fn);                                                    \
750406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr);   \
760406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }                                                               \
770406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } while (0)
780406ce1417f76f2034833414dcecc9f56253640cVikas Arora
790406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef __cplusplus
800406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define MAKE_REFGUID(x) (x)
810406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else
820406ce1417f76f2034833414dcecc9f56253640cVikas Arora#define MAKE_REFGUID(x) &(x)
830406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
840406ce1417f76f2034833414dcecc9f56253640cVikas Arora
850406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic HRESULT CreateOutputStream(const char* out_file_name, IStream** stream) {
860406ce1417f76f2034833414dcecc9f56253640cVikas Arora  HRESULT hr = S_OK;
870406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(SHCreateStreamOnFileA(out_file_name, STGM_WRITE | STGM_CREATE, stream));
880406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (FAILED(hr)) {
890406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(stderr, "Error opening output file %s (%08lx)\n",
900406ce1417f76f2034833414dcecc9f56253640cVikas Arora            out_file_name, hr);
910406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
920406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return hr;
930406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
940406ce1417f76f2034833414dcecc9f56253640cVikas Arora
950406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
960406ce1417f76f2034833414dcecc9f56253640cVikas Arora                             unsigned char* rgb, int stride,
970406ce1417f76f2034833414dcecc9f56253640cVikas Arora                             uint32_t width, uint32_t height, int has_alpha) {
980406ce1417f76f2034833414dcecc9f56253640cVikas Arora  HRESULT hr = S_OK;
990406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IWICImagingFactory* factory = NULL;
1000406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IWICBitmapFrameEncode* frame = NULL;
1010406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IWICBitmapEncoder* encoder = NULL;
1020406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IStream* stream = NULL;
1030406ce1417f76f2034833414dcecc9f56253640cVikas Arora  WICPixelFormatGUID pixel_format = has_alpha ? GUID_WICPixelFormat32bppBGRA
1040406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                              : GUID_WICPixelFormat24bppBGR;
1050406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1060406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(CoInitialize(NULL));
1070406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
1080406ce1417f76f2034833414dcecc9f56253640cVikas Arora                       CLSCTX_INPROC_SERVER,
1090406ce1417f76f2034833414dcecc9f56253640cVikas Arora                       MAKE_REFGUID(IID_IWICImagingFactory),
1100406ce1417f76f2034833414dcecc9f56253640cVikas Arora                       (LPVOID*)&factory));
1110406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (hr == REGDB_E_CLASSNOTREG) {
1120406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(stderr,
1130406ce1417f76f2034833414dcecc9f56253640cVikas Arora            "Couldn't access Windows Imaging Component (are you running "
1140406ce1417f76f2034833414dcecc9f56253640cVikas Arora            "Windows XP SP3 or newer?). PNG support not available. "
1150406ce1417f76f2034833414dcecc9f56253640cVikas Arora            "Use -ppm or -pgm for available PPM and PGM formats.\n");
1160406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
1170406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(CreateOutputStream(out_file_name, &stream));
1180406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICImagingFactory_CreateEncoder(factory, container_guid, NULL,
1190406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                       &encoder));
1200406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapEncoder_Initialize(encoder, stream,
1210406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                   WICBitmapEncoderNoCache));
1220406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapEncoder_CreateNewFrame(encoder, &frame, NULL));
1230406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapFrameEncode_Initialize(frame, NULL));
1240406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapFrameEncode_SetSize(frame, width, height));
1250406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapFrameEncode_SetPixelFormat(frame, &pixel_format));
1260406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapFrameEncode_WritePixels(frame, height, stride,
1270406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                        height * stride, rgb));
1280406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapFrameEncode_Commit(frame));
1290406ce1417f76f2034833414dcecc9f56253640cVikas Arora  IFS(IWICBitmapEncoder_Commit(encoder));
1300406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1310406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (frame != NULL) IUnknown_Release(frame);
1320406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (encoder != NULL) IUnknown_Release(encoder);
1330406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (factory != NULL) IUnknown_Release(factory);
1340406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (stream != NULL) IUnknown_Release(stream);
1350406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return hr;
1360406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1370406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1380406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WritePNG(const char* out_file_name,
1390406ce1417f76f2034833414dcecc9f56253640cVikas Arora                    const WebPDecBuffer* const buffer) {
1400406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t width = buffer->width;
1410406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t height = buffer->height;
1420406ce1417f76f2034833414dcecc9f56253640cVikas Arora  unsigned char* const rgb = buffer->u.RGBA.rgba;
1430406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int stride = buffer->u.RGBA.stride;
1440406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int has_alpha = (buffer->colorspace == MODE_BGRA);
1450406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1460406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return SUCCEEDED(WriteUsingWIC(out_file_name,
1470406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                 MAKE_REFGUID(GUID_ContainerFormatPng),
1480406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                 rgb, stride, width, height, has_alpha));
1490406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1500406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1510406ce1417f76f2034833414dcecc9f56253640cVikas Arora#elif defined(WEBP_HAVE_PNG)    // !HAVE_WINCODEC_H
1520406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic void PNGAPI error_function(png_structp png, png_const_charp dummy) {
1530406ce1417f76f2034833414dcecc9f56253640cVikas Arora  (void)dummy;  // remove variable-unused warning
1540406ce1417f76f2034833414dcecc9f56253640cVikas Arora  longjmp(png_jmpbuf(png), 1);
1550406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1560406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1570406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
1580406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t width = buffer->width;
1590406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t height = buffer->height;
1600406ce1417f76f2034833414dcecc9f56253640cVikas Arora  unsigned char* const rgb = buffer->u.RGBA.rgba;
1610406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int stride = buffer->u.RGBA.stride;
1620406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int has_alpha = (buffer->colorspace == MODE_RGBA);
1630406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_structp png;
1640406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_infop info;
1650406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_uint_32 y;
1660406ce1417f76f2034833414dcecc9f56253640cVikas Arora
1670406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
1680406ce1417f76f2034833414dcecc9f56253640cVikas Arora                                NULL, error_function, NULL);
1690406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (png == NULL) {
1700406ce1417f76f2034833414dcecc9f56253640cVikas Arora    return 0;
1710406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
1720406ce1417f76f2034833414dcecc9f56253640cVikas Arora  info = png_create_info_struct(png);
1730406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (info == NULL) {
1740406ce1417f76f2034833414dcecc9f56253640cVikas Arora    png_destroy_write_struct(&png, NULL);
1750406ce1417f76f2034833414dcecc9f56253640cVikas Arora    return 0;
1760406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
1770406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (setjmp(png_jmpbuf(png))) {
1780406ce1417f76f2034833414dcecc9f56253640cVikas Arora    png_destroy_write_struct(&png, &info);
1790406ce1417f76f2034833414dcecc9f56253640cVikas Arora    return 0;
1800406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
1810406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_init_io(png, out_file);
1820406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_set_IHDR(png, info, width, height, 8,
1830406ce1417f76f2034833414dcecc9f56253640cVikas Arora               has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
1840406ce1417f76f2034833414dcecc9f56253640cVikas Arora               PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
1850406ce1417f76f2034833414dcecc9f56253640cVikas Arora               PNG_FILTER_TYPE_DEFAULT);
1860406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_write_info(png, info);
1870406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (y = 0; y < height; ++y) {
1880406ce1417f76f2034833414dcecc9f56253640cVikas Arora    png_bytep row = rgb + y * stride;
1890406ce1417f76f2034833414dcecc9f56253640cVikas Arora    png_write_rows(png, &row, 1);
1900406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
1910406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_write_end(png, info);
1920406ce1417f76f2034833414dcecc9f56253640cVikas Arora  png_destroy_write_struct(&png, &info);
1930406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return 1;
1940406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
1950406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else    // !HAVE_WINCODEC_H && !WEBP_HAVE_PNG
1960406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WritePNG(FILE* out_file, const WebPDecBuffer* const buffer) {
1970406ce1417f76f2034833414dcecc9f56253640cVikas Arora  (void)out_file;
1980406ce1417f76f2034833414dcecc9f56253640cVikas Arora  (void)buffer;
1990406ce1417f76f2034833414dcecc9f56253640cVikas Arora  fprintf(stderr, "PNG support not compiled. Please install the libpng "
2000406ce1417f76f2034833414dcecc9f56253640cVikas Arora          "development package before building.\n");
2010406ce1417f76f2034833414dcecc9f56253640cVikas Arora  fprintf(stderr, "You can run with -ppm flag to decode in PPM format.\n");
2020406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return 0;
2030406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
2040406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
2050406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2060406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WritePPM(FILE* fout, const WebPDecBuffer* const buffer, int alpha) {
2070406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t width = buffer->width;
2080406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t height = buffer->height;
2090406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const unsigned char* const rgb = buffer->u.RGBA.rgba;
2100406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int stride = buffer->u.RGBA.stride;
2110406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const size_t bytes_per_px = alpha ? 4 : 3;
2120406ce1417f76f2034833414dcecc9f56253640cVikas Arora  uint32_t y;
2130406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2140406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (alpha) {
2150406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(fout, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\n"
2160406ce1417f76f2034833414dcecc9f56253640cVikas Arora                  "TUPLTYPE RGB_ALPHA\nENDHDR\n", width, height);
2170406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else {
2180406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(fout, "P6\n%d %d\n255\n", width, height);
2190406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2200406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (y = 0; y < height; ++y) {
2210406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (fwrite(rgb + y * stride, width, bytes_per_px, fout) != bytes_per_px) {
2220406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return 0;
2230406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2240406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2250406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return 1;
2260406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
2270406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2280406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WriteAlphaPlane(FILE* fout, const WebPDecBuffer* const buffer) {
2290406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t width = buffer->width;
2300406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const uint32_t height = buffer->height;
2310406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const unsigned char* const a = buffer->u.YUVA.a;
2320406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int a_stride = buffer->u.YUVA.a_stride;
2330406ce1417f76f2034833414dcecc9f56253640cVikas Arora  uint32_t y;
2340406ce1417f76f2034833414dcecc9f56253640cVikas Arora  assert(a != NULL);
2350406ce1417f76f2034833414dcecc9f56253640cVikas Arora  fprintf(fout, "P5\n%d %d\n255\n", width, height);
2360406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (y = 0; y < height; ++y) {
2370406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (fwrite(a + y * a_stride, width, 1, fout) != 1) {
2380406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return 0;
2390406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2400406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2410406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return 1;
2420406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
2430406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2440406ce1417f76f2034833414dcecc9f56253640cVikas Arora// format=PGM: save a grayscale PGM file using the IMC4 layout
2450406ce1417f76f2034833414dcecc9f56253640cVikas Arora// (http://www.fourcc.org/yuv.php#IMC4). This is a very convenient format for
2460406ce1417f76f2034833414dcecc9f56253640cVikas Arora// viewing the samples, esp. for odd dimensions.
2470406ce1417f76f2034833414dcecc9f56253640cVikas Arora// format=YUV: just save the Y/U/V/A planes sequentially without header.
2480406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic int WritePGMOrYUV(FILE* fout, const WebPDecBuffer* const buffer,
2490406ce1417f76f2034833414dcecc9f56253640cVikas Arora                         OutputFileFormat format) {
2500406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int width = buffer->width;
2510406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int height = buffer->height;
2520406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const WebPYUVABuffer* const yuv = &buffer->u.YUVA;
2530406ce1417f76f2034833414dcecc9f56253640cVikas Arora  int ok = 1;
2540406ce1417f76f2034833414dcecc9f56253640cVikas Arora  int y;
2550406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int pad = (format == YUV) ? 0 : 1;
2560406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int uv_width = (width + 1) / 2;
2570406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int uv_height = (height + 1) / 2;
2580406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int out_stride = (width + pad) & ~pad;
2590406ce1417f76f2034833414dcecc9f56253640cVikas Arora  const int a_height = yuv->a ? height : 0;
2600406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (format == PGM) {
2610406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(fout, "P5\n%d %d\n255\n",
2620406ce1417f76f2034833414dcecc9f56253640cVikas Arora            out_stride, height + uv_height + a_height);
2630406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2640406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (y = 0; ok && y < height; ++y) {
2650406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= (fwrite(yuv->y + y * yuv->y_stride, width, 1, fout) == 1);
2660406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (format == PGM) {
2670406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (width & 1) fputc(0, fout);    // padding byte
2680406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2690406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2700406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (format == PGM) {   // IMC4 layout
2710406ce1417f76f2034833414dcecc9f56253640cVikas Arora    for (y = 0; ok && y < uv_height; ++y) {
2720406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
2730406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
2740406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2750406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else {
2760406ce1417f76f2034833414dcecc9f56253640cVikas Arora    for (y = 0; ok && y < uv_height; ++y) {
2770406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok &= (fwrite(yuv->u + y * yuv->u_stride, uv_width, 1, fout) == 1);
2780406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2790406ce1417f76f2034833414dcecc9f56253640cVikas Arora    for (y = 0; ok && y < uv_height; ++y) {
2800406ce1417f76f2034833414dcecc9f56253640cVikas Arora      ok &= (fwrite(yuv->v + y * yuv->v_stride, uv_width, 1, fout) == 1);
2810406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2820406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2830406ce1417f76f2034833414dcecc9f56253640cVikas Arora  for (y = 0; ok && y < a_height; ++y) {
2840406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= (fwrite(yuv->a + y * yuv->a_stride, width, 1, fout) == 1);
2850406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (format == PGM) {
2860406ce1417f76f2034833414dcecc9f56253640cVikas Arora      if (width & 1) fputc(0, fout);    // padding byte
2870406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
2880406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
2890406ce1417f76f2034833414dcecc9f56253640cVikas Arora  return ok;
2900406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
2910406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2920406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic void SaveOutput(const WebPDecBuffer* const buffer,
2930406ce1417f76f2034833414dcecc9f56253640cVikas Arora                       OutputFileFormat format, const char* const out_file) {
2940406ce1417f76f2034833414dcecc9f56253640cVikas Arora  FILE* fout = NULL;
2950406ce1417f76f2034833414dcecc9f56253640cVikas Arora  int needs_open_file = 1;
2960406ce1417f76f2034833414dcecc9f56253640cVikas Arora  int ok = 1;
2970406ce1417f76f2034833414dcecc9f56253640cVikas Arora  Stopwatch stop_watch;
2980406ce1417f76f2034833414dcecc9f56253640cVikas Arora
2990406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (verbose)
3000406ce1417f76f2034833414dcecc9f56253640cVikas Arora    StopwatchReadAndReset(&stop_watch);
3010406ce1417f76f2034833414dcecc9f56253640cVikas Arora
3020406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_WINCODEC_H
3030406ce1417f76f2034833414dcecc9f56253640cVikas Arora  needs_open_file = (format != PNG);
3040406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
3050406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (needs_open_file) {
3060406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fout = fopen(out_file, "wb");
3070406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (!fout) {
3080406ce1417f76f2034833414dcecc9f56253640cVikas Arora      fprintf(stderr, "Error opening output file %s\n", out_file);
3090406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return;
3100406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
3110406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
3120406ce1417f76f2034833414dcecc9f56253640cVikas Arora
3130406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (format == PNG) {
3140406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_WINCODEC_H
3150406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WritePNG(out_file, buffer);
3160406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else
3170406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WritePNG(fout, buffer);
3180406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
3190406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else if (format == PAM) {
3200406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WritePPM(fout, buffer, 1);
3210406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else if (format == PPM) {
3220406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WritePPM(fout, buffer, 0);
3230406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else if (format == PGM || format == YUV) {
3240406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WritePGMOrYUV(fout, buffer, format);
3250406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else if (format == ALPHA_PLANE_ONLY) {
3260406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok &= WriteAlphaPlane(fout, buffer);
3270406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
3280406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (fout) {
3290406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fclose(fout);
3300406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
3310406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (ok) {
3320406ce1417f76f2034833414dcecc9f56253640cVikas Arora    printf("Saved file %s\n", out_file);
3330406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (verbose) {
3340406ce1417f76f2034833414dcecc9f56253640cVikas Arora      const double write_time = StopwatchReadAndReset(&stop_watch);
3350406ce1417f76f2034833414dcecc9f56253640cVikas Arora      printf("Time to write output: %.3fs\n", write_time);
3360406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
3370406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else {
3380406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(stderr, "Error writing file %s !!\n", out_file);
3390406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
3400406ce1417f76f2034833414dcecc9f56253640cVikas Arora}
3419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
3420406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic void Help(void) {
3430406ce1417f76f2034833414dcecc9f56253640cVikas Arora  printf("Usage: dwebp in_file [options] [-o out_file]\n\n"
3440406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "Decodes the WebP image file to PNG format [Default]\n"
3450406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "Use following options to convert into alternate image formats:\n"
3460406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -pam ......... save the raw RGBA samples as a color PAM\n"
3470406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -ppm ......... save the raw RGB samples as a color PPM\n"
3480406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -pgm ......... save the raw YUV samples as a grayscale PGM\n"
3490406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "                 file with IMC4 layout.\n"
3500406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -yuv ......... save the raw YUV samples in flat layout.\n"
3510406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "\n"
3520406ce1417f76f2034833414dcecc9f56253640cVikas Arora         " Other options are:\n"
3530406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -version  .... print version number and exit.\n"
3540406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -nofancy ..... don't use the fancy YUV420 upscaler.\n"
3550406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -nofilter .... disable in-loop filtering.\n"
3560406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -mt .......... use multi-threading\n"
3570406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -crop <x> <y> <w> <h> ... crop output with the given rectangle\n"
3580406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -scale <w> <h> .......... scale the output (*after* any cropping)\n"
3590406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -alpha ....... only save the alpha plane.\n"
3600406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -h     ....... this help message.\n"
3610406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -v     ....... verbose (e.g. print encoding/decoding times)\n"
3620406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifndef WEBP_DLL
3630406ce1417f76f2034833414dcecc9f56253640cVikas Arora         "  -noasm ....... disable all assembly optimizations.\n"
3640406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
3659aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        );
3669aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
3679aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
3680406ce1417f76f2034833414dcecc9f56253640cVikas Arorastatic const char* const kStatusMessages[] = {
3690406ce1417f76f2034833414dcecc9f56253640cVikas Arora  "OK", "OUT_OF_MEMORY", "INVALID_PARAM", "BITSTREAM_ERROR",
3700406ce1417f76f2034833414dcecc9f56253640cVikas Arora  "UNSUPPORTED_FEATURE", "SUSPENDED", "USER_ABORT", "NOT_ENOUGH_DATA"
3710406ce1417f76f2034833414dcecc9f56253640cVikas Arora};
3720406ce1417f76f2034833414dcecc9f56253640cVikas Arora
3730406ce1417f76f2034833414dcecc9f56253640cVikas Aroraint main(int argc, const char *argv[]) {
3749aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  const char *in_file = NULL;
3759aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  const char *out_file = NULL;
3769aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
3770406ce1417f76f2034833414dcecc9f56253640cVikas Arora  WebPDecoderConfig config;
3780406ce1417f76f2034833414dcecc9f56253640cVikas Arora  WebPDecBuffer* const output_buffer = &config.output;
3790406ce1417f76f2034833414dcecc9f56253640cVikas Arora  WebPBitstreamFeatures* const bitstream = &config.input;
3800406ce1417f76f2034833414dcecc9f56253640cVikas Arora  OutputFileFormat format = PNG;
3819aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  int c;
3820406ce1417f76f2034833414dcecc9f56253640cVikas Arora
3830406ce1417f76f2034833414dcecc9f56253640cVikas Arora  if (!WebPInitDecoderConfig(&config)) {
3840406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(stderr, "Library version mismatch!\n");
3850406ce1417f76f2034833414dcecc9f56253640cVikas Arora    return -1;
3860406ce1417f76f2034833414dcecc9f56253640cVikas Arora  }
3870406ce1417f76f2034833414dcecc9f56253640cVikas Arora
3889aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  for (c = 1; c < argc; ++c) {
3890406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
3900406ce1417f76f2034833414dcecc9f56253640cVikas Arora      Help();
3919aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return 0;
3929aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
3939aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      out_file = argv[++c];
3940406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-alpha")) {
3950406ce1417f76f2034833414dcecc9f56253640cVikas Arora      format = ALPHA_PLANE_ONLY;
3960406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-nofancy")) {
3970406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.no_fancy_upsampling = 1;
3980406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-nofilter")) {
3990406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.bypass_filtering = 1;
4000406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-pam")) {
4010406ce1417f76f2034833414dcecc9f56253640cVikas Arora      format = PAM;
4020406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-ppm")) {
4030406ce1417f76f2034833414dcecc9f56253640cVikas Arora      format = PPM;
4040406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-version")) {
4050406ce1417f76f2034833414dcecc9f56253640cVikas Arora      const int version = WebPGetDecoderVersion();
4060406ce1417f76f2034833414dcecc9f56253640cVikas Arora      printf("%d.%d.%d\n",
4070406ce1417f76f2034833414dcecc9f56253640cVikas Arora             (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
4080406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return 0;
4090406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-pgm")) {
4100406ce1417f76f2034833414dcecc9f56253640cVikas Arora      format = PGM;
4110406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-yuv")) {
4120406ce1417f76f2034833414dcecc9f56253640cVikas Arora      format = YUV;
4130406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-mt")) {
4140406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.use_threads = 1;
4150406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
4160406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.use_cropping = 1;
4170406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.crop_left   = strtol(argv[++c], NULL, 0);
4180406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.crop_top    = strtol(argv[++c], NULL, 0);
4190406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.crop_width  = strtol(argv[++c], NULL, 0);
4200406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.crop_height = strtol(argv[++c], NULL, 0);
4210406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-scale") && c < argc - 2) {
4220406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.use_scaling = 1;
4230406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.scaled_width  = strtol(argv[++c], NULL, 0);
4240406ce1417f76f2034833414dcecc9f56253640cVikas Arora      config.options.scaled_height = strtol(argv[++c], NULL, 0);
4250406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-v")) {
4260406ce1417f76f2034833414dcecc9f56253640cVikas Arora      verbose = 1;
4270406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifndef WEBP_DLL
4280406ce1417f76f2034833414dcecc9f56253640cVikas Arora    } else if (!strcmp(argv[c], "-noasm")) {
4290406ce1417f76f2034833414dcecc9f56253640cVikas Arora      VP8GetCPUInfo = NULL;
4300406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
4319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else if (argv[c][0] == '-') {
4320406ce1417f76f2034833414dcecc9f56253640cVikas Arora      fprintf(stderr, "Unknown option '%s'\n", argv[c]);
4330406ce1417f76f2034833414dcecc9f56253640cVikas Arora      Help();
4349aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return -1;
4359aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else {
4369aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      in_file = argv[c];
4379aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
4389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
4399aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
4409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (in_file == NULL) {
4410406ce1417f76f2034833414dcecc9f56253640cVikas Arora    fprintf(stderr, "missing input file!!\n");
4420406ce1417f76f2034833414dcecc9f56253640cVikas Arora    Help();
4439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return -1;
4449aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
4459aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
4469aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  {
4470406ce1417f76f2034833414dcecc9f56253640cVikas Arora    Stopwatch stop_watch;
4480406ce1417f76f2034833414dcecc9f56253640cVikas Arora    VP8StatusCode status = VP8_STATUS_OK;
4490406ce1417f76f2034833414dcecc9f56253640cVikas Arora    int ok;
4500406ce1417f76f2034833414dcecc9f56253640cVikas Arora    size_t data_size = 0;
4510406ce1417f76f2034833414dcecc9f56253640cVikas Arora    const uint8_t* data = NULL;
4520406ce1417f76f2034833414dcecc9f56253640cVikas Arora
4530406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (!ExUtilReadFile(in_file, &data, &data_size)) return -1;
4540406ce1417f76f2034833414dcecc9f56253640cVikas Arora
4550406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (verbose)
4560406ce1417f76f2034833414dcecc9f56253640cVikas Arora      StopwatchReadAndReset(&stop_watch);
4570406ce1417f76f2034833414dcecc9f56253640cVikas Arora
4580406ce1417f76f2034833414dcecc9f56253640cVikas Arora    status = WebPGetFeatures(data, data_size, bitstream);
4590406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (status != VP8_STATUS_OK) {
4600406ce1417f76f2034833414dcecc9f56253640cVikas Arora      goto end;
4619aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
4620406ce1417f76f2034833414dcecc9f56253640cVikas Arora
4630406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (bitstream->has_animation) {
4640406ce1417f76f2034833414dcecc9f56253640cVikas Arora      fprintf(stderr,
4650406ce1417f76f2034833414dcecc9f56253640cVikas Arora              "Error! Decoding of an animated WebP file is not supported.\n"
4660406ce1417f76f2034833414dcecc9f56253640cVikas Arora              "       Use webpmux to extract the individual frames or\n"
4670406ce1417f76f2034833414dcecc9f56253640cVikas Arora              "       vwebp to view this image.\n");
4689aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
4699aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
4700406ce1417f76f2034833414dcecc9f56253640cVikas Arora    switch (format) {
4710406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case PNG:
4720406ce1417f76f2034833414dcecc9f56253640cVikas Arora#ifdef HAVE_WINCODEC_H
4730406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = bitstream->has_alpha ? MODE_BGRA : MODE_BGR;
4740406ce1417f76f2034833414dcecc9f56253640cVikas Arora#else
4750406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = bitstream->has_alpha ? MODE_RGBA : MODE_RGB;
4760406ce1417f76f2034833414dcecc9f56253640cVikas Arora#endif
4770406ce1417f76f2034833414dcecc9f56253640cVikas Arora        break;
4780406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case PAM:
4790406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = MODE_RGBA;
4800406ce1417f76f2034833414dcecc9f56253640cVikas Arora        break;
4810406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case PPM:
4820406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = MODE_RGB;  // drops alpha for PPM
4830406ce1417f76f2034833414dcecc9f56253640cVikas Arora        break;
4840406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case PGM:
4850406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case YUV:
4860406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = bitstream->has_alpha ? MODE_YUVA : MODE_YUV;
4870406ce1417f76f2034833414dcecc9f56253640cVikas Arora        break;
4880406ce1417f76f2034833414dcecc9f56253640cVikas Arora      case ALPHA_PLANE_ONLY:
4890406ce1417f76f2034833414dcecc9f56253640cVikas Arora        output_buffer->colorspace = MODE_YUVA;
4900406ce1417f76f2034833414dcecc9f56253640cVikas Arora        break;
4910406ce1417f76f2034833414dcecc9f56253640cVikas Arora      default:
4920406ce1417f76f2034833414dcecc9f56253640cVikas Arora        free((void*)data);
4930406ce1417f76f2034833414dcecc9f56253640cVikas Arora        return -1;
4949aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
4950406ce1417f76f2034833414dcecc9f56253640cVikas Arora    status = WebPDecode(data, data_size, &config);
4969aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
4970406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (verbose) {
4980406ce1417f76f2034833414dcecc9f56253640cVikas Arora      const double decode_time = StopwatchReadAndReset(&stop_watch);
4990406ce1417f76f2034833414dcecc9f56253640cVikas Arora      printf("Time to decode picture: %.3fs\n", decode_time);
5000406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
5010406ce1417f76f2034833414dcecc9f56253640cVikas Arora end:
5020406ce1417f76f2034833414dcecc9f56253640cVikas Arora    free((void*)data);
5030406ce1417f76f2034833414dcecc9f56253640cVikas Arora    ok = (status == VP8_STATUS_OK);
5040406ce1417f76f2034833414dcecc9f56253640cVikas Arora    if (!ok) {
5050406ce1417f76f2034833414dcecc9f56253640cVikas Arora      fprintf(stderr, "Decoding of %s failed.\n", in_file);
5060406ce1417f76f2034833414dcecc9f56253640cVikas Arora      fprintf(stderr, "Status: %d (%s)\n", status, kStatusMessages[status]);
5070406ce1417f76f2034833414dcecc9f56253640cVikas Arora      return -1;
5080406ce1417f76f2034833414dcecc9f56253640cVikas Arora    }
5099aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
5109aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
5119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (out_file) {
5120406ce1417f76f2034833414dcecc9f56253640cVikas Arora    printf("Decoded %s. Dimensions: %d x %d%s. Now saving...\n", in_file,
5130406ce1417f76f2034833414dcecc9f56253640cVikas Arora           output_buffer->width, output_buffer->height,
5140406ce1417f76f2034833414dcecc9f56253640cVikas Arora           bitstream->has_alpha ? " (with alpha)" : "");
5150406ce1417f76f2034833414dcecc9f56253640cVikas Arora    SaveOutput(output_buffer, format, out_file);
5160406ce1417f76f2034833414dcecc9f56253640cVikas Arora  } else {
5170406ce1417f76f2034833414dcecc9f56253640cVikas Arora    printf("File %s can be decoded (dimensions: %d x %d)%s.\n",
5180406ce1417f76f2034833414dcecc9f56253640cVikas Arora           in_file, output_buffer->width, output_buffer->height,
5190406ce1417f76f2034833414dcecc9f56253640cVikas Arora           bitstream->has_alpha ? " (with alpha)" : "");
5200406ce1417f76f2034833414dcecc9f56253640cVikas Arora    printf("Nothing written; use -o flag to save the result as e.g. PNG.\n");
5219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
5220406ce1417f76f2034833414dcecc9f56253640cVikas Arora  WebPFreeDecBuffer(output_buffer);
5239aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
5249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return 0;
5259aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
5269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
5270406ce1417f76f2034833414dcecc9f56253640cVikas Arora//------------------------------------------------------------------------------
528