blob: 38cccdf3cf2cacac7c829f4c8fe4552979d2ff31 [file] [log] [blame]
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001// Copyright 2011 Google Inc.
2//
3// This code is licensed under the same terms as WebM:
4// Software License Agreement: http://www.webmproject.org/license/software/
5// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
6// -----------------------------------------------------------------------------
7//
8// simple command line calling the WebPEncode function.
9// Encodes a raw .YUV into WebP bitstream
10//
11// Author: Skal (pascal.massimino@gmail.com)
12
13#include <stdio.h>
Pascal Massimino4b0b0d62011-03-26 09:27:45 -070014#include <stdlib.h>
Pascal Massiminof61d14a2011-02-18 23:33:46 -080015#include <string.h>
16
17#ifdef WEBP_HAVE_PNG
18#include <png.h>
19#endif
20
21#ifdef WEBP_HAVE_JPEG
22#include <setjmp.h> // note: this must be included *after* png.h
23#include <jpeglib.h>
24#endif
25
26#ifdef _WIN32
27#define CINTERFACE
28#define COBJMACROS
29#define _WIN32_IE 0x500 // Workaround bug in shlwapi.h when compiling C++
30 // code with COBJMACROS.
31#include <shlwapi.h>
32#include <windows.h>
33#include <wincodec.h>
34#endif
35
36
37#include "webp/encode.h"
38#include "stopwatch.h"
39
Pascal Massiminocfbf88a2011-04-22 12:14:45 -070040extern void* VP8GetCPUInfo;
41
Pascal Massiminof61d14a2011-02-18 23:33:46 -080042//-----------------------------------------------------------------------------
43
44static int verbose = 0;
45
46static int ReadYUV(FILE* in_file, WebPPicture* const pic) {
47 const int uv_width = (pic->width + 1) / 2;
48 const int uv_height = (pic->height + 1) / 2;
49 int y;
50 int ok = 0;
51
52 if (!WebPPictureAlloc(pic)) return ok;
53
54 for (y = 0; y < pic->height; ++y) {
55 if (fread(pic->y + y * pic->y_stride, pic->width, 1, in_file) != 1) {
56 goto End;
57 }
58 }
59 for (y = 0; y < uv_height; ++y) {
60 if (fread(pic->u + y * pic->uv_stride, uv_width, 1, in_file) != 1)
61 goto End;
62 }
63 for (y = 0; y < uv_height; ++y) {
64 if (fread(pic->v + y * pic->uv_stride, uv_width, 1, in_file) != 1)
65 goto End;
66 }
67 ok = 1;
68
69 End:
70 return ok;
71}
72
73#ifdef _WIN32
74
75#define IFS(fn) \
76 do { \
77 if (SUCCEEDED(hr)) \
78 { \
79 hr = (fn); \
80 if (FAILED(hr) && verbose) \
81 printf(#fn " failed %08x\n", hr); \
82 } \
83 } while (0)
84
85#ifdef __cplusplus
86#define MAKE_REFGUID(x) (x)
87#else
88#define MAKE_REFGUID(x) &(x)
89#endif
90
91static HRESULT OpenInputStream(const char* filename, IStream** ppStream) {
92 HRESULT hr = S_OK;
93 IFS(SHCreateStreamOnFileA(filename, STGM_READ, ppStream));
94 if (FAILED(hr))
95 printf("Error opening input file %s (%08x)\n", filename, hr);
96 return hr;
97}
98
99static HRESULT ReadPictureWithWIC(const char* filename,
100 WebPPicture* const pic) {
101 HRESULT hr = S_OK;
102 IWICBitmapFrameDecode* pFrame = NULL;
103 IWICFormatConverter* pConverter = NULL;
104 IWICImagingFactory* pFactory = NULL;
105 IWICBitmapDecoder* pDecoder = NULL;
106 IStream* pStream = NULL;
107 UINT frameCount = 0;
108 UINT width, height = 0;
109 BYTE* rgb = NULL;
110
111 IFS(CoInitialize(NULL));
112 IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
113 CLSCTX_INPROC_SERVER, MAKE_REFGUID(IID_IWICImagingFactory),
114 (LPVOID*)&pFactory));
115 if (hr == REGDB_E_CLASSNOTREG) {
116 printf("Couldn't access Windows Imaging Component (are you running \n");
117 printf("Windows XP SP3 or newer?). Most formats not available.\n");
118 printf("Use -s for the available YUV input.\n");
119 }
120 // Prepare for image decoding.
121 IFS(OpenInputStream(filename, &pStream));
122 IFS(IWICImagingFactory_CreateDecoderFromStream(pFactory, pStream, NULL,
123 WICDecodeMetadataCacheOnDemand, &pDecoder));
124 IFS(IWICBitmapDecoder_GetFrameCount(pDecoder, &frameCount));
125 if (SUCCEEDED(hr) && frameCount == 0) {
126 printf("No frame found in input file.\n");
127 hr = E_FAIL;
128 }
129 IFS(IWICBitmapDecoder_GetFrame(pDecoder, 0, &pFrame));
130
131 // Prepare for pixel format conversion (if necessary).
132 IFS(IWICImagingFactory_CreateFormatConverter(pFactory, &pConverter));
133 IFS(IWICFormatConverter_Initialize(pConverter, (IWICBitmapSource*)pFrame,
134 MAKE_REFGUID(GUID_WICPixelFormat24bppRGB), WICBitmapDitherTypeNone,
135 NULL, 0.0, WICBitmapPaletteTypeCustom));
136
137 // Decode.
138 IFS(IWICFormatConverter_GetSize(pConverter, &width, &height));
139 if (SUCCEEDED(hr)) {
140 rgb = (BYTE*)malloc(3 * width * height);
141 if (rgb == NULL)
142 hr = E_OUTOFMEMORY;
143 }
144 IFS(IWICFormatConverter_CopyPixels(pConverter, NULL, 3 * width,
145 3 * width * height, rgb));
146
147 // WebP conversion.
148 if (SUCCEEDED(hr)) {
149 pic->width = width;
150 pic->height = height;
151 if (!WebPPictureImportRGB(pic, rgb, 3 * width))
152 hr = E_FAIL;
153 }
154
155 // Cleanup.
156 if (pConverter != NULL) IUnknown_Release(pConverter);
157 if (pFrame != NULL) IUnknown_Release(pFrame);
158 if (pDecoder != NULL) IUnknown_Release(pDecoder);
159 if (pFactory != NULL) IUnknown_Release(pFactory);
160 if (pStream != NULL) IUnknown_Release(pStream);
161 free(rgb);
162 return hr;
163}
164
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700165static int ReadPicture(const char* const filename, WebPPicture* const pic,
166 int keep_alpha) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800167 int ok;
168 if (pic->width != 0 && pic->height != 0) {
169 // If image size is specified, infer it as YUV format.
170 FILE* in_file = fopen(filename, "rb");
171 if (in_file == NULL) {
172 fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
173 return 0;
174 }
175 ok = ReadYUV(in_file, pic);
176 fclose(in_file);
177 } else {
178 // If no size specified, try to decode it using WIC.
179 ok = SUCCEEDED(ReadPictureWithWIC(filename, pic));
180 }
181 if (!ok) {
182 fprintf(stderr, "Error! Could not process file %s\n", filename);
183 }
184 return ok;
185}
186
187#else // !_WIN32
188
189#ifdef WEBP_HAVE_JPEG
190struct my_error_mgr {
191 struct jpeg_error_mgr pub;
192 jmp_buf setjmp_buffer;
193};
194
195static void my_error_exit(j_common_ptr dinfo) {
196 struct my_error_mgr* myerr = (struct my_error_mgr*) dinfo->err;
197 (*dinfo->err->output_message) (dinfo);
198 longjmp(myerr->setjmp_buffer, 1);
199}
200
201static int ReadJPEG(FILE* in_file, WebPPicture* const pic) {
202 int ok = 0;
203 int stride, width, height;
204 uint8_t* rgb = NULL;
205 uint8_t* row_ptr = NULL;
206 struct jpeg_decompress_struct dinfo;
207 struct my_error_mgr jerr;
208 JSAMPARRAY buffer;
209
210 dinfo.err = jpeg_std_error(&jerr.pub);
211 jerr.pub.error_exit = my_error_exit;
212
213 if (setjmp (jerr.setjmp_buffer)) {
214 Error:
215 jpeg_destroy_decompress(&dinfo);
216 goto End;
217 }
218
219 jpeg_create_decompress(&dinfo);
220 jpeg_stdio_src(&dinfo, in_file);
221 jpeg_read_header(&dinfo, TRUE);
222
223 dinfo.out_color_space = JCS_RGB;
224 dinfo.dct_method = JDCT_IFAST;
225 dinfo.do_fancy_upsampling = TRUE;
226
227 jpeg_start_decompress(&dinfo);
228
229 if (dinfo.output_components != 3) {
230 goto Error;
231 }
232
233 width = dinfo.output_width;
234 height = dinfo.output_height;
235 stride = dinfo.output_width * dinfo.output_components * sizeof(*rgb);
236
237 rgb = (uint8_t*)malloc(stride * height);
238 if (rgb == NULL) {
239 goto End;
240 }
241 row_ptr = rgb;
242
243 buffer = (*dinfo.mem->alloc_sarray) ((j_common_ptr) &dinfo,
244 JPOOL_IMAGE, stride, 1);
245 if (buffer == NULL) {
246 goto End;
247 }
248
249 while (dinfo.output_scanline < dinfo.output_height) {
250 if (jpeg_read_scanlines(&dinfo, buffer, 1) != 1) {
251 goto End;
252 }
253 memcpy(row_ptr, buffer[0], stride);
254 row_ptr += stride;
255 }
256
257 jpeg_finish_decompress (&dinfo);
258 jpeg_destroy_decompress (&dinfo);
259
260 // WebP conversion.
261 pic->width = width;
262 pic->height = height;
263 ok = WebPPictureImportRGB(pic, rgb, stride);
264
265 End:
266 if (rgb) {
267 free(rgb);
268 }
269 return ok;
270}
271
272#else
273static int ReadJPEG(FILE* in_file, WebPPicture* const pic) {
274 printf("JPEG support not compiled. Please install the libjpeg development "
275 "package before building.\n");
276 return 0;
277}
278#endif
279
280#ifdef WEBP_HAVE_PNG
281static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700282 (void)dummy; // remove variable-unused warning
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800283 longjmp(png_jmpbuf(png), 1);
284}
285
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700286static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800287 png_structp png;
288 png_infop info;
289 int color_type, bit_depth, interlaced;
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700290 int has_alpha;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800291 int num_passes;
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700292 int p;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800293 int ok = 0;
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700294 png_uint_32 width, height, y;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800295 int stride;
296 uint8_t* rgb = NULL;
297
298 png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
299 if (png == NULL) {
300 goto End;
301 }
302
303 png_set_error_fn(png, 0, error_function, NULL);
304 if (setjmp(png_jmpbuf(png))) {
305 Error:
306 png_destroy_read_struct(&png, NULL, NULL);
307 if (rgb) free(rgb);
308 goto End;
309 }
310
311 info = png_create_info_struct(png);
312 if (info == NULL) goto Error;
313
314 png_init_io(png, in_file);
315 png_read_info(png, info);
316 if (!png_get_IHDR(png, info,
317 &width, &height, &bit_depth, &color_type, &interlaced,
318 NULL, NULL)) goto Error;
319
320 png_set_strip_16(png);
321 png_set_packing(png);
322 if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
323 if (color_type == PNG_COLOR_TYPE_GRAY) {
324 if (bit_depth < 8) {
325 png_set_expand_gray_1_2_4_to_8(png);
326 }
327 png_set_gray_to_rgb(png);
328 }
329 if (png_get_valid(png, info, PNG_INFO_tRNS)) {
330 png_set_tRNS_to_alpha(png);
331 }
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700332 has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800333
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700334 if (!keep_alpha) {
335 png_set_strip_alpha(png);
336 has_alpha = 0;
337 }
338
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800339 num_passes = png_set_interlace_handling(png);
340 png_read_update_info(png, info);
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700341 stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800342 rgb = (uint8_t*)malloc(stride * height);
343 if (rgb == NULL) goto Error;
344 for (p = 0; p < num_passes; ++p) {
345 for (y = 0; y < height; ++y) {
346 png_bytep row = rgb + y * stride;
347 png_read_rows(png, &row, NULL, 1);
348 }
349 }
350 png_read_end(png, info);
351 png_destroy_read_struct(&png, &info, NULL);
352
353 pic->width = width;
354 pic->height = height;
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700355 ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
356 : WebPPictureImportRGB(pic, rgb, stride);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800357 free(rgb);
358
359 End:
360 return ok;
361}
362#else
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700363static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800364 printf("PNG support not compiled. Please install the libpng development "
365 "package before building.\n");
366 return 0;
367}
368#endif
369
370typedef enum {
371 PNG = 0,
372 JPEG,
373 UNSUPPORTED,
374} InputFileFormat;
375
376static InputFileFormat GetImageType(FILE* in_file) {
377 InputFileFormat format = UNSUPPORTED;
378 unsigned int magic;
379 unsigned char buf[4];
380
381 if ((fread(&buf[0], 4, 1, in_file) != 1) ||
382 (fseek(in_file, 0, SEEK_SET) != 0)) {
383 return format;
384 }
385
386 magic = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
387 if (magic == 0x89504E47U) {
388 format = PNG;
389 } else if (magic >= 0xFFD8FF00U && magic <= 0xFFD8FFFFU) {
390 format = JPEG;
391 }
392 return format;
393}
394
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700395static int ReadPicture(const char* const filename, WebPPicture* const pic,
396 int keep_alpha) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800397 int ok = 0;
398 FILE* in_file = fopen(filename, "rb");
399 if (in_file == NULL) {
400 fprintf(stderr, "Error! Cannot open input file '%s'\n", filename);
401 return ok;
402 }
403
404 if (pic->width == 0 || pic->height == 0) {
405 // If no size specified, try to decode it as PNG/JPEG (as appropriate).
406 const InputFileFormat format = GetImageType(in_file);
407 if (format == PNG) {
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700408 ok = ReadPNG(in_file, pic, keep_alpha);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800409 } else if (format == JPEG) {
410 ok = ReadJPEG(in_file, pic);
411 }
412 } else {
413 // If image size is specified, infer it as YUV format.
414 ok = ReadYUV(in_file, pic);
415 }
416 if (!ok) {
417 fprintf(stderr, "Error! Could not process file %s\n", filename);
418 }
419
420 fclose(in_file);
421 return ok;
422}
423
424#endif // !_WIN32
425
426static void AllocExtraInfo(WebPPicture* const pic) {
427 const int mb_w = (pic->width + 15) / 16;
428 const int mb_h = (pic->height + 15) / 16;
429 pic->extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(*pic->extra_info));
430}
431
432static void PrintByteCount(const int bytes[4], int total_size,
433 int* const totals) {
434 int s;
435 int total = 0;
436 for (s = 0; s < 4; ++s) {
437 fprintf(stderr, "| %7d ", bytes[s]);
438 total += bytes[s];
439 if (totals) totals[s] += bytes[s];
440 }
441 fprintf(stderr,"| %7d (%.1f%%)\n", total, 100.f * total / total_size);
442}
443
444static void PrintPercents(const int counts[4], int total) {
445 int s;
446 for (s = 0; s < 4; ++s) {
447 fprintf(stderr, "| %2d%%", 100 * counts[s] / total);
448 }
449 fprintf(stderr,"| %7d\n", total);
450}
451
452static void PrintValues(const int values[4]) {
453 int s;
454 for (s = 0; s < 4; ++s) {
455 fprintf(stderr, "| %7d ", values[s]);
456 }
457 fprintf(stderr,"|\n");
458}
459
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700460static void PrintExtraInfo(const WebPPicture* const pic, int short_output) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800461 const WebPAuxStats* const stats = pic->stats;
462 if (short_output) {
463 fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
464 } else{
465 const int num_i4 = stats->block_count[0];
466 const int num_i16 = stats->block_count[1];
467 const int num_skip = stats->block_count[2];
468 const int total = num_i4 + num_i16;
469 fprintf(stderr,
470 "%7d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n",
471 stats->coded_size,
472 stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3]);
473 if (total > 0) {
474 int totals[4] = { 0, 0, 0, 0 };
475 fprintf(stderr, "block count: intra4: %d\n"
476 " intra16: %d (-> %.2f%%)\n",
477 num_i4, num_i16, 100.f * num_i16 / total);
478 fprintf(stderr, " skipped block: %d (%.2f%%)\n",
479 num_skip, 100.f * num_skip / total);
480 fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
481 " mode-partition: %6d (%.1f%%)\n",
482 stats->header_bytes[0],
483 100.f * stats->header_bytes[0] / stats->coded_size,
484 stats->header_bytes[1],
485 100.f * stats->header_bytes[1] / stats->coded_size);
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700486 if (stats->alpha_data_size) {
487 fprintf(stderr, " transparency: %6d\n",
488 stats->alpha_data_size);
489 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800490 fprintf(stderr, " Residuals bytes "
491 "|segment 1|segment 2|segment 3"
492 "|segment 4| total\n");
493 fprintf(stderr, " intra4-coeffs: ");
494 PrintByteCount(stats->residual_bytes[0], stats->coded_size, totals);
495 fprintf(stderr, " intra16-coeffs: ");
496 PrintByteCount(stats->residual_bytes[1], stats->coded_size, totals);
497 fprintf(stderr, " chroma coeffs: ");
498 PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
499 fprintf(stderr, " macroblocks: ");
500 PrintPercents(stats->segment_size, total);
501 fprintf(stderr, " quantizer: ");
502 PrintValues(stats->segment_quant);
503 fprintf(stderr, " filter level: ");
504 PrintValues(stats->segment_level);
505 fprintf(stderr, "------------------+---------");
506 fprintf(stderr, "+---------+---------+---------+-----------------\n");
507 fprintf(stderr, " segments total: ");
508 PrintByteCount(totals, stats->coded_size, NULL);
509 }
510 }
511 if (pic->extra_info) {
512 const int mb_w = (pic->width + 15) / 16;
513 const int mb_h = (pic->height + 15) / 16;
514 const int type = pic->extra_info_type;
515 int x, y;
516 for (y = 0; y < mb_h; ++y) {
517 for (x = 0; x < mb_w; ++x) {
518 const int c = pic->extra_info[x + y * mb_w];
519 if (type == 1) { // intra4/intra16
520 printf("%c", "+."[c]);
521 } else if (type == 2) { // segments
522 printf("%c", ".-*X"[c]);
523 } else if (type == 3) { // quantizers
524 printf("%.2d ", c);
525 } else if (type == 6 || type == 7) {
526 printf("%3d ", c);
527 } else {
528 printf("0x%.2x ", c);
529 }
530 }
531 printf("\n");
532 }
533 }
534}
535
536//-----------------------------------------------------------------------------
537
538static int MyWriter(const uint8_t* data, size_t data_size,
539 const WebPPicture* const pic) {
540 FILE* const out = (FILE*)pic->custom_ptr;
541 return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
542}
543
544// Dumps a picture as a PGM file using the IMC4 layout.
545static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
546 int y;
547 const int uv_width = (picture->width + 1) / 2;
548 const int uv_height = (picture->height + 1) / 2;
549 const int stride = (picture->width + 1) & ~1;
550 const int height = picture->height + uv_height;
551 FILE* const f = fopen(PGM_name, "wb");
552 if (!f) return 0;
553 fprintf(f, "P5\n%d %d\n255\n", stride, height);
554 for (y = 0; y < picture->height; ++y) {
555 if (fwrite(picture->y + y * picture->y_stride, picture->width, 1, f) != 1)
556 return 0;
557 if (picture->width & 1) fputc(0, f); // pad
558 }
559 for (y = 0; y < uv_height; ++y) {
560 if (fwrite(picture->u + y * picture->uv_stride, uv_width, 1, f) != 1)
561 return 0;
562 if (fwrite(picture->v + y * picture->uv_stride, uv_width, 1, f) != 1)
563 return 0;
564 }
565 fclose(f);
566 return 1;
567}
568
569//-----------------------------------------------------------------------------
570
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700571static void HelpShort(void) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800572 printf("Usage:\n\n");
573 printf(" cwebp [options] -q quality input.png -o output.webp\n\n");
574 printf("where quality is between 0 (poor) to 100 (very good).\n");
575 printf("Typical value is around 80.\n\n");
576 printf("Try -longhelp for an exhaustive list of advanced options.\n");
577}
578
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700579static void HelpLong(void) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800580 printf("Usage:\n");
581 printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n");
582 printf("If input size (-s) for an image is not specified, "
583 "it is assumed to be a PNG or JPEG file.\n");
584#ifdef _WIN32
585 printf("Windows builds can take as input any of the files handled by WIC\n");
586#endif
587 printf("options:\n");
588 printf(" -h / -help ............ short help\n");
589 printf(" -H / -longhelp ........ long help\n");
590 printf(" -q <float> ............. quality factor (0:small..100:big)\n");
591 printf(" -preset <string> ....... Preset setting, one of:\n");
592 printf(" default, photo, picture,\n");
593 printf(" drawing, icon, text\n");
594 printf(" -preset must come first, as it overwrites other parameters.");
595 printf("\n");
596 printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
597 printf(" -segments <int> ........ number of segments to use (1..4)\n");
598 printf("\n");
599 printf(" -s <int> <int> ......... Input size (width x height) for YUV\n");
600 printf(" -sns <int> ............. Spatial Noise Shaping (0:off, 100:max)\n");
601 printf(" -f <int> ............... filter strength (0=off..100)\n");
602 printf(" -sharpness <int> ....... "
603 "filter sharpness (0:most .. 7:least sharp)\n");
604 printf(" -strong ................ use strong filter instead of simple.\n");
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700605 printf(" -alpha_comp <int> ...... set the transparency-compression\n");
606 printf(" -noalpha ............... discard any transparency information.\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800607 printf(" -pass <int> ............ analysis pass number (1..10)\n");
608 printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
609 printf(" -map <int> ............. print map of extra info.\n");
610 printf(" -d <file.pgm> .......... dump the compressed output (PGM file).\n");
611 printf("\n");
612 printf(" -short ................. condense printed message\n");
613 printf(" -quiet ................. don't print anything.\n");
Pascal Massimino650ffa32011-03-24 16:17:10 -0700614 printf(" -version ............... print version number and exit.\n");
Pascal Massiminocfbf88a2011-04-22 12:14:45 -0700615 printf(" -noasm ................. disable all assembly optimizations.\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800616 printf(" -v ..................... verbose, e.g. print encoding/decoding "
617 "times\n");
618 printf("\n");
619 printf("Experimental Options:\n");
620 printf(" -size <int> ............ Target size (in bytes)\n");
621 printf(" -psnr <float> .......... Target PSNR (in dB. typically: 42)\n");
622 printf(" -af .................... auto-adjust filter strength.\n");
623 printf(" -pre <int> ............. pre-processing filter\n");
624 printf("\n");
625}
626
627//-----------------------------------------------------------------------------
628
629int main(int argc, const char *argv[]) {
630 const char *in_file = NULL, *out_file = NULL, *dump_file = NULL;
631 FILE *out = NULL;
632 int c;
633 int short_output = 0;
634 int quiet = 0;
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700635 int keep_alpha = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800636 int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
637 WebPPicture picture;
638 WebPConfig config;
639 WebPAuxStats stats;
640 Stopwatch stop_watch;
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700641#ifdef WEBP_EXPERIMENTAL_FEATURES
642 keep_alpha = 1;
643#endif
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800644 if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
645 fprintf(stderr, "Error! Version mismatch!\n");
646 goto Error;
647 }
648
649 if (argc == 1) {
650 HelpShort();
651 return 0;
652 }
653
654 for (c = 1; c < argc; ++c) {
655 if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
656 HelpShort();
657 return 0;
658 } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
659 HelpLong();
660 return 0;
661 } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
662 out_file = argv[++c];
663 } else if (!strcmp(argv[c], "-d") && c < argc - 1) {
664 dump_file = argv[++c];
665 config.show_compressed = 1;
666 } else if (!strcmp(argv[c], "-short")) {
667 short_output++;
668 } else if (!strcmp(argv[c], "-s") && c < argc - 2) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700669 picture.width = strtol(argv[++c], NULL, 0);
670 picture.height = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800671 } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700672 config.method = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800673 } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700674 config.quality = strtod(argv[++c], NULL);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800675 } else if (!strcmp(argv[c], "-size") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700676 config.target_size = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800677 } else if (!strcmp(argv[c], "-psnr") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700678 config.target_PSNR = strtod(argv[++c], NULL);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800679 } else if (!strcmp(argv[c], "-sns") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700680 config.sns_strength = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800681 } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700682 config.filter_strength = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800683 } else if (!strcmp(argv[c], "-af")) {
684 config.autofilter = 1;
685 } else if (!strcmp(argv[c], "-strong") && c < argc - 1) {
686 config.filter_type = 1;
687 } else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700688 config.filter_sharpness = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800689 } else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700690 config.pass = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800691 } else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700692 config.preprocessing = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800693 } else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700694 config.segments = strtol(argv[++c], NULL, 0);
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700695 } else if (!strcmp(argv[c], "-alpha_comp") && c < argc - 1) {
696 config.alpha_compression = strtol(argv[++c], NULL, 0);
697 } else if (!strcmp(argv[c], "-noalpha")) {
698 keep_alpha = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800699 } else if (!strcmp(argv[c], "-map") && c < argc - 1) {
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700700 picture.extra_info_type = strtol(argv[++c], NULL, 0);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800701 } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
702 crop = 1;
Pascal Massimino4b0b0d62011-03-26 09:27:45 -0700703 crop_x = strtol(argv[++c], NULL, 0);
704 crop_y = strtol(argv[++c], NULL, 0);
705 crop_w = strtol(argv[++c], NULL, 0);
706 crop_h = strtol(argv[++c], NULL, 0);
Pascal Massiminocfbf88a2011-04-22 12:14:45 -0700707 } else if (!strcmp(argv[c], "-noasm")) {
708 VP8GetCPUInfo = NULL;
Pascal Massimino650ffa32011-03-24 16:17:10 -0700709 } else if (!strcmp(argv[c], "-version")) {
710 const int version = WebPGetEncoderVersion();
711 printf("%d.%d.%d\n",
712 (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
713 return 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800714 } else if (!strcmp(argv[c], "-quiet")) {
715 quiet = 1;
716 } else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
717 WebPPreset preset;
718 ++c;
719 if (!strcmp(argv[c], "default")) {
720 preset = WEBP_PRESET_DEFAULT;
721 } else if (!strcmp(argv[c], "photo")) {
722 preset = WEBP_PRESET_PHOTO;
723 } else if (!strcmp(argv[c], "picture")) {
724 preset = WEBP_PRESET_PICTURE;
725 } else if (!strcmp(argv[c], "drawing")) {
726 preset = WEBP_PRESET_DRAWING;
727 } else if (!strcmp(argv[c], "icon")) {
728 preset = WEBP_PRESET_ICON;
729 } else if (!strcmp(argv[c], "text")) {
730 preset = WEBP_PRESET_TEXT;
731 } else {
732 fprintf(stderr, "Error! Unrecognized preset: %s\n", argv[c]);
733 goto Error;
734 }
735 if (!WebPConfigPreset(&config, preset, config.quality)) {
Pascal Massimino6d978a62011-03-17 14:49:19 -0700736 fprintf(stderr, "Error! Could initialize configuration with preset.\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800737 goto Error;
738 }
739 } else if (!strcmp(argv[c], "-v")) {
740 verbose = 1;
741 } else if (argv[c][0] == '-') {
742 fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
743 HelpLong();
744 return -1;
745 } else {
746 in_file = argv[c];
747 }
748 }
749
750 if (!WebPValidateConfig(&config)) {
751 fprintf(stderr, "Error! Invalid configuration.\n");
752 goto Error;
753 }
754
Pascal Massimino0744e842011-02-25 12:03:27 -0800755 // Read the input
756 if (verbose)
757 StopwatchReadAndReset(&stop_watch);
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700758 if (!ReadPicture(in_file, &picture, keep_alpha)) {
Pascal Massimino6d978a62011-03-17 14:49:19 -0700759 fprintf(stderr, "Error! Cannot read input picture\n");
760 goto Error;
761 }
Pascal Massimino0744e842011-02-25 12:03:27 -0800762 if (verbose) {
763 const double time = StopwatchReadAndReset(&stop_watch);
764 fprintf(stderr, "Time to read input: %.3fs\n", time);
765 }
766
767 // Open the output
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800768 if (out_file) {
769 out = fopen(out_file, "wb");
770 if (!out) {
771 fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
772 goto Error;
773 } else {
774 if (!short_output && !quiet) {
775 fprintf(stderr, "Saving file '%s'\n", out_file);
776 }
777 }
778 picture.writer = MyWriter;
779 picture.custom_ptr = (void*)out;
780 } else {
781 out = NULL;
782 if (!quiet && !short_output) {
783 fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
784 fprintf(stderr, "be performed, but its results discarded.\n\n");
785 }
786 }
787 picture.stats = &stats;
788
Pascal Massimino0744e842011-02-25 12:03:27 -0800789 // Compress
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800790 if (verbose)
791 StopwatchReadAndReset(&stop_watch);
Pascal Massimino6d978a62011-03-17 14:49:19 -0700792 if (crop != 0 && !WebPPictureCrop(&picture, crop_x, crop_y, crop_w, crop_h)) {
793 fprintf(stderr, "Error! Cannot crop picture\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800794 goto Error;
Pascal Massimino6d978a62011-03-17 14:49:19 -0700795 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800796 if (picture.extra_info_type > 0) AllocExtraInfo(&picture);
Pascal Massimino6d978a62011-03-17 14:49:19 -0700797 if (!WebPEncode(&config, &picture)) {
798 fprintf(stderr, "Error! Cannot encode picture as WebP\n");
799 goto Error;
800 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800801 if (verbose) {
802 const double time = StopwatchReadAndReset(&stop_watch);
803 fprintf(stderr, "Time to encode picture: %.3fs\n", time);
804 }
Pascal Massimino0744e842011-02-25 12:03:27 -0800805
806 // Write info
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800807 if (dump_file) DumpPicture(&picture, dump_file);
808 if (!quiet) PrintExtraInfo(&picture, short_output);
809
810 Error:
811 free(picture.extra_info);
812 WebPPictureFree(&picture);
813 if (out != NULL) {
814 fclose(out);
815 }
816
817 return 0;
818}
819
820//-----------------------------------------------------------------------------