blob: df45aa9b6d1b835d8bb0a8c45fd3613aceddb9ab [file] [log] [blame]
James Zernad1e1632012-01-06 14:49:06 -08001// Copyright 2011 Google Inc. All Rights Reserved.
Pascal Massiminof61d14a2011-02-18 23:33:46 -08002//
James Zernd6406142013-06-06 23:05:58 -07003// Use of this source code is governed by a BSD-style license
4// that can be found in the COPYING file in the root of the source
5// tree. An additional intellectual property rights grant can be found
6// in the file PATENTS. All contributing project authors may
7// be found in the AUTHORS file in the root of the source tree.
Pascal Massiminof61d14a2011-02-18 23:33:46 -08008// -----------------------------------------------------------------------------
9//
10// simple command line calling the WebPEncode function.
11// Encodes a raw .YUV into WebP bitstream
12//
13// Author: Skal (pascal.massimino@gmail.com)
14
15#include <stdio.h>
Pascal Massimino4b0b0d62011-03-26 09:27:45 -070016#include <stdlib.h>
Pascal Massiminof61d14a2011-02-18 23:33:46 -080017#include <string.h>
18
James Zern31f9dc62011-06-06 17:56:50 -070019#ifdef HAVE_CONFIG_H
James Zern32b31372014-06-10 17:53:44 -070020#include "webp/config.h"
James Zern31f9dc62011-06-06 17:56:50 -070021#endif
22
James Zerne9bfb112014-08-29 19:11:41 -070023#include "./example_util.h"
Pascal Massiminoae2a7222016-05-30 21:45:38 -070024#include "./image_dec.h"
James Zern00b29e22012-05-15 13:48:11 -070025#include "./stopwatch.h"
Pascal Massiminoae2a7222016-05-30 21:45:38 -070026#include "webp/encode.h"
skal1bd287a2012-12-11 11:02:39 +010027
James Zernb4d0ef82011-07-15 14:53:03 -070028#ifndef WEBP_DLL
James Zern605a7122013-11-25 14:43:12 -080029#ifdef __cplusplus
James Zern04e84cf2011-11-04 15:20:08 -070030extern "C" {
James Zernb4d0ef82011-07-15 14:53:03 -070031#endif
Pascal Massiminocfbf88a2011-04-22 12:14:45 -070032
James Zern04e84cf2011-11-04 15:20:08 -070033extern void* VP8GetCPUInfo; // opaque forward declaration.
34
James Zern605a7122013-11-25 14:43:12 -080035#ifdef __cplusplus
James Zern04e84cf2011-11-04 15:20:08 -070036} // extern "C"
37#endif
38#endif // WEBP_DLL
39
James Zernc7e86ab2011-08-25 14:22:32 -070040//------------------------------------------------------------------------------
Pascal Massiminof61d14a2011-02-18 23:33:46 -080041
42static int verbose = 0;
43
Pascal Massiminoa9947c32015-12-08 08:22:41 +010044static int ReadYUV(const uint8_t* const data, size_t data_size,
45 WebPPicture* const pic) {
Pascal Massiminodd108172012-07-18 21:58:53 +000046 const int use_argb = pic->use_argb;
Pascal Massiminof61d14a2011-02-18 23:33:46 -080047 const int uv_width = (pic->width + 1) / 2;
48 const int uv_height = (pic->height + 1) / 2;
Pascal Massiminoab8d6692016-05-24 22:54:57 -070049 const int y_plane_size = pic->width * pic->height;
Pascal Massimino1c1702d2015-11-12 23:05:02 +000050 const int uv_plane_size = uv_width * uv_height;
Pascal Massiminoab8d6692016-05-24 22:54:57 -070051 const size_t expected_data_size = y_plane_size + 2 * uv_plane_size;
Pascal Massimino1c1702d2015-11-12 23:05:02 +000052
53 if (data_size != expected_data_size) {
54 fprintf(stderr,
Pascal Massiminoa9947c32015-12-08 08:22:41 +010055 "input data doesn't have the expected size (%d instead of %d)\n",
56 (int)data_size, (int)expected_data_size);
57 return 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -080058 }
Pascal Massimino1c1702d2015-11-12 23:05:02 +000059
Pascal Massiminoa9947c32015-12-08 08:22:41 +010060 pic->use_argb = 0;
61 if (!WebPPictureAlloc(pic)) return 0;
Pascal Massiminoab8d6692016-05-24 22:54:57 -070062 ExUtilCopyPlane(data, pic->width, pic->y, pic->y_stride,
63 pic->width, pic->height);
64 ExUtilCopyPlane(data + y_plane_size, uv_width,
65 pic->u, pic->uv_stride, uv_width, uv_height);
66 ExUtilCopyPlane(data + y_plane_size + uv_plane_size, uv_width,
67 pic->v, pic->uv_stride, uv_width, uv_height);
Pascal Massiminoa9947c32015-12-08 08:22:41 +010068 return use_argb ? WebPPictureYUVAToARGB(pic) : 1;
Pascal Massiminof61d14a2011-02-18 23:33:46 -080069}
70
James Zern31f9dc62011-06-06 17:56:50 -070071#ifdef HAVE_WINCODEC_H
Pascal Massiminof61d14a2011-02-18 23:33:46 -080072
Pascal Massimino2ab4b722011-04-25 16:58:04 -070073static int ReadPicture(const char* const filename, WebPPicture* const pic,
James Zern63aba3a2012-12-03 18:20:00 -080074 int keep_alpha, Metadata* const metadata) {
Pascal Massiminoa9947c32015-12-08 08:22:41 +010075 int ok = 0;
76 const uint8_t* data = NULL;
77 size_t data_size = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -080078 if (pic->width != 0 && pic->height != 0) {
Pascal Massiminoa9947c32015-12-08 08:22:41 +010079 ok = ExUtilReadFile(filename, &data, &data_size);
80 ok = ok && ReadYUV(data, data_size, pic);
Pascal Massiminof61d14a2011-02-18 23:33:46 -080081 } else {
82 // If no size specified, try to decode it using WIC.
James Zerne83ff7d2013-01-24 15:37:49 -080083 ok = ReadPictureWithWIC(filename, pic, keep_alpha, metadata);
James Zern7d039fc2014-05-24 18:30:33 -070084 if (!ok) {
Pascal Massiminoa9947c32015-12-08 08:22:41 +010085 ok = ExUtilReadFile(filename, &data, &data_size);
86 ok = ok && ReadWebP(data, data_size, pic, keep_alpha, metadata);
James Zern7d039fc2014-05-24 18:30:33 -070087 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -080088 }
89 if (!ok) {
90 fprintf(stderr, "Error! Could not process file %s\n", filename);
91 }
Pascal Massiminoa9947c32015-12-08 08:22:41 +010092 free((void*)data);
Pascal Massiminof61d14a2011-02-18 23:33:46 -080093 return ok;
94}
95
James Zern31f9dc62011-06-06 17:56:50 -070096#else // !HAVE_WINCODEC_H
Pascal Massiminof61d14a2011-02-18 23:33:46 -080097
Pascal Massimino2ab4b722011-04-25 16:58:04 -070098static int ReadPicture(const char* const filename, WebPPicture* const pic,
James Zern63aba3a2012-12-03 18:20:00 -080099 int keep_alpha, Metadata* const metadata) {
Pascal Massiminoa9947c32015-12-08 08:22:41 +0100100 const uint8_t* data = NULL;
101 size_t data_size = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800102 int ok = 0;
Pascal Massiminoa9947c32015-12-08 08:22:41 +0100103
104 ok = ExUtilReadFile(filename, &data, &data_size);
105 if (!ok) goto End;
106
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800107 if (pic->width == 0 || pic->height == 0) {
Pascal Massiminod77b8772016-06-01 20:55:29 +0200108 WebPImageReader reader = WebPGuessImageReader(data, data_size);
109 ok = (reader != NULL) && reader(data, data_size, pic, keep_alpha, metadata);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800110 } else {
111 // If image size is specified, infer it as YUV format.
Pascal Massiminoa9947c32015-12-08 08:22:41 +0100112 ok = ReadYUV(data, data_size, pic);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800113 }
Pascal Massiminoa9947c32015-12-08 08:22:41 +0100114 End:
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800115 if (!ok) {
116 fprintf(stderr, "Error! Could not process file %s\n", filename);
117 }
Pascal Massiminoa9947c32015-12-08 08:22:41 +0100118 free((void*)data);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800119 return ok;
120}
121
James Zern31f9dc62011-06-06 17:56:50 -0700122#endif // !HAVE_WINCODEC_H
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800123
124static void AllocExtraInfo(WebPPicture* const pic) {
125 const int mb_w = (pic->width + 15) / 16;
126 const int mb_h = (pic->height + 15) / 16;
127 pic->extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(*pic->extra_info));
128}
129
130static void PrintByteCount(const int bytes[4], int total_size,
131 int* const totals) {
132 int s;
133 int total = 0;
134 for (s = 0; s < 4; ++s) {
135 fprintf(stderr, "| %7d ", bytes[s]);
136 total += bytes[s];
137 if (totals) totals[s] += bytes[s];
138 }
James Zern04e84cf2011-11-04 15:20:08 -0700139 fprintf(stderr, "| %7d (%.1f%%)\n", total, 100.f * total / total_size);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800140}
141
142static void PrintPercents(const int counts[4], int total) {
143 int s;
144 for (s = 0; s < 4; ++s) {
145 fprintf(stderr, "| %2d%%", 100 * counts[s] / total);
146 }
James Zern04e84cf2011-11-04 15:20:08 -0700147 fprintf(stderr, "| %7d\n", total);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800148}
149
150static void PrintValues(const int values[4]) {
151 int s;
152 for (s = 0; s < 4; ++s) {
153 fprintf(stderr, "| %7d ", values[s]);
154 }
James Zern04e84cf2011-11-04 15:20:08 -0700155 fprintf(stderr, "|\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800156}
157
Pascal Massimino7d853d72012-07-24 16:15:36 -0700158static void PrintFullLosslessInfo(const WebPAuxStats* const stats,
159 const char* const description) {
160 fprintf(stderr, "Lossless-%s compressed size: %d bytes\n",
161 description, stats->lossless_size);
Vikas Arorab9014162014-09-17 14:11:52 -0700162 fprintf(stderr, " * Header size: %d bytes, image data size: %d\n",
163 stats->lossless_hdr_size, stats->lossless_data_size);
Pascal Massimino7d853d72012-07-24 16:15:36 -0700164 if (stats->lossless_features) {
165 fprintf(stderr, " * Lossless features used:");
166 if (stats->lossless_features & 1) fprintf(stderr, " PREDICTION");
167 if (stats->lossless_features & 2) fprintf(stderr, " CROSS-COLOR-TRANSFORM");
168 if (stats->lossless_features & 4) fprintf(stderr, " SUBTRACT-GREEN");
169 if (stats->lossless_features & 8) fprintf(stderr, " PALETTE");
170 fprintf(stderr, "\n");
171 }
172 fprintf(stderr, " * Precision Bits: histogram=%d transform=%d cache=%d\n",
173 stats->histogram_bits, stats->transform_bits, stats->cache_bits);
174 if (stats->palette_size > 0) {
175 fprintf(stderr, " * Palette size: %d\n", stats->palette_size);
176 }
177}
178
Vikas Arorac4ccab62012-05-09 11:27:46 +0530179static void PrintExtraInfoLossless(const WebPPicture* const pic,
180 int short_output,
181 const char* const file_name) {
182 const WebPAuxStats* const stats = pic->stats;
183 if (short_output) {
184 fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
185 } else {
186 fprintf(stderr, "File: %s\n", file_name);
187 fprintf(stderr, "Dimension: %d x %d\n", pic->width, pic->height);
188 fprintf(stderr, "Output: %d bytes\n", stats->coded_size);
Pascal Massimino7d853d72012-07-24 16:15:36 -0700189 PrintFullLosslessInfo(stats, "ARGB");
Vikas Arorac4ccab62012-05-09 11:27:46 +0530190 }
191}
192
193static void PrintExtraInfoLossy(const WebPPicture* const pic, int short_output,
skal9bfbdd12013-03-12 00:37:42 +0100194 int full_details,
Vikas Arorac4ccab62012-05-09 11:27:46 +0530195 const char* const file_name) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800196 const WebPAuxStats* const stats = pic->stats;
197 if (short_output) {
198 fprintf(stderr, "%7d %2.2f\n", stats->coded_size, stats->PSNR[3]);
James Zern04e84cf2011-11-04 15:20:08 -0700199 } else {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800200 const int num_i4 = stats->block_count[0];
201 const int num_i16 = stats->block_count[1];
202 const int num_skip = stats->block_count[2];
203 const int total = num_i4 + num_i16;
Pascal Massiminod61479f2012-01-20 07:20:56 -0800204 fprintf(stderr, "File: %s\n", file_name);
205 fprintf(stderr, "Dimension: %d x %d%s\n",
James Zernc71ff9e2012-06-07 17:32:29 -0700206 pic->width, pic->height,
207 stats->alpha_data_size ? " (with alpha)" : "");
Pascal Massiminod61479f2012-01-20 07:20:56 -0800208 fprintf(stderr, "Output: "
209 "%d bytes Y-U-V-All-PSNR %2.2f %2.2f %2.2f %2.2f dB\n",
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800210 stats->coded_size,
211 stats->PSNR[0], stats->PSNR[1], stats->PSNR[2], stats->PSNR[3]);
212 if (total > 0) {
213 int totals[4] = { 0, 0, 0, 0 };
214 fprintf(stderr, "block count: intra4: %d\n"
215 " intra16: %d (-> %.2f%%)\n",
216 num_i4, num_i16, 100.f * num_i16 / total);
217 fprintf(stderr, " skipped block: %d (%.2f%%)\n",
218 num_skip, 100.f * num_skip / total);
219 fprintf(stderr, "bytes used: header: %6d (%.1f%%)\n"
220 " mode-partition: %6d (%.1f%%)\n",
221 stats->header_bytes[0],
222 100.f * stats->header_bytes[0] / stats->coded_size,
223 stats->header_bytes[1],
224 100.f * stats->header_bytes[1] / stats->coded_size);
Pascal Massimino7d853d72012-07-24 16:15:36 -0700225 if (stats->alpha_data_size > 0) {
226 fprintf(stderr, " transparency: %6d (%.1f dB)\n",
227 stats->alpha_data_size, stats->PSNR[4]);
Pascal Massimino2ab4b722011-04-25 16:58:04 -0700228 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800229 fprintf(stderr, " Residuals bytes "
230 "|segment 1|segment 2|segment 3"
231 "|segment 4| total\n");
skal9bfbdd12013-03-12 00:37:42 +0100232 if (full_details) {
233 fprintf(stderr, " intra4-coeffs: ");
234 PrintByteCount(stats->residual_bytes[0], stats->coded_size, totals);
235 fprintf(stderr, " intra16-coeffs: ");
236 PrintByteCount(stats->residual_bytes[1], stats->coded_size, totals);
237 fprintf(stderr, " chroma coeffs: ");
238 PrintByteCount(stats->residual_bytes[2], stats->coded_size, totals);
239 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800240 fprintf(stderr, " macroblocks: ");
241 PrintPercents(stats->segment_size, total);
242 fprintf(stderr, " quantizer: ");
243 PrintValues(stats->segment_quant);
244 fprintf(stderr, " filter level: ");
245 PrintValues(stats->segment_level);
skal9bfbdd12013-03-12 00:37:42 +0100246 if (full_details) {
247 fprintf(stderr, "------------------+---------");
248 fprintf(stderr, "+---------+---------+---------+-----------------\n");
249 fprintf(stderr, " segments total: ");
250 PrintByteCount(totals, stats->coded_size, NULL);
251 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800252 }
Pascal Massimino7d853d72012-07-24 16:15:36 -0700253 if (stats->lossless_size > 0) {
254 PrintFullLosslessInfo(stats, "alpha");
255 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800256 }
skalfff2a112013-12-23 12:03:00 +0100257}
258
259static void PrintMapInfo(const WebPPicture* const pic) {
Pascal Massimino7d853d72012-07-24 16:15:36 -0700260 if (pic->extra_info != NULL) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800261 const int mb_w = (pic->width + 15) / 16;
262 const int mb_h = (pic->height + 15) / 16;
263 const int type = pic->extra_info_type;
264 int x, y;
265 for (y = 0; y < mb_h; ++y) {
266 for (x = 0; x < mb_w; ++x) {
267 const int c = pic->extra_info[x + y * mb_w];
268 if (type == 1) { // intra4/intra16
skale12f8742014-03-12 19:48:00 +0100269 fprintf(stderr, "%c", "+."[c]);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800270 } else if (type == 2) { // segments
skale12f8742014-03-12 19:48:00 +0100271 fprintf(stderr, "%c", ".-*X"[c]);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800272 } else if (type == 3) { // quantizers
skale12f8742014-03-12 19:48:00 +0100273 fprintf(stderr, "%.2d ", c);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800274 } else if (type == 6 || type == 7) {
skale12f8742014-03-12 19:48:00 +0100275 fprintf(stderr, "%3d ", c);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800276 } else {
skale12f8742014-03-12 19:48:00 +0100277 fprintf(stderr, "0x%.2x ", c);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800278 }
279 }
skale12f8742014-03-12 19:48:00 +0100280 fprintf(stderr, "\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800281 }
282 }
283}
284
James Zernc7e86ab2011-08-25 14:22:32 -0700285//------------------------------------------------------------------------------
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800286
287static int MyWriter(const uint8_t* data, size_t data_size,
288 const WebPPicture* const pic) {
289 FILE* const out = (FILE*)pic->custom_ptr;
290 return data_size ? (fwrite(data, data_size, 1, out) == 1) : 1;
291}
292
293// Dumps a picture as a PGM file using the IMC4 layout.
294static int DumpPicture(const WebPPicture* const picture, const char* PGM_name) {
295 int y;
296 const int uv_width = (picture->width + 1) / 2;
297 const int uv_height = (picture->height + 1) / 2;
298 const int stride = (picture->width + 1) & ~1;
Pascal Massimino437999f2012-06-04 15:50:05 -0700299 const int alpha_height =
300 WebPPictureHasTransparency(picture) ? picture->height : 0;
Pascal Massimino5142a0b2011-07-07 16:08:15 -0700301 const int height = picture->height + uv_height + alpha_height;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800302 FILE* const f = fopen(PGM_name, "wb");
Pascal Massiminod61479f2012-01-20 07:20:56 -0800303 if (f == NULL) return 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800304 fprintf(f, "P5\n%d %d\n255\n", stride, height);
305 for (y = 0; y < picture->height; ++y) {
306 if (fwrite(picture->y + y * picture->y_stride, picture->width, 1, f) != 1)
307 return 0;
308 if (picture->width & 1) fputc(0, f); // pad
309 }
310 for (y = 0; y < uv_height; ++y) {
311 if (fwrite(picture->u + y * picture->uv_stride, uv_width, 1, f) != 1)
312 return 0;
313 if (fwrite(picture->v + y * picture->uv_stride, uv_width, 1, f) != 1)
314 return 0;
315 }
Pascal Massimino5142a0b2011-07-07 16:08:15 -0700316 for (y = 0; y < alpha_height; ++y) {
317 if (fwrite(picture->a + y * picture->a_stride, picture->width, 1, f) != 1)
318 return 0;
319 if (picture->width & 1) fputc(0, f); // pad
320 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800321 fclose(f);
322 return 1;
323}
324
James Zern7eaee9f2013-01-11 12:25:36 -0800325// -----------------------------------------------------------------------------
326// Metadata writing.
327
328enum {
329 METADATA_EXIF = (1 << 0),
James Zernd8dc72a2013-03-13 14:04:20 -0700330 METADATA_ICC = (1 << 1),
James Zern7eaee9f2013-01-11 12:25:36 -0800331 METADATA_XMP = (1 << 2),
James Zernd8dc72a2013-03-13 14:04:20 -0700332 METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP
James Zern7eaee9f2013-01-11 12:25:36 -0800333};
334
James Zern76ec5fa2013-01-14 18:32:44 -0800335static const int kChunkHeaderSize = 8;
336static const int kTagSize = 4;
337
James Zern0bc42682013-03-13 14:41:38 -0700338static void PrintMetadataInfo(const Metadata* const metadata,
339 int metadata_written) {
340 if (metadata == NULL || metadata_written == 0) return;
341
342 fprintf(stderr, "Metadata:\n");
James Zern7dd288f2013-03-15 16:42:58 -0700343 if (metadata_written & METADATA_ICC) {
James Zern14d42af2013-03-20 16:59:35 -0700344 fprintf(stderr, " * ICC profile: %6d bytes\n", (int)metadata->iccp.size);
James Zern0bc42682013-03-13 14:41:38 -0700345 }
346 if (metadata_written & METADATA_EXIF) {
James Zern14d42af2013-03-20 16:59:35 -0700347 fprintf(stderr, " * EXIF data: %6d bytes\n", (int)metadata->exif.size);
James Zern0bc42682013-03-13 14:41:38 -0700348 }
349 if (metadata_written & METADATA_XMP) {
James Zern14d42af2013-03-20 16:59:35 -0700350 fprintf(stderr, " * XMP data: %6d bytes\n", (int)metadata->xmp.size);
James Zern0bc42682013-03-13 14:41:38 -0700351 }
352}
353
James Zern76ec5fa2013-01-14 18:32:44 -0800354// Outputs, in little endian, 'num' bytes from 'val' to 'out'.
355static int WriteLE(FILE* const out, uint32_t val, int num) {
356 uint8_t buf[4];
357 int i;
358 for (i = 0; i < num; ++i) {
359 buf[i] = (uint8_t)(val & 0xff);
360 val >>= 8;
361 }
362 return (fwrite(buf, num, 1, out) == 1);
363}
364
365static int WriteLE24(FILE* const out, uint32_t val) {
366 return WriteLE(out, val, 3);
367}
368
369static int WriteLE32(FILE* const out, uint32_t val) {
370 return WriteLE(out, val, 4);
371}
372
373static int WriteMetadataChunk(FILE* const out, const char fourcc[4],
374 const MetadataPayload* const payload) {
375 const uint8_t zero = 0;
376 const size_t need_padding = payload->size & 1;
377 int ok = (fwrite(fourcc, kTagSize, 1, out) == 1);
378 ok = ok && WriteLE32(out, (uint32_t)payload->size);
379 ok = ok && (fwrite(payload->bytes, payload->size, 1, out) == 1);
380 return ok && (fwrite(&zero, need_padding, need_padding, out) == need_padding);
381}
382
383// Sets 'flag' in 'vp8x_flags' and updates 'metadata_size' with the size of the
384// chunk if there is metadata and 'keep' is true.
385static int UpdateFlagsAndSize(const MetadataPayload* const payload,
386 int keep, int flag,
387 uint32_t* vp8x_flags, uint64_t* metadata_size) {
388 if (keep && payload->bytes != NULL && payload->size > 0) {
389 *vp8x_flags |= flag;
390 *metadata_size += kChunkHeaderSize + payload->size + (payload->size & 1);
391 return 1;
392 }
393 return 0;
394}
395
396// Writes a WebP file using the image contained in 'memory_writer' and the
397// metadata from 'metadata'. Metadata is controlled by 'keep_metadata' and the
398// availability in 'metadata'. Returns true on success.
399// For details see doc/webp-container-spec.txt#extended-file-format.
400static int WriteWebPWithMetadata(FILE* const out,
401 const WebPPicture* const picture,
402 const WebPMemoryWriter* const memory_writer,
403 const Metadata* const metadata,
James Zern0bc42682013-03-13 14:41:38 -0700404 int keep_metadata,
405 int* const metadata_written) {
James Zern76ec5fa2013-01-14 18:32:44 -0800406 const char kVP8XHeader[] = "VP8X\x0a\x00\x00\x00";
407 const int kAlphaFlag = 0x10;
408 const int kEXIFFlag = 0x08;
409 const int kICCPFlag = 0x20;
410 const int kXMPFlag = 0x04;
411 const size_t kRiffHeaderSize = 12;
412 const size_t kMaxChunkPayload = ~0 - kChunkHeaderSize - 1;
413 const size_t kMinSize = kRiffHeaderSize + kChunkHeaderSize;
414 uint32_t flags = 0;
415 uint64_t metadata_size = 0;
416 const int write_exif = UpdateFlagsAndSize(&metadata->exif,
417 !!(keep_metadata & METADATA_EXIF),
418 kEXIFFlag, &flags, &metadata_size);
419 const int write_iccp = UpdateFlagsAndSize(&metadata->iccp,
James Zernd8dc72a2013-03-13 14:04:20 -0700420 !!(keep_metadata & METADATA_ICC),
James Zern76ec5fa2013-01-14 18:32:44 -0800421 kICCPFlag, &flags, &metadata_size);
422 const int write_xmp = UpdateFlagsAndSize(&metadata->xmp,
423 !!(keep_metadata & METADATA_XMP),
424 kXMPFlag, &flags, &metadata_size);
425 uint8_t* webp = memory_writer->mem;
426 size_t webp_size = memory_writer->size;
James Zern0bc42682013-03-13 14:41:38 -0700427
428 *metadata_written = 0;
429
James Zern76ec5fa2013-01-14 18:32:44 -0800430 if (webp_size < kMinSize) return 0;
431 if (webp_size - kChunkHeaderSize + metadata_size > kMaxChunkPayload) {
432 fprintf(stderr, "Error! Addition of metadata would exceed "
433 "container size limit.\n");
434 return 0;
435 }
436
437 if (metadata_size > 0) {
438 const int kVP8XChunkSize = 18;
439 const int has_vp8x = !memcmp(webp + kRiffHeaderSize, "VP8X", kTagSize);
440 const uint32_t riff_size = (uint32_t)(webp_size - kChunkHeaderSize +
441 (has_vp8x ? 0 : kVP8XChunkSize) +
442 metadata_size);
443 // RIFF
444 int ok = (fwrite(webp, kTagSize, 1, out) == 1);
445 // RIFF size (file header size is not recorded)
446 ok = ok && WriteLE32(out, riff_size);
447 webp += kChunkHeaderSize;
448 webp_size -= kChunkHeaderSize;
449 // WEBP
450 ok = ok && (fwrite(webp, kTagSize, 1, out) == 1);
451 webp += kTagSize;
452 webp_size -= kTagSize;
453 if (has_vp8x) { // update the existing VP8X flags
454 webp[kChunkHeaderSize] |= (uint8_t)(flags & 0xff);
455 ok = ok && (fwrite(webp, kVP8XChunkSize, 1, out) == 1);
James Zernb5b2e3c2013-12-19 10:17:08 -0800456 webp += kVP8XChunkSize;
James Zern76ec5fa2013-01-14 18:32:44 -0800457 webp_size -= kVP8XChunkSize;
458 } else {
459 const int is_lossless = !memcmp(webp, "VP8L", kTagSize);
Urvang Joshi8ba1bf62013-07-19 11:55:09 -0700460 if (is_lossless) {
461 // Presence of alpha is stored in the 29th bit of VP8L data.
462 if (webp[kChunkHeaderSize + 3] & (1 << 5)) flags |= kAlphaFlag;
463 }
James Zern76ec5fa2013-01-14 18:32:44 -0800464 ok = ok && (fwrite(kVP8XHeader, kChunkHeaderSize, 1, out) == 1);
465 ok = ok && WriteLE32(out, flags);
466 ok = ok && WriteLE24(out, picture->width - 1);
467 ok = ok && WriteLE24(out, picture->height - 1);
468 }
James Zern0bc42682013-03-13 14:41:38 -0700469 if (write_iccp) {
470 ok = ok && WriteMetadataChunk(out, "ICCP", &metadata->iccp);
James Zern7dd288f2013-03-15 16:42:58 -0700471 *metadata_written |= METADATA_ICC;
James Zern0bc42682013-03-13 14:41:38 -0700472 }
James Zern76ec5fa2013-01-14 18:32:44 -0800473 // Image
474 ok = ok && (fwrite(webp, webp_size, 1, out) == 1);
James Zern0bc42682013-03-13 14:41:38 -0700475 if (write_exif) {
476 ok = ok && WriteMetadataChunk(out, "EXIF", &metadata->exif);
477 *metadata_written |= METADATA_EXIF;
478 }
479 if (write_xmp) {
480 ok = ok && WriteMetadataChunk(out, "XMP ", &metadata->xmp);
481 *metadata_written |= METADATA_XMP;
482 }
James Zern76ec5fa2013-01-14 18:32:44 -0800483 return ok;
484 } else {
485 // No metadata, just write the original image file.
486 return (fwrite(webp, webp_size, 1, out) == 1);
487 }
488}
489
James Zernc7e86ab2011-08-25 14:22:32 -0700490//------------------------------------------------------------------------------
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800491
Pascal Massimino30971c92011-12-01 02:24:50 -0800492static int ProgressReport(int percent, const WebPPicture* const picture) {
skale12f8742014-03-12 19:48:00 +0100493 fprintf(stderr, "[%s]: %3d %% \r",
494 (char*)picture->user_data, percent);
Pascal Massimino30971c92011-12-01 02:24:50 -0800495 return 1; // all ok
496}
497
498//------------------------------------------------------------------------------
499
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700500static void HelpShort(void) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800501 printf("Usage:\n\n");
502 printf(" cwebp [options] -q quality input.png -o output.webp\n\n");
503 printf("where quality is between 0 (poor) to 100 (very good).\n");
504 printf("Typical value is around 80.\n\n");
505 printf("Try -longhelp for an exhaustive list of advanced options.\n");
506}
507
Pascal Massiminof8db5d52011-03-25 15:04:11 -0700508static void HelpLong(void) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800509 printf("Usage:\n");
510 printf(" cwebp [-preset <...>] [options] in_file [-o out_file]\n\n");
skal0a8b8862014-06-18 16:45:34 +0200511 printf("If input size (-s) for an image is not specified, it is\n"
512 "assumed to be a PNG, JPEG, TIFF or WebP file.\n");
James Zern31f9dc62011-06-06 17:56:50 -0700513#ifdef HAVE_WINCODEC_H
skal0a8b8862014-06-18 16:45:34 +0200514 printf("Windows builds can take as input any of the files handled by WIC.\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800515#endif
skal0a8b8862014-06-18 16:45:34 +0200516 printf("\nOptions:\n");
James Zernbdf62412016-06-24 19:25:11 -0700517 printf(" -h / -help ............. short help\n");
518 printf(" -H / -longhelp ......... long help\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800519 printf(" -q <float> ............. quality factor (0:small..100:big)\n");
skal0a8b8862014-06-18 16:45:34 +0200520 printf(" -alpha_q <int> ......... transparency-compression quality "
521 "(0..100)\n");
522 printf(" -preset <string> ....... preset setting, one of:\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800523 printf(" default, photo, picture,\n");
524 printf(" drawing, icon, text\n");
skal0a8b8862014-06-18 16:45:34 +0200525 printf(" -preset must come first, as it overwrites other parameters\n");
526 printf(" -z <int> ............... activates lossless preset with given\n"
skal65b99f12014-03-11 23:25:35 +0100527 " level in [0:fast, ..., 9:slowest]\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800528 printf("\n");
529 printf(" -m <int> ............... compression method (0=fast, 6=slowest)\n");
530 printf(" -segments <int> ........ number of segments to use (1..4)\n");
skal0a8b8862014-06-18 16:45:34 +0200531 printf(" -size <int> ............ target size (in bytes)\n");
532 printf(" -psnr <float> .......... target PSNR (in dB. typically: 42)\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800533 printf("\n");
skal0a8b8862014-06-18 16:45:34 +0200534 printf(" -s <int> <int> ......... input size (width x height) for YUV\n");
535 printf(" -sns <int> ............. spatial noise shaping (0:off, 100:max)\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800536 printf(" -f <int> ............... filter strength (0=off..100)\n");
537 printf(" -sharpness <int> ....... "
538 "filter sharpness (0:most .. 7:least sharp)\n");
Pascal Massimino92668da2013-02-15 01:08:52 -0800539 printf(" -strong ................ use strong filter instead "
skal0a8b8862014-06-18 16:45:34 +0200540 "of simple (default)\n");
541 printf(" -nostrong .............. use simple filter instead of strong\n");
Pascal Massimino900286e2011-08-23 15:58:22 -0700542 printf(" -partition_limit <int> . limit quality to fit the 512k limit on\n");
543 printf(" "
544 "the first partition (0=no degradation ... 100=full)\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800545 printf(" -pass <int> ............ analysis pass number (1..10)\n");
546 printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700547 printf(" -resize <w> <h> ........ resize picture (after any cropping)\n");
skalf8179302013-03-01 01:21:34 +0100548 printf(" -mt .................... use multi-threading if available\n");
skal9bfbdd12013-03-12 00:37:42 +0100549 printf(" -low_memory ............ reduce memory usage (slower encoding)\n");
skal0a8b8862014-06-18 16:45:34 +0200550 printf(" -map <int> ............. print map of extra info\n");
551 printf(" -print_psnr ............ prints averaged PSNR distortion\n");
552 printf(" -print_ssim ............ prints averaged SSIM distortion\n");
553 printf(" -print_lsim ............ prints local-similarity distortion\n");
554 printf(" -d <file.pgm> .......... dump the compressed output (PGM file)\n");
555 printf(" -alpha_method <int> .... transparency-compression method (0..1)\n");
556 printf(" -alpha_filter <string> . predictive filtering for alpha plane,\n");
557 printf(" one of: none, fast (default) or best\n");
Lode Vandevenne1f9be972015-11-16 13:14:57 +0000558 printf(" -exact ................. preserve RGB values in transparent area"
559 "\n");
skal0a8b8862014-06-18 16:45:34 +0200560 printf(" -blend_alpha <hex> ..... blend colors against background color\n"
Pascal Massiminoe7d95482013-04-02 19:14:14 -0700561 " expressed as RGB values written in\n"
562 " hexadecimal, e.g. 0xc0e0d0 for red=0xc0\n"
skal0a8b8862014-06-18 16:45:34 +0200563 " green=0xe0 and blue=0xd0\n");
564 printf(" -noalpha ............... discard any transparency information\n");
565 printf(" -lossless .............. encode image losslessly\n");
Vikas Arora98c81382015-01-29 16:02:09 -0800566 printf(" -near_lossless <int> ... use near-lossless image\n"
Vikas Arora4c822842015-02-05 11:16:37 -0800567 " preprocessing (0..100=off)\n");
Mislav Bradac48f66b62015-09-11 12:29:07 +0000568#ifdef WEBP_EXPERIMENTAL_FEATURES
569 printf(" -delta_palettization ... use delta palettization\n");
570#endif // WEBP_EXPERIMENTAL_FEATURES
skal0a8b8862014-06-18 16:45:34 +0200571 printf(" -hint <string> ......... specify image characteristics hint,\n");
572 printf(" one of: photo, picture or graph\n");
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700573
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800574 printf("\n");
James Zern7eaee9f2013-01-11 12:25:36 -0800575 printf(" -metadata <string> ..... comma separated list of metadata to\n");
576 printf(" ");
577 printf("copy from the input to the output if present.\n");
578 printf(" "
James Zernd8dc72a2013-03-13 14:04:20 -0700579 "Valid values: all, none (default), exif, icc, xmp\n");
James Zern7eaee9f2013-01-11 12:25:36 -0800580
581 printf("\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800582 printf(" -short ................. condense printed message\n");
skal0a8b8862014-06-18 16:45:34 +0200583 printf(" -quiet ................. don't print anything\n");
584 printf(" -version ............... print version number and exit\n");
James Zernb4d0ef82011-07-15 14:53:03 -0700585#ifndef WEBP_DLL
skal0a8b8862014-06-18 16:45:34 +0200586 printf(" -noasm ................. disable all assembly optimizations\n");
James Zernb4d0ef82011-07-15 14:53:03 -0700587#endif
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800588 printf(" -v ..................... verbose, e.g. print encoding/decoding "
589 "times\n");
Pascal Massimino30971c92011-12-01 02:24:50 -0800590 printf(" -progress .............. report encoding progress\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800591 printf("\n");
592 printf("Experimental Options:\n");
skal0a8b8862014-06-18 16:45:34 +0200593 printf(" -jpeg_like ............. roughly match expected JPEG size\n");
594 printf(" -af .................... auto-adjust filter strength\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800595 printf(" -pre <int> ............. pre-processing filter\n");
596 printf("\n");
597}
598
James Zernc7e86ab2011-08-25 14:22:32 -0700599//------------------------------------------------------------------------------
Pascal Massiminoca7a2fd2011-06-02 06:55:03 -0700600// Error messages
601
skal0b747b12014-07-21 15:44:43 +0200602static const char* const kErrorMessages[VP8_ENC_ERROR_LAST] = {
Pascal Massiminoca7a2fd2011-06-02 06:55:03 -0700603 "OK",
604 "OUT_OF_MEMORY: Out of memory allocating objects",
605 "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer",
606 "NULL_PARAMETER: NULL parameter passed to function",
607 "INVALID_CONFIGURATION: configuration is invalid",
Pascal Massimino900286e2011-08-23 15:58:22 -0700608 "BAD_DIMENSION: Bad picture dimension. Maximum width and height "
609 "allowed is 16383 pixels.",
610 "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n"
611 "To reduce the size of this partition, try using less segments "
612 "with the -segments option, and eventually reduce the number of "
613 "header bits using -partition_limit. More details are available "
614 "in the manual (`man cwebp`)",
615 "PARTITION_OVERFLOW: Partition is too big to fit 16M",
Pascal Massiminod71fbdc2011-12-01 03:34:22 -0800616 "BAD_WRITE: Picture writer returned an I/O error",
Pascal Massimino30971c92011-12-01 02:24:50 -0800617 "FILE_TOO_BIG: File would be too big to fit in 4G",
618 "USER_ABORT: encoding abort requested by user"
Pascal Massiminoca7a2fd2011-06-02 06:55:03 -0700619};
620
James Zernc7e86ab2011-08-25 14:22:32 -0700621//------------------------------------------------------------------------------
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800622
623int main(int argc, const char *argv[]) {
Pascal Massimino4abe04a2012-05-09 00:32:20 -0700624 int return_value = -1;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800625 const char *in_file = NULL, *out_file = NULL, *dump_file = NULL;
626 FILE *out = NULL;
627 int c;
628 int short_output = 0;
629 int quiet = 0;
Vikas Aroraa0ec9aa2011-12-01 15:11:34 +0530630 int keep_alpha = 1;
Pascal Massiminoe7d95482013-04-02 19:14:14 -0700631 int blend_alpha = 0;
632 uint32_t background_color = 0xffffffu;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800633 int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700634 int resize_w = 0, resize_h = 0;
skal65b99f12014-03-11 23:25:35 +0100635 int lossless_preset = 6;
636 int use_lossless_preset = -1; // -1=unset, 0=don't use, 1=use it
Pascal Massimino30971c92011-12-01 02:24:50 -0800637 int show_progress = 0;
James Zern7eaee9f2013-01-11 12:25:36 -0800638 int keep_metadata = 0;
James Zern0bc42682013-03-13 14:41:38 -0700639 int metadata_written = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800640 WebPPicture picture;
Pascal Massiminof86e6ab2012-10-18 08:26:40 -0700641 int print_distortion = -1; // -1=off, 0=PSNR, 1=SSIM, 2=LSIM
Pascal Massiminod61479f2012-01-20 07:20:56 -0800642 WebPPicture original_picture; // when PSNR or SSIM is requested
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800643 WebPConfig config;
644 WebPAuxStats stats;
James Zern76ec5fa2013-01-14 18:32:44 -0800645 WebPMemoryWriter memory_writer;
James Zern63aba3a2012-12-03 18:20:00 -0800646 Metadata metadata;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800647 Stopwatch stop_watch;
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700648
James Zern63aba3a2012-12-03 18:20:00 -0800649 MetadataInit(&metadata);
James Zern88d382a2013-02-01 19:17:26 -0800650 WebPMemoryWriterInit(&memory_writer);
Pascal Massiminod61479f2012-01-20 07:20:56 -0800651 if (!WebPPictureInit(&picture) ||
652 !WebPPictureInit(&original_picture) ||
653 !WebPConfigInit(&config)) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800654 fprintf(stderr, "Error! Version mismatch!\n");
James Zern256afef2012-07-27 18:56:55 -0700655 return -1;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800656 }
657
658 if (argc == 1) {
659 HelpShort();
660 return 0;
661 }
662
663 for (c = 1; c < argc; ++c) {
James Zern96d43a82014-09-10 23:35:48 -0700664 int parse_error = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800665 if (!strcmp(argv[c], "-h") || !strcmp(argv[c], "-help")) {
666 HelpShort();
667 return 0;
668 } else if (!strcmp(argv[c], "-H") || !strcmp(argv[c], "-longhelp")) {
669 HelpLong();
670 return 0;
671 } else if (!strcmp(argv[c], "-o") && c < argc - 1) {
672 out_file = argv[++c];
673 } else if (!strcmp(argv[c], "-d") && c < argc - 1) {
674 dump_file = argv[++c];
675 config.show_compressed = 1;
Pascal Massiminod61479f2012-01-20 07:20:56 -0800676 } else if (!strcmp(argv[c], "-print_psnr")) {
677 config.show_compressed = 1;
Pascal Massiminof86e6ab2012-10-18 08:26:40 -0700678 print_distortion = 0;
679 } else if (!strcmp(argv[c], "-print_ssim")) {
680 config.show_compressed = 1;
Pascal Massiminod61479f2012-01-20 07:20:56 -0800681 print_distortion = 1;
Pascal Massiminof86e6ab2012-10-18 08:26:40 -0700682 } else if (!strcmp(argv[c], "-print_lsim")) {
683 config.show_compressed = 1;
684 print_distortion = 2;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800685 } else if (!strcmp(argv[c], "-short")) {
skalfff2a112013-12-23 12:03:00 +0100686 ++short_output;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800687 } else if (!strcmp(argv[c], "-s") && c < argc - 2) {
James Zern96d43a82014-09-10 23:35:48 -0700688 picture.width = ExUtilGetInt(argv[++c], 0, &parse_error);
689 picture.height = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massimino1c1702d2015-11-12 23:05:02 +0000690 if (picture.width > WEBP_MAX_DIMENSION || picture.width < 0 ||
691 picture.height > WEBP_MAX_DIMENSION || picture.height < 0) {
692 fprintf(stderr,
693 "Specified dimension (%d x %d) is out of range.\n",
694 picture.width, picture.height);
695 goto Error;
696 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800697 } else if (!strcmp(argv[c], "-m") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700698 config.method = ExUtilGetInt(argv[++c], 0, &parse_error);
skal65b99f12014-03-11 23:25:35 +0100699 use_lossless_preset = 0; // disable -z option
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800700 } else if (!strcmp(argv[c], "-q") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700701 config.quality = ExUtilGetFloat(argv[++c], &parse_error);
skal65b99f12014-03-11 23:25:35 +0100702 use_lossless_preset = 0; // disable -z option
703 } else if (!strcmp(argv[c], "-z") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700704 lossless_preset = ExUtilGetInt(argv[++c], 0, &parse_error);
skal65b99f12014-03-11 23:25:35 +0100705 if (use_lossless_preset != 0) use_lossless_preset = 1;
Vikas Aroraa0ec9aa2011-12-01 15:11:34 +0530706 } else if (!strcmp(argv[c], "-alpha_q") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700707 config.alpha_quality = ExUtilGetInt(argv[++c], 0, &parse_error);
Vikas Aroraa0ec9aa2011-12-01 15:11:34 +0530708 } else if (!strcmp(argv[c], "-alpha_method") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700709 config.alpha_compression = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massimino2e3e8b22012-01-17 08:18:22 +0000710 } else if (!strcmp(argv[c], "-alpha_cleanup")) {
Lode Vandevenne1f9be972015-11-16 13:14:57 +0000711 // This flag is obsolete, does opposite of -exact.
712 config.exact = 0;
713 } else if (!strcmp(argv[c], "-exact")) {
714 config.exact = 1;
Pascal Massiminoe7d95482013-04-02 19:14:14 -0700715 } else if (!strcmp(argv[c], "-blend_alpha") && c < argc - 1) {
716 blend_alpha = 1;
James Zern96d43a82014-09-10 23:35:48 -0700717 // background color is given in hex with an optional '0x' prefix
718 background_color = ExUtilGetInt(argv[++c], 16, &parse_error);
Pascal Massiminoe7d95482013-04-02 19:14:14 -0700719 background_color = background_color & 0x00ffffffu;
Vikas Arora252028a2012-01-05 13:04:30 +0530720 } else if (!strcmp(argv[c], "-alpha_filter") && c < argc - 1) {
Pascal Massimino8ca20762012-01-08 19:27:21 -0800721 ++c;
722 if (!strcmp(argv[c], "none")) {
723 config.alpha_filtering = 0;
724 } else if (!strcmp(argv[c], "fast")) {
725 config.alpha_filtering = 1;
726 } else if (!strcmp(argv[c], "best")) {
727 config.alpha_filtering = 2;
728 } else {
729 fprintf(stderr, "Error! Unrecognized alpha filter: %s\n", argv[c]);
730 goto Error;
731 }
Vikas Aroraa0ec9aa2011-12-01 15:11:34 +0530732 } else if (!strcmp(argv[c], "-noalpha")) {
733 keep_alpha = 0;
Pascal Massimino72920ca2012-04-24 10:59:08 +0000734 } else if (!strcmp(argv[c], "-lossless")) {
735 config.lossless = 1;
skalb5a36cc2014-08-05 19:14:57 +0200736 } else if (!strcmp(argv[c], "-near_lossless") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700737 config.near_lossless = ExUtilGetInt(argv[++c], 0, &parse_error);
skalb5a36cc2014-08-05 19:14:57 +0200738 config.lossless = 1; // use near-lossless only with lossless
Mislav Bradac48f66b62015-09-11 12:29:07 +0000739#ifdef WEBP_EXPERIMENTAL_FEATURES
740 } else if (!strcmp(argv[c], "-delta_palettization")) {
741 config.delta_palettization = 1;
742 config.lossless = 1; // use delta-palettization only with lossless
743#endif // WEBP_EXPERIMENTAL_FEATURES
Vikas Arorad3730762012-06-22 12:14:48 +0530744 } else if (!strcmp(argv[c], "-hint") && c < argc - 1) {
745 ++c;
746 if (!strcmp(argv[c], "photo")) {
747 config.image_hint = WEBP_HINT_PHOTO;
748 } else if (!strcmp(argv[c], "picture")) {
749 config.image_hint = WEBP_HINT_PICTURE;
Vikas Aroradd1c3872012-07-31 23:07:52 -0700750 } else if (!strcmp(argv[c], "graph")) {
751 config.image_hint = WEBP_HINT_GRAPH;
Vikas Arorad3730762012-06-22 12:14:48 +0530752 } else {
753 fprintf(stderr, "Error! Unrecognized image hint: %s\n", argv[c]);
754 goto Error;
755 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800756 } else if (!strcmp(argv[c], "-size") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700757 config.target_size = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800758 } else if (!strcmp(argv[c], "-psnr") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700759 config.target_PSNR = ExUtilGetFloat(argv[++c], &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800760 } else if (!strcmp(argv[c], "-sns") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700761 config.sns_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800762 } else if (!strcmp(argv[c], "-f") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700763 config.filter_strength = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800764 } else if (!strcmp(argv[c], "-af")) {
765 config.autofilter = 1;
skale8950592013-02-05 19:40:18 +0100766 } else if (!strcmp(argv[c], "-jpeg_like")) {
767 config.emulate_jpeg_size = 1;
skalf8179302013-03-01 01:21:34 +0100768 } else if (!strcmp(argv[c], "-mt")) {
769 ++config.thread_level; // increase thread level
skal9bfbdd12013-03-12 00:37:42 +0100770 } else if (!strcmp(argv[c], "-low_memory")) {
771 config.low_memory = 1;
Pascal Massimino842c0092011-05-05 18:10:08 -0700772 } else if (!strcmp(argv[c], "-strong")) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800773 config.filter_type = 1;
Pascal Massimino92668da2013-02-15 01:08:52 -0800774 } else if (!strcmp(argv[c], "-nostrong")) {
775 config.filter_type = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800776 } else if (!strcmp(argv[c], "-sharpness") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700777 config.filter_sharpness = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800778 } else if (!strcmp(argv[c], "-pass") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700779 config.pass = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800780 } else if (!strcmp(argv[c], "-pre") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700781 config.preprocessing = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800782 } else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700783 config.segments = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massimino900286e2011-08-23 15:58:22 -0700784 } else if (!strcmp(argv[c], "-partition_limit") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700785 config.partition_limit = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800786 } else if (!strcmp(argv[c], "-map") && c < argc - 1) {
James Zern96d43a82014-09-10 23:35:48 -0700787 picture.extra_info_type = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800788 } else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
789 crop = 1;
James Zern96d43a82014-09-10 23:35:48 -0700790 crop_x = ExUtilGetInt(argv[++c], 0, &parse_error);
791 crop_y = ExUtilGetInt(argv[++c], 0, &parse_error);
792 crop_w = ExUtilGetInt(argv[++c], 0, &parse_error);
793 crop_h = ExUtilGetInt(argv[++c], 0, &parse_error);
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700794 } else if (!strcmp(argv[c], "-resize") && c < argc - 2) {
James Zern96d43a82014-09-10 23:35:48 -0700795 resize_w = ExUtilGetInt(argv[++c], 0, &parse_error);
796 resize_h = ExUtilGetInt(argv[++c], 0, &parse_error);
James Zernb4d0ef82011-07-15 14:53:03 -0700797#ifndef WEBP_DLL
Pascal Massiminocfbf88a2011-04-22 12:14:45 -0700798 } else if (!strcmp(argv[c], "-noasm")) {
Pascal Massiminoe06ac082011-09-02 21:30:08 +0000799 VP8GetCPUInfo = NULL;
James Zernb4d0ef82011-07-15 14:53:03 -0700800#endif
Pascal Massimino650ffa32011-03-24 16:17:10 -0700801 } else if (!strcmp(argv[c], "-version")) {
802 const int version = WebPGetEncoderVersion();
803 printf("%d.%d.%d\n",
James Zern64da45a2015-12-11 16:40:23 -0800804 (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff);
Pascal Massimino650ffa32011-03-24 16:17:10 -0700805 return 0;
Pascal Massimino30971c92011-12-01 02:24:50 -0800806 } else if (!strcmp(argv[c], "-progress")) {
807 show_progress = 1;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800808 } else if (!strcmp(argv[c], "-quiet")) {
809 quiet = 1;
810 } else if (!strcmp(argv[c], "-preset") && c < argc - 1) {
811 WebPPreset preset;
812 ++c;
813 if (!strcmp(argv[c], "default")) {
814 preset = WEBP_PRESET_DEFAULT;
815 } else if (!strcmp(argv[c], "photo")) {
816 preset = WEBP_PRESET_PHOTO;
817 } else if (!strcmp(argv[c], "picture")) {
818 preset = WEBP_PRESET_PICTURE;
819 } else if (!strcmp(argv[c], "drawing")) {
820 preset = WEBP_PRESET_DRAWING;
821 } else if (!strcmp(argv[c], "icon")) {
822 preset = WEBP_PRESET_ICON;
823 } else if (!strcmp(argv[c], "text")) {
824 preset = WEBP_PRESET_TEXT;
825 } else {
826 fprintf(stderr, "Error! Unrecognized preset: %s\n", argv[c]);
827 goto Error;
828 }
829 if (!WebPConfigPreset(&config, preset, config.quality)) {
Pascal Massimino6d978a62011-03-17 14:49:19 -0700830 fprintf(stderr, "Error! Could initialize configuration with preset.\n");
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800831 goto Error;
832 }
James Zern7eaee9f2013-01-11 12:25:36 -0800833 } else if (!strcmp(argv[c], "-metadata") && c < argc - 1) {
834 static const struct {
835 const char* option;
836 int flag;
837 } kTokens[] = {
838 { "all", METADATA_ALL },
839 { "none", 0 },
840 { "exif", METADATA_EXIF },
James Zernd8dc72a2013-03-13 14:04:20 -0700841 { "icc", METADATA_ICC },
James Zern7eaee9f2013-01-11 12:25:36 -0800842 { "xmp", METADATA_XMP },
843 };
844 const size_t kNumTokens = sizeof(kTokens) / sizeof(kTokens[0]);
845 const char* start = argv[++c];
846 const char* const end = start + strlen(start);
847
848 while (start < end) {
849 size_t i;
850 const char* token = strchr(start, ',');
851 if (token == NULL) token = end;
852
853 for (i = 0; i < kNumTokens; ++i) {
854 if ((size_t)(token - start) == strlen(kTokens[i].option) &&
855 !strncmp(start, kTokens[i].option, strlen(kTokens[i].option))) {
856 if (kTokens[i].flag != 0) {
857 keep_metadata |= kTokens[i].flag;
858 } else {
859 keep_metadata = 0;
860 }
861 break;
862 }
863 }
864 if (i == kNumTokens) {
865 fprintf(stderr, "Error! Unknown metadata type '%.*s'\n",
866 (int)(token - start), start);
867 HelpLong();
868 return -1;
869 }
870 start = token + 1;
871 }
James Zern76ec5fa2013-01-14 18:32:44 -0800872#ifdef HAVE_WINCODEC_H
James Zernd8dc72a2013-03-13 14:04:20 -0700873 if (keep_metadata != 0 && keep_metadata != METADATA_ICC) {
James Zern7eaee9f2013-01-11 12:25:36 -0800874 // TODO(jzern): remove when -metadata is supported on all platforms.
James Zerne83ff7d2013-01-24 15:37:49 -0800875 fprintf(stderr, "Warning: only ICC profile extraction is currently"
876 " supported on this platform!\n");
James Zern7eaee9f2013-01-11 12:25:36 -0800877 }
James Zern76ec5fa2013-01-14 18:32:44 -0800878#endif
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800879 } else if (!strcmp(argv[c], "-v")) {
880 verbose = 1;
James Zern98af68f2013-12-12 20:20:08 -0800881 } else if (!strcmp(argv[c], "--")) {
882 if (c < argc - 1) in_file = argv[++c];
883 break;
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800884 } else if (argv[c][0] == '-') {
885 fprintf(stderr, "Error! Unknown option '%s'\n", argv[c]);
886 HelpLong();
887 return -1;
888 } else {
889 in_file = argv[c];
890 }
James Zern96d43a82014-09-10 23:35:48 -0700891
892 if (parse_error) {
893 HelpLong();
894 return -1;
895 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800896 }
Pascal Massimino4abe04a2012-05-09 00:32:20 -0700897 if (in_file == NULL) {
898 fprintf(stderr, "No input file specified!\n");
899 HelpShort();
900 goto Error;
901 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800902
skal65b99f12014-03-11 23:25:35 +0100903 if (use_lossless_preset == 1) {
904 if (!WebPConfigLosslessPreset(&config, lossless_preset)) {
905 fprintf(stderr, "Invalid lossless preset (-z %d)\n", lossless_preset);
906 goto Error;
907 }
908 }
909
Vikas Arorab7fb0ed2012-06-20 09:02:25 +0530910 // Check for unsupported command line options for lossless mode and log
911 // warning for such options.
Pascal Massimino02751592012-06-20 09:20:34 +0000912 if (!quiet && config.lossless == 1) {
Vikas Arorab7fb0ed2012-06-20 09:02:25 +0530913 if (config.target_size > 0 || config.target_PSNR > 0) {
914 fprintf(stderr, "Encoding for specified size or PSNR is not supported"
915 " for lossless encoding. Ignoring such option(s)!\n");
916 }
917 if (config.partition_limit > 0) {
918 fprintf(stderr, "Partition limit option is not required for lossless"
919 " encoding. Ignoring this option!\n");
920 }
Vikas Arorab7fb0ed2012-06-20 09:02:25 +0530921 }
Pascal Massimino4ed650a2016-02-13 10:22:32 +0100922 // If a target size or PSNR was given, but somehow the -pass option was
923 // omitted, force a reasonable value.
924 if (config.target_size > 0 || config.target_PSNR > 0) {
925 if (config.pass == 1) config.pass = 6;
926 }
Vikas Arorab7fb0ed2012-06-20 09:02:25 +0530927
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800928 if (!WebPValidateConfig(&config)) {
929 fprintf(stderr, "Error! Invalid configuration.\n");
930 goto Error;
931 }
932
Pascal Massimino78615782015-10-27 22:54:11 +0100933 // Read the input. We need to decide if we prefer ARGB or YUVA
934 // samples, depending on the expected compression mode (this saves
935 // some conversion steps).
936 picture.use_argb = (config.lossless || config.preprocessing > 0 ||
937 crop || (resize_w | resize_h) > 0);
Pascal Massimino38369c02011-05-04 22:59:51 -0700938 if (verbose) {
skald51f45f2013-09-12 09:32:28 +0200939 StopwatchReset(&stop_watch);
Pascal Massimino38369c02011-05-04 22:59:51 -0700940 }
James Zern7eaee9f2013-01-11 12:25:36 -0800941 if (!ReadPicture(in_file, &picture, keep_alpha,
942 (keep_metadata == 0) ? NULL : &metadata)) {
Pascal Massiminod61479f2012-01-20 07:20:56 -0800943 fprintf(stderr, "Error! Cannot read input picture file '%s'\n", in_file);
Pascal Massimino6d978a62011-03-17 14:49:19 -0700944 goto Error;
945 }
Pascal Massimino30971c92011-12-01 02:24:50 -0800946 picture.progress_hook = (show_progress && !quiet) ? ProgressReport : NULL;
Pascal Massiminoe7d95482013-04-02 19:14:14 -0700947
948 if (blend_alpha) {
949 WebPBlendAlpha(&picture, background_color);
950 }
951
Pascal Massimino0744e842011-02-25 12:03:27 -0800952 if (verbose) {
Pascal Massimino126c0352013-01-25 00:44:16 -0800953 const double read_time = StopwatchReadAndReset(&stop_watch);
954 fprintf(stderr, "Time to read input: %.3fs\n", read_time);
Pascal Massimino0744e842011-02-25 12:03:27 -0800955 }
956
957 // Open the output
skale12f8742014-03-12 19:48:00 +0100958 if (out_file != NULL) {
959 const int use_stdout = !strcmp(out_file, "-");
James Zerne9bfb112014-08-29 19:11:41 -0700960 out = use_stdout ? ExUtilSetBinaryMode(stdout) : fopen(out_file, "wb");
Pascal Massiminod61479f2012-01-20 07:20:56 -0800961 if (out == NULL) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800962 fprintf(stderr, "Error! Cannot open output file '%s'\n", out_file);
963 goto Error;
964 } else {
965 if (!short_output && !quiet) {
966 fprintf(stderr, "Saving file '%s'\n", out_file);
967 }
968 }
James Zern76ec5fa2013-01-14 18:32:44 -0800969 if (keep_metadata == 0) {
970 picture.writer = MyWriter;
971 picture.custom_ptr = (void*)out;
972 } else {
James Zern76ec5fa2013-01-14 18:32:44 -0800973 picture.writer = WebPMemoryWrite;
974 picture.custom_ptr = (void*)&memory_writer;
975 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800976 } else {
977 out = NULL;
978 if (!quiet && !short_output) {
979 fprintf(stderr, "No output file specified (no -o flag). Encoding will\n");
980 fprintf(stderr, "be performed, but its results discarded.\n\n");
981 }
982 }
Pascal Massimino7d853d72012-07-24 16:15:36 -0700983 if (!quiet) {
984 picture.stats = &stats;
James Zern475d87d2012-07-27 19:53:16 -0700985 picture.user_data = (void*)in_file;
Pascal Massimino7d853d72012-07-24 16:15:36 -0700986 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -0800987
Vikas Arorae09e9ff2014-07-28 16:04:54 -0700988 // Crop & resize.
Pascal Massimino38369c02011-05-04 22:59:51 -0700989 if (verbose) {
skald51f45f2013-09-12 09:32:28 +0200990 StopwatchReset(&stop_watch);
Pascal Massimino38369c02011-05-04 22:59:51 -0700991 }
Pascal Massimino31b68fe2012-06-21 00:30:43 -0700992 if (crop != 0) {
993 // We use self-cropping using a view.
994 if (!WebPPictureView(&picture, crop_x, crop_y, crop_w, crop_h, &picture)) {
995 fprintf(stderr, "Error! Cannot crop picture\n");
996 goto Error;
997 }
Pascal Massimino6d978a62011-03-17 14:49:19 -0700998 }
Pascal Massimino6d0e66c2011-05-02 17:19:00 -0700999 if ((resize_w | resize_h) > 0) {
1000 if (!WebPPictureRescale(&picture, resize_w, resize_h)) {
1001 fprintf(stderr, "Error! Cannot resize picture\n");
1002 goto Error;
1003 }
1004 }
Vikas Arorae09e9ff2014-07-28 16:04:54 -07001005 if (verbose && (crop != 0 || (resize_w | resize_h) > 0)) {
1006 const double preproc_time = StopwatchReadAndReset(&stop_watch);
1007 fprintf(stderr, "Time to crop/resize picture: %.3fs\n", preproc_time);
1008 }
1009
Pascal Massimino6d0e66c2011-05-02 17:19:00 -07001010 if (picture.extra_info_type > 0) {
1011 AllocExtraInfo(&picture);
1012 }
Pascal Massiminof86e6ab2012-10-18 08:26:40 -07001013 if (print_distortion >= 0) { // Save original picture for later comparison
Pascal Massiminod61479f2012-01-20 07:20:56 -08001014 WebPPictureCopy(&picture, &original_picture);
1015 }
Vikas Arorae09e9ff2014-07-28 16:04:54 -07001016
1017 // Compress.
1018 if (verbose) {
1019 StopwatchReset(&stop_watch);
1020 }
Pascal Massimino6d978a62011-03-17 14:49:19 -07001021 if (!WebPEncode(&config, &picture)) {
1022 fprintf(stderr, "Error! Cannot encode picture as WebP\n");
Pascal Massiminoca7a2fd2011-06-02 06:55:03 -07001023 fprintf(stderr, "Error code: %d (%s)\n",
1024 picture.error_code, kErrorMessages[picture.error_code]);
Pascal Massimino6d978a62011-03-17 14:49:19 -07001025 goto Error;
1026 }
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001027 if (verbose) {
Pascal Massimino126c0352013-01-25 00:44:16 -08001028 const double encode_time = StopwatchReadAndReset(&stop_watch);
1029 fprintf(stderr, "Time to encode picture: %.3fs\n", encode_time);
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001030 }
Pascal Massimino0744e842011-02-25 12:03:27 -08001031
1032 // Write info
Pascal Massimino38369c02011-05-04 22:59:51 -07001033 if (dump_file) {
Pascal Massiminodd108172012-07-18 21:58:53 +00001034 if (picture.use_argb) {
Pascal Massimino437999f2012-06-04 15:50:05 -07001035 fprintf(stderr, "Warning: can't dump file (-d option) in lossless mode.");
1036 } else if (!DumpPicture(&picture, dump_file)) {
1037 fprintf(stderr, "Warning, couldn't dump picture %s\n", dump_file);
1038 }
Pascal Massimino38369c02011-05-04 22:59:51 -07001039 }
Pascal Massiminod61479f2012-01-20 07:20:56 -08001040
James Zern70490432013-12-09 20:15:54 -08001041 if (keep_metadata != 0) {
1042 if (out != NULL) {
1043 if (!WriteWebPWithMetadata(out, &picture, &memory_writer,
1044 &metadata, keep_metadata, &metadata_written)) {
1045 fprintf(stderr, "Error writing WebP file with metadata!\n");
1046 goto Error;
1047 }
1048 } else { // output is disabled, just display the metadata stats.
1049 const struct {
1050 const MetadataPayload* const payload;
1051 int flag;
1052 } *iter, info[] = {
1053 { &metadata.exif, METADATA_EXIF },
1054 { &metadata.iccp, METADATA_ICC },
1055 { &metadata.xmp, METADATA_XMP },
1056 { NULL, 0 }
1057 };
1058 uint32_t unused1 = 0;
1059 uint64_t unused2 = 0;
1060
1061 for (iter = info; iter->payload != NULL; ++iter) {
1062 if (UpdateFlagsAndSize(iter->payload, !!(keep_metadata & iter->flag),
1063 0, &unused1, &unused2)) {
1064 metadata_written |= iter->flag;
1065 }
1066 }
James Zern76ec5fa2013-01-14 18:32:44 -08001067 }
1068 }
1069
Pascal Massimino38369c02011-05-04 22:59:51 -07001070 if (!quiet) {
skalfff2a112013-12-23 12:03:00 +01001071 if (!short_output || print_distortion < 0) {
1072 if (config.lossless) {
1073 PrintExtraInfoLossless(&picture, short_output, in_file);
1074 } else {
1075 PrintExtraInfoLossy(&picture, short_output, config.low_memory, in_file);
1076 }
1077 }
1078 if (!short_output && picture.extra_info_type > 0) {
1079 PrintMapInfo(&picture);
1080 }
1081 if (print_distortion >= 0) { // print distortion
1082 static const char* distortion_names[] = { "PSNR", "SSIM", "LSIM" };
1083 float values[5];
skal56a2e9f2015-08-11 17:28:29 -07001084 if (picture.use_argb != original_picture.use_argb) {
1085 // Somehow, the WebPEncode() call converted the original picture.
1086 // We need to make both match before calling WebPPictureDistortion().
1087 int ok = 0;
1088 if (picture.use_argb) {
1089 ok = WebPPictureYUVAToARGB(&original_picture);
1090 } else {
1091 ok = WebPPictureARGBToYUVA(&original_picture, WEBP_YUV420A);
1092 }
1093 if (!ok) {
1094 fprintf(stderr, "Error while converting original picture.\n");
1095 goto Error;
1096 }
skalfff2a112013-12-23 12:03:00 +01001097 }
1098 if (!WebPPictureDistortion(&picture, &original_picture,
1099 print_distortion, values)) {
1100 fprintf(stderr, "Error while computing the distortion.\n");
1101 goto Error;
1102 }
1103 if (!short_output) {
skal56a2e9f2015-08-11 17:28:29 -07001104 fprintf(stderr, "%s: ", distortion_names[print_distortion]);
1105 if (picture.use_argb) {
1106 fprintf(stderr, "B:%.2f G:%.2f R:%.2f A:%.2f Total:%.2f\n",
1107 values[0], values[1], values[2], values[3], values[4]);
1108 } else {
1109 fprintf(stderr, "Y:%.2f U:%.2f V:%.2f A:%.2f Total:%.2f\n",
1110 values[0], values[1], values[2], values[3], values[4]);
1111 }
skalfff2a112013-12-23 12:03:00 +01001112 } else {
1113 fprintf(stderr, "%7d %.4f\n", picture.stats->coded_size, values[4]);
1114 }
Vikas Arorac4ccab62012-05-09 11:27:46 +05301115 }
James Zern0bc42682013-03-13 14:41:38 -07001116 if (!short_output) {
1117 PrintMetadataInfo(&metadata, metadata_written);
1118 }
Pascal Massiminod61479f2012-01-20 07:20:56 -08001119 }
Pascal Massimino4abe04a2012-05-09 00:32:20 -07001120 return_value = 0;
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001121
1122 Error:
skalaf93bdd2014-03-27 23:27:32 +01001123 WebPMemoryWriterClear(&memory_writer);
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001124 free(picture.extra_info);
James Zern63aba3a2012-12-03 18:20:00 -08001125 MetadataFree(&metadata);
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001126 WebPPictureFree(&picture);
Pascal Massiminod61479f2012-01-20 07:20:56 -08001127 WebPPictureFree(&original_picture);
skale12f8742014-03-12 19:48:00 +01001128 if (out != NULL && out != stdout) {
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001129 fclose(out);
1130 }
1131
Pascal Massimino4abe04a2012-05-09 00:32:20 -07001132 return return_value;
Pascal Massiminof61d14a2011-02-18 23:33:46 -08001133}
1134
James Zernc7e86ab2011-08-25 14:22:32 -07001135//------------------------------------------------------------------------------