blob: 76c9a60b524b4794f74d92b66f98448450c0e501 [file] [log] [blame]
James Zernad1e1632012-01-06 14:49:06 -08001// Copyright 2011 Google Inc. All Rights Reserved.
Urvang Joshia4f32ca2011-09-30 11:07:01 +05302//
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 to create a WebP container file and to extract or strip
9// relevant data from the container file.
10//
James Zern04e84cf2011-11-04 15:20:08 -070011// Compile with: gcc -o webpmux webpmux.c -lwebpmux -lwebp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053012//
13//
14// Authors: Vikas (vikaas.arora@gmail.com),
15// Urvang (urvang@google.com)
16
17/* Usage examples:
18
19 Create container WebP file:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053020 webpmux -tile tile_1.webp +0+0 \
21 -tile tile_2.webp +960+0 \
22 -tile tile_3.webp +0+576 \
23 -tile tile_4.webp +960+576 \
24 -o out_tile_container.webp
25
26 webpmux -frame anim_1.webp +0+0+0 \
27 -frame anim_2.webp +25+25+100 \
28 -frame anim_3.webp +50+50+100 \
29 -frame anim_4.webp +0+0+100 \
30 -loop 10 \
31 -o out_animation_container.webp
32
33 webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053034 webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
35
Urvang Joshia4f32ca2011-09-30 11:07:01 +053036 Extract relevant data from WebP container file:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053037 webpmux -get tile n in.webp -o out_tile.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053038 webpmux -get frame n in.webp -o out_frame.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053039 webpmux -get icc in.webp -o image_profile.icc
Urvang Joshia4f32ca2011-09-30 11:07:01 +053040 webpmux -get xmp in.webp -o image_metadata.xmp
41
Urvang Joshia4f32ca2011-09-30 11:07:01 +053042 Strip data from WebP Container file:
James Zern04e84cf2011-11-04 15:20:08 -070043 webpmux -strip icc in.webp -o out.webp
44 webpmux -strip xmp in.webp -o out.webp
Urvang Joshia4f32ca2011-09-30 11:07:01 +053045
46 Misc:
Urvang Joshia4f32ca2011-09-30 11:07:01 +053047 webpmux -info in.webp
James Zern04e84cf2011-11-04 15:20:08 -070048 webpmux [ -h | -help ]
Urvang Joshia4f32ca2011-09-30 11:07:01 +053049*/
50
51#include <assert.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55#include "webp/mux.h"
James Zern061263a2012-05-11 16:00:57 -070056#include "./example_util.h"
Urvang Joshia4f32ca2011-09-30 11:07:01 +053057
Urvang Joshia4f32ca2011-09-30 11:07:01 +053058//------------------------------------------------------------------------------
59// Config object to parse command-line arguments.
60
61typedef enum {
62 NIL_ACTION = 0,
63 ACTION_GET,
64 ACTION_SET,
65 ACTION_STRIP,
66 ACTION_INFO,
67 ACTION_HELP
68} ActionType;
69
70typedef enum {
71 NIL_SUBTYPE = 0,
72 SUBTYPE_FRM,
73 SUBTYPE_LOOP
74} FeatureSubType;
75
76typedef struct {
77 FeatureSubType subtype_;
78 const char* filename_;
79 const char* params_;
80} FeatureArg;
81
82typedef enum {
83 NIL_FEATURE = 0,
84 FEATURE_XMP,
85 FEATURE_ICCP,
86 FEATURE_FRM,
87 FEATURE_TILE
88} FeatureType;
89
90typedef struct {
91 FeatureType type_;
92 FeatureArg* args_;
93 int arg_count_;
94} Feature;
95
96typedef struct {
97 ActionType action_type_;
98 const char* input_;
99 const char* output_;
100 Feature feature_;
101} WebPMuxConfig;
102
103//------------------------------------------------------------------------------
104// Helper functions.
105
James Zern04e84cf2011-11-04 15:20:08 -0700106static int CountOccurrences(const char* arglist[], int list_length,
107 const char* arg) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530108 int i;
109 int num_occurences = 0;
110
111 for (i = 0; i < list_length; ++i) {
112 if (!strcmp(arglist[i], arg)) {
113 ++num_occurences;
114 }
115 }
116 return num_occurences;
117}
118
119static int IsNotCompatible(int count1, int count2) {
James Zern04e84cf2011-11-04 15:20:08 -0700120 return (count1 > 0) != (count2 > 0);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530121}
122
James Zern0f7820e2012-01-24 14:08:27 -0800123// Allocate necessary storage for dst then copy the contents of src.
124// Returns 1 on success.
125static int WebPDataCopy(const WebPData* const src, WebPData* const dst) {
126 if (src == NULL || dst == NULL) return 0;
127
128 memset(dst, 0, sizeof(*dst));
129 if (src->bytes_ != NULL && src->size_ != 0) {
130 dst->bytes_ = (uint8_t*)malloc(src->size_);
131 if (dst->bytes_ == NULL) return 0;
132 memcpy((void*)dst->bytes_, src->bytes_, src->size_);
133 dst->size_ = src->size_;
134 }
135 return 1;
136}
137
138// Frees data allocated by WebPDataCopy.
139static void WebPDataFree(WebPData* const webpdata) {
140 free((void*)webpdata->bytes_);
141 memset(webpdata, 0, sizeof(*webpdata));
142}
143
James Zerna0b27362012-01-27 17:39:47 -0800144#define RETURN_IF_ERROR(ERR_MSG) \
145 if (err != WEBP_MUX_OK) { \
146 fprintf(stderr, ERR_MSG); \
147 return err; \
148 }
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530149
James Zerna0b27362012-01-27 17:39:47 -0800150#define RETURN_IF_ERROR2(ERR_MSG, FORMAT_STR) \
151 if (err != WEBP_MUX_OK) { \
152 fprintf(stderr, ERR_MSG, FORMAT_STR); \
153 return err; \
154 }
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530155
James Zerna0b27362012-01-27 17:39:47 -0800156#define ERROR_GOTO1(ERR_MSG, LABEL) \
157 do { \
158 fprintf(stderr, ERR_MSG); \
159 ok = 0; \
160 goto LABEL; \
161 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530162
James Zerna0b27362012-01-27 17:39:47 -0800163#define ERROR_GOTO2(ERR_MSG, FORMAT_STR, LABEL) \
164 do { \
165 fprintf(stderr, ERR_MSG, FORMAT_STR); \
166 ok = 0; \
167 goto LABEL; \
168 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530169
James Zerna0b27362012-01-27 17:39:47 -0800170#define ERROR_GOTO3(ERR_MSG, FORMAT_STR1, FORMAT_STR2, LABEL) \
171 do { \
172 fprintf(stderr, ERR_MSG, FORMAT_STR1, FORMAT_STR2); \
173 ok = 0; \
174 goto LABEL; \
175 } while (0)
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530176
177static WebPMuxError DisplayInfo(const WebPMux* mux) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530178 uint32_t flag;
179
180 WebPMuxError err = WebPMuxGetFeatures(mux, &flag);
181 RETURN_IF_ERROR("Failed to retrieve features\n");
182
183 if (flag == 0) {
184 fprintf(stderr, "No features present.\n");
185 return err;
186 }
187
188 // Print the features present.
James Zern974aaff2012-01-24 12:46:46 -0800189 printf("Features present:");
190 if (flag & ANIMATION_FLAG) printf(" animation");
191 if (flag & TILE_FLAG) printf(" tiling");
192 if (flag & ICCP_FLAG) printf(" icc profile");
193 if (flag & META_FLAG) printf(" metadata");
194 if (flag & ALPHA_FLAG) printf(" transparency");
195 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530196
197 if (flag & ANIMATION_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800198 int nFrames;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530199 uint32_t loop_count;
200 err = WebPMuxGetLoopCount(mux, &loop_count);
201 RETURN_IF_ERROR("Failed to retrieve loop count\n");
James Zern974aaff2012-01-24 12:46:46 -0800202 printf("Loop Count : %d\n", loop_count);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530203
204 err = WebPMuxNumNamedElements(mux, "frame", &nFrames);
205 RETURN_IF_ERROR("Failed to retrieve number of frames\n");
206
James Zern974aaff2012-01-24 12:46:46 -0800207 printf("Number of frames: %d\n", nFrames);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530208 if (nFrames > 0) {
209 int i;
James Zern974aaff2012-01-24 12:46:46 -0800210 printf("No.: x_offset y_offset duration image_size");
211 if (flag & ALPHA_FLAG) printf(" alpha_size");
212 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530213 for (i = 1; i <= nFrames; i++) {
James Zern974aaff2012-01-24 12:46:46 -0800214 uint32_t x_offset, y_offset, duration;
James Zerneec4b872012-01-07 12:44:01 -0800215 WebPData image, alpha;
216 err = WebPMuxGetFrame(mux, i, &image, &alpha,
Urvang Joshic398f592011-11-22 14:40:41 +0530217 &x_offset, &y_offset, &duration);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530218 RETURN_IF_ERROR2("Failed to retrieve frame#%d\n", i);
James Zern95667b82012-04-18 17:13:34 -0700219 printf("%3d: %8d %8d %8d %10zu",
James Zern974aaff2012-01-24 12:46:46 -0800220 i, x_offset, y_offset, duration, image.size_);
James Zern95667b82012-04-18 17:13:34 -0700221 if (flag & ALPHA_FLAG) printf(" %10zu", alpha.size_);
James Zern974aaff2012-01-24 12:46:46 -0800222 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530223 }
224 }
225 }
226
227 if (flag & TILE_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800228 int nTiles;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530229 err = WebPMuxNumNamedElements(mux, "tile", &nTiles);
230 RETURN_IF_ERROR("Failed to retrieve number of tiles\n");
231
James Zern974aaff2012-01-24 12:46:46 -0800232 printf("Number of tiles: %d\n", nTiles);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530233 if (nTiles > 0) {
234 int i;
James Zern974aaff2012-01-24 12:46:46 -0800235 printf("No.: x_offset y_offset image_size");
236 if (flag & ALPHA_FLAG) printf(" alpha_size");
237 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530238 for (i = 1; i <= nTiles; i++) {
James Zern0f7820e2012-01-24 14:08:27 -0800239 uint32_t x_offset, y_offset;
James Zerneec4b872012-01-07 12:44:01 -0800240 WebPData image, alpha;
241 err = WebPMuxGetTile(mux, i, &image, &alpha, &x_offset, &y_offset);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530242 RETURN_IF_ERROR2("Failed to retrieve tile#%d\n", i);
James Zern95667b82012-04-18 17:13:34 -0700243 printf("%3d: %8d %8d %10zu",
James Zern974aaff2012-01-24 12:46:46 -0800244 i, x_offset, y_offset, image.size_);
James Zern95667b82012-04-18 17:13:34 -0700245 if (flag & ALPHA_FLAG) printf(" %10zu", alpha.size_);
James Zern974aaff2012-01-24 12:46:46 -0800246 printf("\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530247 }
248 }
249 }
250
251 if (flag & ICCP_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800252 WebPData icc_profile;
253 err = WebPMuxGetColorProfile(mux, &icc_profile);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530254 RETURN_IF_ERROR("Failed to retrieve the color profile\n");
James Zern95667b82012-04-18 17:13:34 -0700255 printf("Size of the color profile data: %zu\n", icc_profile.size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530256 }
257
258 if (flag & META_FLAG) {
James Zerneec4b872012-01-07 12:44:01 -0800259 WebPData metadata;
260 err = WebPMuxGetMetadata(mux, &metadata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530261 RETURN_IF_ERROR("Failed to retrieve the XMP metadata\n");
James Zern95667b82012-04-18 17:13:34 -0700262 printf("Size of the XMP metadata: %zu\n", metadata.size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530263 }
264
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530265 if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) {
James Zerneec4b872012-01-07 12:44:01 -0800266 WebPData image, alpha;
267 err = WebPMuxGetImage(mux, &image, &alpha);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530268 RETURN_IF_ERROR("Failed to retrieve the image\n");
James Zern95667b82012-04-18 17:13:34 -0700269 printf("Size of the alpha data: %zu\n", alpha.size_);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530270 }
271
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530272 return WEBP_MUX_OK;
273}
274
Pascal Massiminoabd030b2011-11-01 06:24:34 -0700275static void PrintHelp(void) {
James Zern974aaff2012-01-24 12:46:46 -0800276 printf("Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT\n");
277 printf(" webpmux -set SET_OPTIONS INPUT -o OUTPUT\n");
278 printf(" webpmux -strip STRIP_OPTIONS INPUT -o OUTPUT\n");
279 printf(" webpmux -tile TILE_OPTIONS [-tile...] -o OUTPUT\n");
280 printf(" webpmux -frame FRAME_OPTIONS [-frame...]");
281 printf(" -loop LOOP_COUNT -o OUTPUT\n");
282 printf(" webpmux -info INPUT\n");
283 printf(" webpmux [-h|-help]\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530284
James Zern974aaff2012-01-24 12:46:46 -0800285 printf("\n");
286 printf("GET_OPTIONS:\n");
287 printf(" Extract relevant data.\n");
288 printf(" icc Get ICCP Color profile.\n");
289 printf(" xmp Get XMP metadata.\n");
290 printf(" tile n Get nth tile.\n");
291 printf(" frame n Get nth frame.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530292
James Zern974aaff2012-01-24 12:46:46 -0800293 printf("\n");
294 printf("SET_OPTIONS:\n");
295 printf(" Set color profile/metadata.\n");
296 printf(" icc Set ICC Color profile.\n");
297 printf(" xmp Set XMP metadata.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530298
James Zern974aaff2012-01-24 12:46:46 -0800299 printf("\n");
300 printf("STRIP_OPTIONS:\n");
301 printf(" Strip color profile/metadata.\n");
302 printf(" icc Strip ICCP color profile.\n");
303 printf(" xmp Strip XMP metadata.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530304
James Zern974aaff2012-01-24 12:46:46 -0800305 printf("\n");
306 printf("TILE_OPTIONS(i):\n");
307 printf(" Create tiled image.\n");
308 printf(" file_i +xi+yi\n");
309 printf(" where: 'file_i' is the i'th tile (webp format),\n");
310 printf(" 'xi','yi' specify the image offset for this tile.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530311
James Zern974aaff2012-01-24 12:46:46 -0800312 printf("\n");
313 printf("FRAME_OPTIONS(i):\n");
314 printf(" Create animation.\n");
315 printf(" file_i +xi+yi+di\n");
316 printf(" where: 'file_i' is the i'th animation frame (webp format),\n");
317 printf(" 'xi','yi' specify the image offset for this frame.\n");
318 printf(" 'di' is the pause duration before next frame.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530319
James Zern974aaff2012-01-24 12:46:46 -0800320 printf("\nINPUT & OUTPUT are in webp format.\n");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530321}
322
James Zern061263a2012-05-11 16:00:57 -0700323static int CreateMux(const char* const filename, WebPMux** mux) {
324 size_t size = 0;
325 const uint8_t* data = NULL;
Urvang Joshi8d6490d2012-01-13 14:46:30 +0530326 WebPMuxState mux_state;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530327
328 assert(mux != NULL);
329
James Zern061263a2012-05-11 16:00:57 -0700330 if (!ExUtilReadFile(filename, &data, &size)) return 0;
James Zern0f7820e2012-01-24 14:08:27 -0800331 *mux = WebPMuxCreate(data, size, 1, &mux_state);
James Zern061263a2012-05-11 16:00:57 -0700332 free((void*)data);
Urvang Joshi8d6490d2012-01-13 14:46:30 +0530333 if (*mux != NULL && mux_state == WEBP_MUX_STATE_COMPLETE) return 1;
334 fprintf(stderr, "Failed to create mux object from file %s. mux_state = %d.\n",
335 filename, mux_state);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530336 return 0;
337}
338
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530339static int ReadImage(const char* filename,
James Zern0f7820e2012-01-24 14:08:27 -0800340 WebPData* const image_ptr, WebPData* const alpha_ptr) {
James Zern061263a2012-05-11 16:00:57 -0700341 const uint8_t* data = NULL;
342 size_t size = 0;
James Zerneec4b872012-01-07 12:44:01 -0800343 WebPData image, alpha;
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530344 WebPMux* mux;
345 WebPMuxError err;
346 int ok = 0;
Urvang Joshi8d6490d2012-01-13 14:46:30 +0530347 WebPMuxState mux_state;
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530348
James Zern061263a2012-05-11 16:00:57 -0700349 if (!ExUtilReadFile(filename, &data, &size)) return 0;
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530350
James Zern0f7820e2012-01-24 14:08:27 -0800351 mux = WebPMuxCreate(data, size, 1, &mux_state);
James Zern061263a2012-05-11 16:00:57 -0700352 free((void*)data);
Urvang Joshi8d6490d2012-01-13 14:46:30 +0530353 if (mux == NULL || mux_state != WEBP_MUX_STATE_COMPLETE) {
354 fprintf(stderr,
355 "Failed to create mux object from file %s. mux_state = %d.\n",
356 filename, mux_state);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530357 return 0;
358 }
James Zerneec4b872012-01-07 12:44:01 -0800359 err = WebPMuxGetImage(mux, &image, &alpha);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530360 if (err == WEBP_MUX_OK) {
James Zern0f7820e2012-01-24 14:08:27 -0800361 ok = 1;
362 ok &= WebPDataCopy(&image, image_ptr);
363 ok &= WebPDataCopy(&alpha, alpha_ptr);
364 if (!ok) {
James Zern95667b82012-04-18 17:13:34 -0700365 fprintf(stderr, "Error allocating storage for image (%zu bytes) "
366 "and alpha (%zu bytes) data\n", image.size_, alpha.size_);
James Zern0f7820e2012-01-24 14:08:27 -0800367 WebPDataFree(image_ptr);
368 WebPDataFree(alpha_ptr);
Urvang Joshicdf97aa2011-12-01 16:11:51 +0530369 }
370 } else {
371 fprintf(stderr, "Failed to extract image data from file %s. Error: %d\n",
372 filename, err);
373 }
374 WebPMuxDelete(mux);
375 return ok;
376}
377
James Zern0f7820e2012-01-24 14:08:27 -0800378static int WriteData(const char* filename, const WebPData* const webpdata) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530379 int ok = 0;
James Zern04e84cf2011-11-04 15:20:08 -0700380 FILE* fout = strcmp(filename, "-") ? fopen(filename, "wb") : stdout;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530381 if (!fout) {
382 fprintf(stderr, "Error opening output WebP file %s!\n", filename);
383 return 0;
384 }
James Zern0f7820e2012-01-24 14:08:27 -0800385 if (fwrite(webpdata->bytes_, webpdata->size_, 1, fout) != 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530386 fprintf(stderr, "Error writing file %s!\n", filename);
387 } else {
James Zern95667b82012-04-18 17:13:34 -0700388 fprintf(stderr, "Saved file %s (%zu bytes)\n", filename, webpdata->size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530389 ok = 1;
390 }
391 if (fout != stdout) fclose(fout);
392 return ok;
393}
394
395static int WriteWebP(WebPMux* const mux, const char* filename) {
James Zern0f7820e2012-01-24 14:08:27 -0800396 WebPData webpdata;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530397 int ok;
398
James Zern0f7820e2012-01-24 14:08:27 -0800399 const WebPMuxError err = WebPMuxAssemble(
400 mux, (uint8_t**)&webpdata.bytes_, &webpdata.size_);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530401 if (err != WEBP_MUX_OK) {
402 fprintf(stderr, "Error (%d) assembling the WebP file.\n", err);
403 return 0;
404 }
James Zern0f7820e2012-01-24 14:08:27 -0800405 ok = WriteData(filename, &webpdata);
406 WebPDataFree(&webpdata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530407 return ok;
408}
409
410static int ParseFrameArgs(const char* args, uint32_t* x_offset,
411 uint32_t* y_offset, uint32_t* duration) {
412 return (sscanf(args, "+%d+%d+%d", x_offset, y_offset, duration) == 3);
413}
414
415static int ParseTileArgs(const char* args, uint32_t* x_offset,
416 uint32_t* y_offset) {
417 return (sscanf(args, "+%d+%d", x_offset, y_offset) == 2);
418}
419
420//------------------------------------------------------------------------------
421// Clean-up.
422
423static void DeleteConfig(WebPMuxConfig* config) {
424 if (config != NULL) {
425 free(config->feature_.args_);
426 free(config);
427 }
428}
429
430//------------------------------------------------------------------------------
431// Parsing.
432
433// Basic syntactic checks on the command-line arguments.
434// Returns 1 on valid, 0 otherwise.
435// Also fills up num_feature_args to be number of feature arguments given.
436// (e.g. if there are 4 '-frame's and 1 '-loop', then num_feature_args = 5).
437static int ValidateCommandLine(int argc, const char* argv[],
438 int* num_feature_args) {
439 int num_frame_args;
440 int num_tile_args;
441 int num_loop_args;
442 int ok = 1;
443
444 assert(num_feature_args != NULL);
445 *num_feature_args = 0;
446
447 // Simple checks.
James Zern04e84cf2011-11-04 15:20:08 -0700448 if (CountOccurrences(argv, argc, "-get") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530449 ERROR_GOTO1("ERROR: Multiple '-get' arguments specified.\n", ErrValidate);
450 }
James Zern04e84cf2011-11-04 15:20:08 -0700451 if (CountOccurrences(argv, argc, "-set") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530452 ERROR_GOTO1("ERROR: Multiple '-set' arguments specified.\n", ErrValidate);
453 }
James Zern04e84cf2011-11-04 15:20:08 -0700454 if (CountOccurrences(argv, argc, "-strip") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530455 ERROR_GOTO1("ERROR: Multiple '-strip' arguments specified.\n", ErrValidate);
456 }
James Zern04e84cf2011-11-04 15:20:08 -0700457 if (CountOccurrences(argv, argc, "-info") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530458 ERROR_GOTO1("ERROR: Multiple '-info' arguments specified.\n", ErrValidate);
459 }
James Zern04e84cf2011-11-04 15:20:08 -0700460 if (CountOccurrences(argv, argc, "-o") > 1) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530461 ERROR_GOTO1("ERROR: Multiple output files specified.\n", ErrValidate);
462 }
463
464 // Compound checks.
James Zern04e84cf2011-11-04 15:20:08 -0700465 num_frame_args = CountOccurrences(argv, argc, "-frame");
466 num_tile_args = CountOccurrences(argv, argc, "-tile");
467 num_loop_args = CountOccurrences(argv, argc, "-loop");
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530468
469 if (num_loop_args > 1) {
470 ERROR_GOTO1("ERROR: Multiple loop counts specified.\n", ErrValidate);
471 }
472
473 if (IsNotCompatible(num_frame_args, num_loop_args)) {
474 ERROR_GOTO1("ERROR: Both frames and loop count have to be specified.\n",
475 ErrValidate);
476 }
477 if (num_frame_args > 0 && num_tile_args > 0) {
478 ERROR_GOTO1("ERROR: Only one of frames & tiles can be specified at a time."
479 "\n", ErrValidate);
480 }
481
482 assert(ok == 1);
483 if (num_frame_args == 0 && num_tile_args == 0) {
484 // Single argument ('set' action for XMP or ICCP, OR a 'get' action).
485 *num_feature_args = 1;
486 } else {
487 // Multiple arguments ('set' action for animation or tiling).
488 if (num_frame_args > 0) {
489 *num_feature_args = num_frame_args + num_loop_args;
490 } else {
491 *num_feature_args = num_tile_args;
492 }
493 }
494
495 ErrValidate:
496 return ok;
497}
498
499#define ACTION_IS_NIL (config->action_type_ == NIL_ACTION)
500
501#define FEATURETYPE_IS_NIL (feature->type_ == NIL_FEATURE)
502
503#define CHECK_NUM_ARGS_LESS(NUM, LABEL) \
504 if (argc < i + (NUM)) { \
505 fprintf(stderr, "ERROR: Too few arguments for '%s'.\n", argv[i]); \
506 goto LABEL; \
507 }
508
509#define CHECK_NUM_ARGS_NOT_EQUAL(NUM, LABEL) \
510 if (argc != i + (NUM)) { \
511 fprintf(stderr, "ERROR: Too many arguments for '%s'.\n", argv[i]); \
512 goto LABEL; \
513 }
514
515// Parses command-line arguments to fill up config object. Also performs some
516// semantic checks.
517static int ParseCommandLine(int argc, const char* argv[],
518 WebPMuxConfig* config) {
519 int i = 0;
520 int feature_arg_index = 0;
521 int ok = 1;
522
523 while (i < argc) {
524 Feature* const feature = &config->feature_;
James Zern04e84cf2011-11-04 15:20:08 -0700525 FeatureArg* const arg = &feature->args_[feature_arg_index];
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530526 if (argv[i][0] == '-') { // One of the action types or output.
527 if (!strcmp(argv[i], "-set")) {
528 if (ACTION_IS_NIL) {
529 config->action_type_ = ACTION_SET;
530 } else {
531 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
532 }
533 ++i;
534 } else if (!strcmp(argv[i], "-get")) {
535 if (ACTION_IS_NIL) {
536 config->action_type_ = ACTION_GET;
537 } else {
538 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
539 }
540 ++i;
541 } else if (!strcmp(argv[i], "-strip")) {
542 if (ACTION_IS_NIL) {
543 config->action_type_ = ACTION_STRIP;
544 feature->arg_count_ = 0;
545 } else {
546 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
547 }
548 ++i;
549 } else if (!strcmp(argv[i], "-frame")) {
550 CHECK_NUM_ARGS_LESS(3, ErrParse);
551 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
552 config->action_type_ = ACTION_SET;
553 } else {
554 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
555 }
556 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) {
557 feature->type_ = FEATURE_FRM;
558 } else {
559 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
560 }
561 arg->subtype_ = SUBTYPE_FRM;
562 arg->filename_ = argv[i + 1];
563 arg->params_ = argv[i + 2];
564 ++feature_arg_index;
565 i += 3;
566 } else if (!strcmp(argv[i], "-loop")) {
567 CHECK_NUM_ARGS_LESS(2, ErrParse);
568 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
569 config->action_type_ = ACTION_SET;
570 } else {
571 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
572 }
573 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_FRM) {
574 feature->type_ = FEATURE_FRM;
575 } else {
576 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
577 }
578 arg->subtype_ = SUBTYPE_LOOP;
579 arg->params_ = argv[i + 1];
580 ++feature_arg_index;
581 i += 2;
582 } else if (!strcmp(argv[i], "-tile")) {
583 CHECK_NUM_ARGS_LESS(3, ErrParse);
584 if (ACTION_IS_NIL || config->action_type_ == ACTION_SET) {
585 config->action_type_ = ACTION_SET;
586 } else {
587 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
588 }
589 if (FEATURETYPE_IS_NIL || feature->type_ == FEATURE_TILE) {
590 feature->type_ = FEATURE_TILE;
591 } else {
592 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
593 }
594 arg->filename_ = argv[i + 1];
595 arg->params_ = argv[i + 2];
596 ++feature_arg_index;
597 i += 3;
598 } else if (!strcmp(argv[i], "-o")) {
599 CHECK_NUM_ARGS_LESS(2, ErrParse);
600 config->output_ = argv[i + 1];
601 i += 2;
602 } else if (!strcmp(argv[i], "-info")) {
603 CHECK_NUM_ARGS_NOT_EQUAL(2, ErrParse);
604 if (config->action_type_ != NIL_ACTION) {
605 ERROR_GOTO1("ERROR: Multiple actions specified.\n", ErrParse);
606 } else {
607 config->action_type_ = ACTION_INFO;
608 feature->arg_count_ = 0;
609 config->input_ = argv[i + 1];
610 }
611 i += 2;
612 } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "-help")) {
613 PrintHelp();
614 DeleteConfig(config);
James Zern974aaff2012-01-24 12:46:46 -0800615 exit(0);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530616 } else {
617 ERROR_GOTO2("ERROR: Unknown option: '%s'.\n", argv[i], ErrParse);
618 }
619 } else { // One of the feature types or input.
620 if (ACTION_IS_NIL) {
621 ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n",
622 ErrParse);
623 }
624 if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "xmp")) {
625 if (FEATURETYPE_IS_NIL) {
626 feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
627 FEATURE_XMP;
628 } else {
629 ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
630 }
631 if (config->action_type_ == ACTION_SET) {
632 CHECK_NUM_ARGS_LESS(2, ErrParse);
633 arg->filename_ = argv[i + 1];
634 ++feature_arg_index;
635 i += 2;
636 } else {
637 ++i;
638 }
639 } else if ((!strcmp(argv[i], "frame") ||
640 !strcmp(argv[i], "tile")) &&
641 (config->action_type_ == ACTION_GET)) {
642 CHECK_NUM_ARGS_LESS(2, ErrParse);
643 feature->type_ = (!strcmp(argv[i], "frame")) ? FEATURE_FRM :
644 FEATURE_TILE;
645 arg->params_ = argv[i + 1];
646 ++feature_arg_index;
647 i += 2;
James Zern04e84cf2011-11-04 15:20:08 -0700648 } else { // Assume input file.
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530649 if (config->input_ == NULL) {
650 config->input_ = argv[i];
651 } else {
652 ERROR_GOTO2("ERROR at '%s': Multiple input files specified.\n",
653 argv[i], ErrParse);
654 }
655 ++i;
656 }
657 }
658 }
659 ErrParse:
660 return ok;
661}
662
James Zern04e84cf2011-11-04 15:20:08 -0700663// Additional checks after config is filled.
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530664static int ValidateConfig(WebPMuxConfig* config) {
665 int ok = 1;
666 Feature* const feature = &config->feature_;
667
668 // Action.
669 if (ACTION_IS_NIL) {
670 ERROR_GOTO1("ERROR: No action specified.\n", ErrValidate2);
671 }
672
673 // Feature type.
674 if (FEATURETYPE_IS_NIL && config->action_type_ != ACTION_INFO) {
675 ERROR_GOTO1("ERROR: No feature specified.\n", ErrValidate2);
676 }
677
678 // Input file.
679 if (config->input_ == NULL) {
680 if (config->action_type_ != ACTION_SET) {
681 ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
682 } else if (feature->type_ != FEATURE_FRM &&
683 feature->type_ != FEATURE_TILE) {
684 ERROR_GOTO1("ERROR: No input file specified.\n", ErrValidate2);
685 }
686 }
687
688 // Output file.
689 if (config->output_ == NULL && config->action_type_ != ACTION_INFO) {
690 ERROR_GOTO1("ERROR: No output file specified.\n", ErrValidate2);
691 }
692
693 ErrValidate2:
694 return ok;
695}
696
697// Create config object from command-line arguments.
698static int InitializeConfig(int argc, const char* argv[],
699 WebPMuxConfig** config) {
700 int num_feature_args = 0;
701 int ok = 1;
702
703 assert(config != NULL);
704 *config = NULL;
705
706 // Validate command-line arguments.
707 if (!ValidateCommandLine(argc, argv, &num_feature_args)) {
708 ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
709 }
710
711 // Allocate memory.
712 *config = (WebPMuxConfig*)calloc(1, sizeof(**config));
713 if (*config == NULL) {
714 ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
715 }
716 (*config)->feature_.arg_count_ = num_feature_args;
717 (*config)->feature_.args_ =
718 (FeatureArg*)calloc(num_feature_args, sizeof(FeatureArg));
719 if ((*config)->feature_.args_ == NULL) {
720 ERROR_GOTO1("ERROR: Memory allocation error.\n", Err1);
721 }
722
723 // Parse command-line.
James Zern04e84cf2011-11-04 15:20:08 -0700724 if (!ParseCommandLine(argc, argv, *config) ||
725 !ValidateConfig(*config)) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530726 ERROR_GOTO1("Exiting due to command-line parsing error.\n", Err1);
727 }
728
729 Err1:
730 return ok;
731}
732
733#undef ACTION_IS_NIL
734#undef FEATURETYPE_IS_NIL
735#undef CHECK_NUM_ARGS_LESS
736#undef CHECK_NUM_ARGS_MORE
737
738//------------------------------------------------------------------------------
739// Processing.
740
James Zern04e84cf2011-11-04 15:20:08 -0700741static int GetFrameTile(const WebPMux* mux,
742 const WebPMuxConfig* config, int isFrame) {
James Zerneec4b872012-01-07 12:44:01 -0800743 WebPData image, alpha;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530744 uint32_t x_offset = 0;
745 uint32_t y_offset = 0;
746 uint32_t duration = 0;
747 WebPMuxError err = WEBP_MUX_OK;
748 WebPMux* mux_single = NULL;
749 long num = 0;
750 int ok = 1;
751
752 num = strtol(config->feature_.args_[0].params_, NULL, 10);
753 if (num < 0) {
754 ERROR_GOTO1("ERROR: Frame/Tile index must be non-negative.\n", ErrGet);
755 }
756
757 if (isFrame) {
James Zerneec4b872012-01-07 12:44:01 -0800758 err = WebPMuxGetFrame(mux, num, &image, &alpha,
Urvang Joshic398f592011-11-22 14:40:41 +0530759 &x_offset, &y_offset, &duration);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530760 if (err != WEBP_MUX_OK) {
761 ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet);
762 }
763 } else {
James Zerneec4b872012-01-07 12:44:01 -0800764 err = WebPMuxGetTile(mux, num, &image, &alpha, &x_offset, &y_offset);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530765 if (err != WEBP_MUX_OK) {
766 ERROR_GOTO3("ERROR#%d: Could not get frame %ld.\n", err, num, ErrGet);
767 }
768 }
769
770 mux_single = WebPMuxNew();
771 if (mux_single == NULL) {
772 err = WEBP_MUX_MEMORY_ERROR;
773 ERROR_GOTO2("ERROR#%d: Could not allocate a mux object.\n", err, ErrGet);
774 }
James Zerneec4b872012-01-07 12:44:01 -0800775 err = WebPMuxSetImage(mux_single, image.bytes_, image.size_,
776 alpha.bytes_, alpha.size_, 1);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530777 if (err != WEBP_MUX_OK) {
778 ERROR_GOTO2("ERROR#%d: Could not create single image mux object.\n", err,
779 ErrGet);
780 }
781 ok = WriteWebP(mux_single, config->output_);
782
783 ErrGet:
784 WebPMuxDelete(mux_single);
785 return ok;
786}
787
788// Read and process config.
James Zern04e84cf2011-11-04 15:20:08 -0700789static int Process(const WebPMuxConfig* config) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530790 WebPMux* mux = NULL;
James Zerneec4b872012-01-07 12:44:01 -0800791 WebPData webpdata;
James Zern061263a2012-05-11 16:00:57 -0700792 const uint8_t* data = NULL;
793 size_t size = 0;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530794 uint32_t x_offset = 0;
795 uint32_t y_offset = 0;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530796 WebPMuxError err = WEBP_MUX_OK;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530797 int index = 0;
798 int ok = 1;
James Zern04e84cf2011-11-04 15:20:08 -0700799 const Feature* const feature = &config->feature_;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530800
James Zern04e84cf2011-11-04 15:20:08 -0700801 switch (config->action_type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530802 case ACTION_GET:
James Zern061263a2012-05-11 16:00:57 -0700803 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530804 if (!ok) goto Err2;
James Zern04e84cf2011-11-04 15:20:08 -0700805 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530806 case FEATURE_FRM:
807 ok = GetFrameTile(mux, config, 1);
808 break;
809
810 case FEATURE_TILE:
811 ok = GetFrameTile(mux, config, 0);
812 break;
813
814 case FEATURE_ICCP:
James Zerneec4b872012-01-07 12:44:01 -0800815 err = WebPMuxGetColorProfile(mux, &webpdata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530816 if (err != WEBP_MUX_OK) {
817 ERROR_GOTO2("ERROR#%d: Could not get color profile.\n", err, Err2);
818 }
James Zern0f7820e2012-01-24 14:08:27 -0800819 ok = WriteData(config->output_, &webpdata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530820 break;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530821 case FEATURE_XMP:
James Zerneec4b872012-01-07 12:44:01 -0800822 err = WebPMuxGetMetadata(mux, &webpdata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530823 if (err != WEBP_MUX_OK) {
824 ERROR_GOTO2("ERROR#%d: Could not get XMP metadata.\n", err, Err2);
825 }
James Zern0f7820e2012-01-24 14:08:27 -0800826 ok = WriteData(config->output_, &webpdata);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530827 break;
828
829 default:
830 ERROR_GOTO1("ERROR: Invalid feature for action 'get'.\n", Err2);
831 break;
832 }
833 break;
834
835 case ACTION_SET:
James Zern04e84cf2011-11-04 15:20:08 -0700836 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530837 case FEATURE_FRM:
838 mux = WebPMuxNew();
839 if (mux == NULL) {
840 ERROR_GOTO2("ERROR#%d: Could not allocate a mux object.\n",
841 WEBP_MUX_MEMORY_ERROR, Err2);
842 }
843 for (index = 0; index < feature->arg_count_; ++index) {
844 if (feature->args_[index].subtype_ == SUBTYPE_LOOP) {
James Zern0f7820e2012-01-24 14:08:27 -0800845 const long num = strtol(feature->args_[index].params_, NULL, 10);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530846 if (num < 0) {
847 ERROR_GOTO1("ERROR: Loop count must be non-negative.\n", Err2);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530848 }
James Zern0f7820e2012-01-24 14:08:27 -0800849 err = WebPMuxSetLoopCount(mux, num);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530850 if (err != WEBP_MUX_OK) {
851 ERROR_GOTO2("ERROR#%d: Could not set loop count.\n", err, Err2);
852 }
853 } else if (feature->args_[index].subtype_ == SUBTYPE_FRM) {
James Zern0f7820e2012-01-24 14:08:27 -0800854 WebPData image, alpha;
855 uint32_t duration;
856 ok = ReadImage(feature->args_[index].filename_, &image, &alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530857 if (!ok) goto Err2;
858 ok = ParseFrameArgs(feature->args_[index].params_,
859 &x_offset, &y_offset, &duration);
860 if (!ok) {
James Zern0f7820e2012-01-24 14:08:27 -0800861 WebPDataFree(&image);
862 WebPDataFree(&alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530863 ERROR_GOTO1("ERROR: Could not parse frame properties.\n", Err2);
864 }
James Zern0f7820e2012-01-24 14:08:27 -0800865 err = WebPMuxAddFrame(mux, 0, image.bytes_, image.size_,
866 alpha.bytes_, alpha.size_,
Urvang Joshic398f592011-11-22 14:40:41 +0530867 x_offset, y_offset, duration, 1);
James Zern0f7820e2012-01-24 14:08:27 -0800868 WebPDataFree(&image);
869 WebPDataFree(&alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530870 if (err != WEBP_MUX_OK) {
871 ERROR_GOTO3("ERROR#%d: Could not add a frame at index %d.\n",
872 err, index, Err2);
873 }
874 } else {
875 ERROR_GOTO1("ERROR: Invalid subtype for 'frame'", Err2);
876 }
877 }
878 break;
879
880 case FEATURE_TILE:
881 mux = WebPMuxNew();
882 if (mux == NULL) {
883 ERROR_GOTO2("ERROR#%d: Could not allocate a mux object.\n",
884 WEBP_MUX_MEMORY_ERROR, Err2);
885 }
886 for (index = 0; index < feature->arg_count_; ++index) {
James Zern0f7820e2012-01-24 14:08:27 -0800887 WebPData image, alpha;
888 ok = ReadImage(feature->args_[index].filename_, &image, &alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530889 if (!ok) goto Err2;
890 ok = ParseTileArgs(feature->args_[index].params_, &x_offset,
891 &y_offset);
892 if (!ok) {
James Zern0f7820e2012-01-24 14:08:27 -0800893 WebPDataFree(&image);
894 WebPDataFree(&alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530895 ERROR_GOTO1("ERROR: Could not parse tile properties.\n", Err2);
896 }
James Zern0f7820e2012-01-24 14:08:27 -0800897 err = WebPMuxAddTile(mux, 0, image.bytes_, image.size_,
898 alpha.bytes_, alpha.size_,
Urvang Joshic398f592011-11-22 14:40:41 +0530899 x_offset, y_offset, 1);
James Zern0f7820e2012-01-24 14:08:27 -0800900 WebPDataFree(&image);
901 WebPDataFree(&alpha);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530902 if (err != WEBP_MUX_OK) {
903 ERROR_GOTO3("ERROR#%d: Could not add a tile at index %d.\n",
904 err, index, Err2);
905 }
906 }
907 break;
908
909 case FEATURE_ICCP:
James Zern061263a2012-05-11 16:00:57 -0700910 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530911 if (!ok) goto Err2;
James Zern061263a2012-05-11 16:00:57 -0700912 ok = ExUtilReadFile(feature->args_[0].filename_, &data, &size);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530913 if (!ok) goto Err2;
914 err = WebPMuxSetColorProfile(mux, data, size, 1);
915 free((void*)data);
916 if (err != WEBP_MUX_OK) {
917 ERROR_GOTO2("ERROR#%d: Could not set color profile.\n", err, Err2);
918 }
919 break;
920
921 case FEATURE_XMP:
James Zern061263a2012-05-11 16:00:57 -0700922 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530923 if (!ok) goto Err2;
James Zern061263a2012-05-11 16:00:57 -0700924 ok = ExUtilReadFile(feature->args_[0].filename_, &data, &size);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530925 if (!ok) goto Err2;
926 err = WebPMuxSetMetadata(mux, data, size, 1);
James Zern061263a2012-05-11 16:00:57 -0700927 free((void*)data);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530928 if (err != WEBP_MUX_OK) {
929 ERROR_GOTO2("ERROR#%d: Could not set XMP metadata.\n", err, Err2);
930 }
931 break;
932
933 default:
934 ERROR_GOTO1("ERROR: Invalid feature for action 'set'.\n", Err2);
935 break;
936 }
937 ok = WriteWebP(mux, config->output_);
938 break;
939
940 case ACTION_STRIP:
James Zern061263a2012-05-11 16:00:57 -0700941 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530942 if (!ok) goto Err2;
James Zern04e84cf2011-11-04 15:20:08 -0700943 switch (feature->type_) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530944 case FEATURE_ICCP:
945 err = WebPMuxDeleteColorProfile(mux);
946 if (err != WEBP_MUX_OK) {
947 ERROR_GOTO2("ERROR#%d: Could not delete color profile.\n", err,
948 Err2);
949 }
950 break;
951 case FEATURE_XMP:
952 err = WebPMuxDeleteMetadata(mux);
953 if (err != WEBP_MUX_OK) {
954 ERROR_GOTO2("ERROR#%d: Could not delete XMP metadata.\n", err,
955 Err2);
956 }
957 break;
958 default:
959 ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
960 break;
961 }
962 ok = WriteWebP(mux, config->output_);
963 break;
964
965 case ACTION_INFO:
James Zern061263a2012-05-11 16:00:57 -0700966 ok = CreateMux(config->input_, &mux);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530967 if (!ok) goto Err2;
968 ok = (DisplayInfo(mux) == WEBP_MUX_OK);
969 break;
970
971 default:
972 assert(0); // Invalid action.
973 break;
974 }
975
976 Err2:
977 WebPMuxDelete(mux);
978 return ok;
979}
980
981//------------------------------------------------------------------------------
982// Main.
983
984int main(int argc, const char* argv[]) {
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530985 WebPMuxConfig* config;
James Zern974aaff2012-01-24 12:46:46 -0800986 int ok = InitializeConfig(argc - 1, argv + 1, &config);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530987 if (ok) {
James Zern974aaff2012-01-24 12:46:46 -0800988 ok = Process(config);
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530989 } else {
990 PrintHelp();
991 }
992 DeleteConfig(config);
James Zern974aaff2012-01-24 12:46:46 -0800993 return !ok;
Urvang Joshia4f32ca2011-09-30 11:07:01 +0530994}
995
996//------------------------------------------------------------------------------