19aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Copyright 2010 Google Inc.
29aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
39aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// This code is licensed under the same terms as WebM:
49aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  Software License Agreement:  http://www.webmproject.org/license/software/
59aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  Additional IP Rights Grant:  http://www.webmproject.org/license/additional/
69aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// -----------------------------------------------------------------------------
79aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
89aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  simple command-line example calling libwebpdecode to
99aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  decode a WebP image into a PPM image.
109aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//  Compile with:     gcc -o dwebp dwebp.c -lwebpdecode
129aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//
139aea642eefa7a641ab8b89d953251939221d2719Eric Hassold// Author: Skal (pascal.massimino@gmail.com)
149aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
159aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <assert.h>
169aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <stdio.h>
179aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <stdlib.h>
189aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include <string.h>
199aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
209aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#include "webp/decode.h"
219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
229aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#if defined(__cplusplus) || defined(c_plusplus)
239aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldextern "C" {
249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
259aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
279aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
289aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldstatic void help(const char *s) {
299aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  printf("Usage: dwebp "
309aea642eefa7a641ab8b89d953251939221d2719Eric Hassold         "[options] [in_file] [-h] [-raw] [-o ppm_file]\n\n"
319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold         " -raw:  save the raw YUV samples as a grayscale PGM\n"
329aea642eefa7a641ab8b89d953251939221d2719Eric Hassold         "        file with IMC4 layout.\n"
339aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        );
349aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
359aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
369aea642eefa7a641ab8b89d953251939221d2719Eric Hassoldint main(int argc, char *argv[]) {
379aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  const char *in_file = NULL;
389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  const char *out_file = NULL;
399aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  int raw_output = 0;
409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  int width, height, stride, uv_stride;
429aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  uint8_t* out = NULL, *u = NULL, *v = NULL;
439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
449aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  int c;
459aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  for (c = 1; c < argc; ++c) {
469aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (!strcmp(argv[c], "-h")) {
479aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      help(argv[0]);
489aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return 0;
499aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
509aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      out_file = argv[++c];
519aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else if (!strcmp(argv[c], "-raw")) {
529aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      raw_output = 1;
539aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else if (argv[c][0] == '-') {
549aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      printf("Unknown option '%s'\n", argv[c]);
559aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      help(argv[0]);
569aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return -1;
579aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else {
589aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      in_file = argv[c];
599aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
609aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
619aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
629aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (in_file == NULL) {
639aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    printf("missing input file!!\n");
649aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    help(argv[0]);
659aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return -1;
669aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
679aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
689aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  {
699aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    uint32_t data_size = 0;
709aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    void* data = NULL;
719aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    FILE* const in = fopen(in_file, "rb");
729aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (!in) {
739aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      printf("cannot open input file '%s'\n", in_file);
749aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return 1;
759aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
769aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    fseek(in, 0, SEEK_END);
779aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    data_size = ftell(in);
789aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    fseek(in, 0, SEEK_SET);
799aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    data = malloc(data_size);
809aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    const int ok = (fread(data, data_size, 1, in) == 1);
819aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    fclose(in);
829aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (!ok) {
839aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      free(data);
849aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      return -1;
859aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
869aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
879aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (!raw_output) {
889aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      out = WebPDecodeRGB(data, data_size, &width, &height);
899aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else {
909aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      out = WebPDecodeYUV(data, data_size, &width, &height,
919aea642eefa7a641ab8b89d953251939221d2719Eric Hassold                          &u, &v, &stride, &uv_stride);
929aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
939aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    free(data);
949aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
959aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
969aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (!out) {
979aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    printf("Decoding of %s failed.\n", in_file);
989aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    return -1;
999aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
1009aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1019aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  if (out_file) {
1029aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    FILE* const fout = fopen(out_file, "wb");
1039aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    if (fout) {
1049aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      int ok = 1;
1059aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      if (!raw_output) {
1069aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        fprintf(fout, "P6\n%d %d\n255\n", width, height);
1079aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        ok &= (fwrite(out, width * height, 3, fout) == 3);
1089aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      } else {
1099aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        // Save a grayscale PGM file using the IMC4 layout
1109aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        // (http://www.fourcc.org/yuv.php#IMC4). This is a very
1119aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        // convenient format for viewing the samples, esp. for
1129aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        // odd dimensions.
1139aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        int y;
1149aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        const int uv_width = (width + 1) / 2;
1159aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        const int uv_height = (height + 1) / 2;
1169aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        const int out_stride = (width + 1) & ~1;
1179aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        fprintf(fout, "P5\n%d %d\n255\n", out_stride, height + uv_height);
1189aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        for (y = 0; ok && y < height; ++y) {
1199aea642eefa7a641ab8b89d953251939221d2719Eric Hassold          ok &= (fwrite(out + y * stride, width, 1, fout) == 1);
1209aea642eefa7a641ab8b89d953251939221d2719Eric Hassold          if (width & 1) fputc(0, fout);    // padding byte
1219aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        }
1229aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        for (y = 0; ok && y < uv_height; ++y) {
1239aea642eefa7a641ab8b89d953251939221d2719Eric Hassold          ok &= (fwrite(u + y * uv_stride, uv_width, 1, fout) == 1);
1249aea642eefa7a641ab8b89d953251939221d2719Eric Hassold          ok &= (fwrite(v + y * uv_stride, uv_width, 1, fout) == 1);
1259aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        }
1269aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      }
1279aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      fclose(fout);
1289aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      if (ok) {
1299aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        printf("Saved file %s\n", out_file);
1309aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      } else {
1319aea642eefa7a641ab8b89d953251939221d2719Eric Hassold        printf("Error writing file %s !!\n", out_file);
1329aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      }
1339aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    } else {
1349aea642eefa7a641ab8b89d953251939221d2719Eric Hassold      printf("Error opening output file %s\n", out_file);
1359aea642eefa7a641ab8b89d953251939221d2719Eric Hassold    }
1369aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  }
1379aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  printf("Decoded %s. Dimensions: %d x %d.\n", in_file, width, height);
1389aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  free(out);
1399aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1409aea642eefa7a641ab8b89d953251939221d2719Eric Hassold  return 0;
1419aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}
1429aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1439aea642eefa7a641ab8b89d953251939221d2719Eric Hassold//-----------------------------------------------------------------------------
1449aea642eefa7a641ab8b89d953251939221d2719Eric Hassold
1459aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#if defined(__cplusplus) || defined(c_plusplus)
1469aea642eefa7a641ab8b89d953251939221d2719Eric Hassold}    // extern "C"
1479aea642eefa7a641ab8b89d953251939221d2719Eric Hassold#endif
148