Chunk fourCCs for XMP/EXIF

Use separate fourCCs "XMP " and "EXIF" instead of a common "META"
Also, some refactorization in webpmux.c

Change-Id: Iad3337e5c1b81e785c60670ce28b1f536dd7ee31
This commit is contained in:
Urvang Joshi 2012-10-31 16:30:41 -07:00
parent 52ad1979d2
commit f903cbab9a
11 changed files with 208 additions and 147 deletions

View File

@ -8,7 +8,7 @@ Description:
============ ============
WebP Mux: library to create a WebP container object for features like WebP Mux: library to create a WebP container object for features like
color profile, metadata, animation & tiling. A reference command line color profile, metadata, animation and tiling. A reference command line
tool 'webpmux' and WebP container specification 'doc/webp-container-spec.txt' tool 'webpmux' and WebP container specification 'doc/webp-container-spec.txt'
are also provided in this package. are also provided in this package.
@ -32,56 +32,63 @@ Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT
GET_OPTIONS: GET_OPTIONS:
Extract relevant data. Extract relevant data.
icc Get ICCP Color profile. icc Get ICC profile.
meta Get XMP/EXIF metadata. exif Get EXIF metadata.
xmp Get XMP metadata.
tile n Get nth tile. tile n Get nth tile.
frame n Get nth frame. frame n Get nth frame.
SET_OPTIONS: SET_OPTIONS:
Set color profile/metadata. Set color profile/metadata.
icc file.icc Set ICC Color profile. icc file.icc Set ICC profile.
meta file.meta Set XMP/EXIF metadata. exif file.exif Set EXIF metadata.
where: 'file.icc' contains the color profile to be set, xmp file.xmp Set XMP metadata.
'file.meta' contains the metadata to be set where: 'file.icc' contains the ICC profile to be set,
'file.exif' contains the EXIF metadata to be set and
'file.xmp' contains the XMP metadata to be set
STRIP_OPTIONS: STRIP_OPTIONS:
Strip color profile/metadata. Strip color profile/metadata.
icc Strip ICCP color profile. icc Strip ICC profile.
meta Strip XMP/EXIF metadata. exif Strip EXIF metadata.
xmp Strip XMP metadata.
TILE_OPTIONS(i): TILE_OPTIONS(i):
Create tiled image. Create tiled image.
file_i +xi+yi file_i +xi+yi
where: 'file_i' is the i'th tile (webp format), where: 'file_i' is the i'th tile (WebP format),
'xi','yi' specify the image offset for this tile. 'xi','yi' specify the image offset for this tile.
FRAME_OPTIONS(i): FRAME_OPTIONS(i):
Create animation. Create animation.
file_i +xi+yi+di file_i +xi+yi+di
where: 'file_i' is the i'th animation frame (webp format), where: 'file_i' is the i'th animation frame (WebP format),
'xi','yi' specify the image offset for this frame. 'xi','yi' specify the image offset for this frame.
'di' is the pause duration before next frame. 'di' is the pause duration before next frame.
INPUT & OUTPUT are in webp format. INPUT and OUTPUT are in WebP format.
Note: The nature of EXIF, XMP and ICC data is not checked and is assumed to be
valid.
WebP Mux API: WebP Mux API:
============== ==============
The WebP Mux API contains methods for adding data to and reading data from The WebP Mux API contains methods for adding data to and reading data from
WebPMux (a WebP container object). This API currently supports XMP/EXIF WebPMux (a WebP container object). This API currently supports XMP/EXIF
metadata, ICC color profile, animation & tiling. Other features will be added in metadata, ICC profile, animation and tiling. Other features will be added
subsequent releases. in subsequent releases.
Example#1 (pseudo code): Creating a WebPMux object with image data, color Example#1 (pseudo code): Creating a WebPMux object with image data, color
profile & XMP metadata. profile and XMP metadata.
int copy_data = 0; int copy_data = 0;
WebPMux* mux = WebPMuxNew(); WebPMux* mux = WebPMuxNew();
// ... (Prepare image data). // ... (Prepare image data).
WebPMuxSetImage(mux, &image, copy_data); WebPMuxSetImage(mux, &image, copy_data);
// ... (Prepare ICCP color profile data). // ... (Prepare ICC profile data).
WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
// ... (Prepare XMP metadata). // ... (Prepare XMP metadata).
WebPMuxSetChunk(mux, "META", &xmp, copy_data); WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
// Get data from mux in WebP RIFF format. // Get data from mux in WebP RIFF format.
WebPMuxAssemble(mux, &output_data); WebPMuxAssemble(mux, &output_data);
WebPMuxDelete(mux); WebPMuxDelete(mux);
@ -89,7 +96,7 @@ profile & XMP metadata.
WebPDataClear(&output_data); WebPDataClear(&output_data);
Example#2 (pseudo code): Get image & color profile data from a WebP file. Example#2 (pseudo code): Get image and color profile data from a WebP file.
int copy_data = 0; int copy_data = 0;
// ... (Read data from file). // ... (Read data from file).

View File

@ -31,17 +31,20 @@
-o out_animation_container.webp -o out_animation_container.webp
webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp webpmux -set icc image_profile.icc in.webp -o out_icc_container.webp
webpmux -set meta image_metadata.meta in.webp -o out_meta_container.webp webpmux -set exif image_metadata.exif in.webp -o out_exif_container.webp
webpmux -set xmp image_metadata.xmp in.webp -o out_xmp_container.webp
Extract relevant data from WebP container file: Extract relevant data from WebP container file:
webpmux -get tile n in.webp -o out_tile.webp webpmux -get tile n in.webp -o out_tile.webp
webpmux -get frame n in.webp -o out_frame.webp webpmux -get frame n in.webp -o out_frame.webp
webpmux -get icc in.webp -o image_profile.icc webpmux -get icc in.webp -o image_profile.icc
webpmux -get meta in.webp -o image_metadata.meta webpmux -get exif in.webp -o image_metadata.exif
webpmux -get xmp in.webp -o image_metadata.xmp
Strip data from WebP Container file: Strip data from WebP Container file:
webpmux -strip icc in.webp -o out.webp webpmux -strip icc in.webp -o out.webp
webpmux -strip meta in.webp -o out.webp webpmux -strip exif in.webp -o out.webp
webpmux -strip xmp in.webp -o out.webp
Misc: Misc:
webpmux -info in.webp webpmux -info in.webp
@ -81,12 +84,23 @@ typedef struct {
typedef enum { typedef enum {
NIL_FEATURE = 0, NIL_FEATURE = 0,
FEATURE_META, FEATURE_EXIF,
FEATURE_XMP,
FEATURE_ICCP, FEATURE_ICCP,
FEATURE_FRM, FEATURE_FRM,
FEATURE_TILE FEATURE_TILE,
LAST_FEATURE
} FeatureType; } FeatureType;
static const char* const kFourccList[LAST_FEATURE] = {
NULL, "EXIF", "XMP ", "ICCP", "ANMF", "FRGM"
};
static const char* const kDescriptions[LAST_FEATURE] = {
NULL, "EXIF metadata", "XMP metadata", "ICC profile",
"Animation frame", "Tile fragment"
};
typedef struct { typedef struct {
FeatureType type_; FeatureType type_;
FeatureArg* args_; FeatureArg* args_;
@ -185,7 +199,8 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
if (flag & ANIMATION_FLAG) printf(" animation"); if (flag & ANIMATION_FLAG) printf(" animation");
if (flag & TILE_FLAG) printf(" tiling"); if (flag & TILE_FLAG) printf(" tiling");
if (flag & ICCP_FLAG) printf(" icc profile"); if (flag & ICCP_FLAG) printf(" icc profile");
if (flag & META_FLAG) printf(" metadata"); if (flag & EXIF_FLAG) printf(" EXIF metadata");
if (flag & XMP_FLAG) printf(" XMP metadata");
if (flag & ALPHA_FLAG) printf(" transparency"); if (flag & ALPHA_FLAG) printf(" transparency");
printf("\n"); printf("\n");
@ -226,15 +241,22 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) {
if (flag & ICCP_FLAG) { if (flag & ICCP_FLAG) {
WebPData icc_profile; WebPData icc_profile;
err = WebPMuxGetChunk(mux, "ICCP", &icc_profile); err = WebPMuxGetChunk(mux, "ICCP", &icc_profile);
RETURN_IF_ERROR("Failed to retrieve the color profile\n"); RETURN_IF_ERROR("Failed to retrieve the ICC profile\n");
printf("Size of the color profile data: %zu\n", icc_profile.size); printf("Size of the ICC profile data: %zu\n", icc_profile.size);
} }
if (flag & META_FLAG) { if (flag & EXIF_FLAG) {
WebPData metadata; WebPData exif;
err = WebPMuxGetChunk(mux, "META", &metadata); err = WebPMuxGetChunk(mux, "EXIF", &exif);
RETURN_IF_ERROR("Failed to retrieve the metadata\n"); RETURN_IF_ERROR("Failed to retrieve the EXIF metadata\n");
printf("Size of the metadata: %zu\n", metadata.size); printf("Size of the EXIF metadata: %zu\n", exif.size);
}
if (flag & XMP_FLAG) {
WebPData xmp;
err = WebPMuxGetChunk(mux, "XMP ", &xmp);
RETURN_IF_ERROR("Failed to retrieve the XMP metadata\n");
printf("Size of the XMP metadata: %zu\n", xmp.size);
} }
if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) { if ((flag & ALPHA_FLAG) && !(flag & (ANIMATION_FLAG | TILE_FLAG))) {
@ -260,41 +282,48 @@ static void PrintHelp(void) {
printf("\n"); printf("\n");
printf("GET_OPTIONS:\n"); printf("GET_OPTIONS:\n");
printf(" Extract relevant data.\n"); printf(" Extract relevant data.\n");
printf(" icc Get ICCP Color profile.\n"); printf(" icc Get ICC profile.\n");
printf(" meta Get XMP/EXIF metadata.\n"); printf(" exif Get EXIF metadata.\n");
printf(" xmp Get XMP metadata.\n");
printf(" tile n Get nth tile.\n"); printf(" tile n Get nth tile.\n");
printf(" frame n Get nth frame.\n"); printf(" frame n Get nth frame.\n");
printf("\n"); printf("\n");
printf("SET_OPTIONS:\n"); printf("SET_OPTIONS:\n");
printf(" Set color profile/metadata.\n"); printf(" Set color profile/metadata.\n");
printf(" icc file.icc Set ICC Color profile.\n"); printf(" icc file.icc Set ICC profile.\n");
printf(" meta file.meta Set XMP/EXIF metadata.\n"); printf(" exif file.exif Set EXIF metadata.\n");
printf(" where: 'file.icc' contains the color profile to be set,\n"); printf(" xmp file.xmp Set XMP metadata.\n");
printf(" 'file.meta' contains the metadata to be set\n"); printf(" where: 'file.icc' contains the ICC profile to be set,\n");
printf(" 'file.exif' contains the EXIF metadata to be set\n");
printf(" 'file.xmp' contains the XMP metadata to be set\n");
printf("\n"); printf("\n");
printf("STRIP_OPTIONS:\n"); printf("STRIP_OPTIONS:\n");
printf(" Strip color profile/metadata.\n"); printf(" Strip color profile/metadata.\n");
printf(" icc Strip ICCP color profile.\n"); printf(" icc Strip ICC profile.\n");
printf(" meta Strip XMP/EXIF metadata.\n"); printf(" exif Strip EXIF metadata.\n");
printf(" xmp Strip XMP metadata.\n");
printf("\n"); printf("\n");
printf("TILE_OPTIONS(i):\n"); printf("TILE_OPTIONS(i):\n");
printf(" Create tiled image.\n"); printf(" Create tiled image.\n");
printf(" file_i +xi+yi\n"); printf(" file_i +xi+yi\n");
printf(" where: 'file_i' is the i'th tile (webp format),\n"); printf(" where: 'file_i' is the i'th tile (WebP format),\n");
printf(" 'xi','yi' specify the image offset for this tile.\n"); printf(" 'xi','yi' specify the image offset for this tile.\n");
printf("\n"); printf("\n");
printf("FRAME_OPTIONS(i):\n"); printf("FRAME_OPTIONS(i):\n");
printf(" Create animation.\n"); printf(" Create animation.\n");
printf(" file_i +xi+yi+di\n"); printf(" file_i +xi+yi+di\n");
printf(" where: 'file_i' is the i'th animation frame (webp format),\n"); printf(" where: 'file_i' is the i'th animation frame (WebP format),\n");
printf(" 'xi','yi' specify the image offset for this frame.\n"); printf(" 'xi','yi' specify the image offset for this frame.\n");
printf(" 'di' is the pause duration before next frame.\n"); printf(" 'di' is the pause duration before next frame.\n");
printf("\nINPUT & OUTPUT are in webp format.\n"); printf("\nINPUT & OUTPUT are in WebP format.\n");
printf("\nNote: The nature of EXIF, XMP and ICC data is not checked and is "
"assumed to be valid.\n");
} }
static int ReadFileToWebPData(const char* const filename, static int ReadFileToWebPData(const char* const filename,
@ -421,7 +450,7 @@ static int ValidateCommandLine(int argc, const char* argv[],
assert(ok == 1); assert(ok == 1);
if (num_frame_args == 0 && num_tile_args == 0) { if (num_frame_args == 0 && num_tile_args == 0) {
// Single argument ('set' action for META or ICCP, OR a 'get' action). // Single argument ('set' action for ICCP/EXIF/XMP, OR a 'get' action).
*num_feature_args = 1; *num_feature_args = 1;
} else { } else {
// Multiple arguments ('set' action for animation or tiling). // Multiple arguments ('set' action for animation or tiling).
@ -561,10 +590,11 @@ static int ParseCommandLine(int argc, const char* argv[],
ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n", ERROR_GOTO1("ERROR: Action must be specified before other arguments.\n",
ErrParse); ErrParse);
} }
if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "meta")) { if (!strcmp(argv[i], "icc") || !strcmp(argv[i], "exif") ||
!strcmp(argv[i], "xmp")) {
if (FEATURETYPE_IS_NIL) { if (FEATURETYPE_IS_NIL) {
feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP : feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP :
FEATURE_META; (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP;
} else { } else {
ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse);
} }
@ -723,7 +753,7 @@ static int GetFrameTile(const WebPMux* mux,
// Read and process config. // Read and process config.
static int Process(const WebPMuxConfig* config) { static int Process(const WebPMuxConfig* config) {
WebPMux* mux = NULL; WebPMux* mux = NULL;
WebPData metadata, color_profile; WebPData chunk;
WebPMuxError err = WEBP_MUX_OK; WebPMuxError err = WEBP_MUX_OK;
int index = 0; int index = 0;
int ok = 1; int ok = 1;
@ -735,28 +765,20 @@ static int Process(const WebPMuxConfig* config) {
if (!ok) goto Err2; if (!ok) goto Err2;
switch (feature->type_) { switch (feature->type_) {
case FEATURE_FRM: case FEATURE_FRM:
ok = GetFrameTile(mux, config, 1);
break;
case FEATURE_TILE: case FEATURE_TILE:
ok = GetFrameTile(mux, config, 0); ok = GetFrameTile(mux, config,
(feature->type_ == FEATURE_FRM) ? 1 : 0);
break; break;
case FEATURE_ICCP: case FEATURE_ICCP:
err = WebPMuxGetChunk(mux, "ICCP", &color_profile); case FEATURE_EXIF:
case FEATURE_XMP:
err = WebPMuxGetChunk(mux, kFourccList[feature->type_], &chunk);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not get color profile.\n", ERROR_GOTO3("ERROR (%s): Could not get the %s.\n",
ErrorString(err), Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
ok = WriteData(config->output_, &color_profile); ok = WriteData(config->output_, &chunk);
break;
case FEATURE_META:
err = WebPMuxGetChunk(mux, "META", &metadata);
if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not get the metadata.\n",
ErrorString(err), Err2);
}
ok = WriteData(config->output_, &metadata);
break; break;
default: default:
@ -834,28 +856,17 @@ static int Process(const WebPMuxConfig* config) {
break; break;
case FEATURE_ICCP: case FEATURE_ICCP:
case FEATURE_EXIF:
case FEATURE_XMP:
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
ok = ReadFileToWebPData(feature->args_[0].filename_, &color_profile); ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk);
if (!ok) goto Err2; if (!ok) goto Err2;
err = WebPMuxSetChunk(mux, "ICCP", &color_profile, 1); err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1);
free((void*)color_profile.bytes); free((void*)chunk.bytes);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not set color profile.\n", ERROR_GOTO3("ERROR (%s): Could not set the %s.\n",
ErrorString(err), Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
}
break;
case FEATURE_META:
ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2;
ok = ReadFileToWebPData(feature->args_[0].filename_, &metadata);
if (!ok) goto Err2;
err = WebPMuxSetChunk(mux, "META", &metadata, 1);
free((void*)metadata.bytes);
if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not set the metadata.\n",
ErrorString(err), Err2);
} }
break; break;
@ -869,22 +880,14 @@ static int Process(const WebPMuxConfig* config) {
case ACTION_STRIP: case ACTION_STRIP:
ok = CreateMux(config->input_, &mux); ok = CreateMux(config->input_, &mux);
if (!ok) goto Err2; if (!ok) goto Err2;
switch (feature->type_) { if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF ||
case FEATURE_ICCP: feature->type_ == FEATURE_XMP) {
err = WebPMuxDeleteChunk(mux, "ICCP"); err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]);
if (err != WEBP_MUX_OK) { if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not delete color profile.\n", ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n",
ErrorString(err), Err2); ErrorString(err), kDescriptions[feature->type_], Err2);
} }
break; } else {
case FEATURE_META:
err = WebPMuxDeleteChunk(mux, "META");
if (err != WEBP_MUX_OK) {
ERROR_GOTO2("ERROR (%s): Could not delete the metadata.\n",
ErrorString(err), Err2);
}
break;
default:
ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2); ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2);
break; break;
} }

View File

@ -48,10 +48,13 @@ and extract/strip relevant data from the container file.
.SS GET_OPTIONS (\-get): .SS GET_OPTIONS (\-get):
.TP .TP
.B icc .B icc
Get ICC Color profile. Get ICC profile.
.TP .TP
.B meta .B exif
Get XMP/EXIF metadata. Get EXIF metadata.
.TP
.B xmp
Get XMP metadata.
.TP .TP
.B tile n .B tile n
Get nth tile. Get nth tile.
@ -62,33 +65,41 @@ Get nth frame.
.SS SET_OPTIONS (\-set) .SS SET_OPTIONS (\-set)
.TP .TP
.B icc file.icc .B icc file.icc
Set ICC Color profile. Set ICC profile.
.P .P
Where: 'file.icc' contains the color profile to be set. Where: 'file.icc' contains the ICC profile to be set.
.TP .TP
.B meta file.meta .B exif file.exif
Set XMP/EXIF metadata. Set EXIF metadata.
.P .P
Where: 'file.meta' contains the metadata to be set. Where: 'file.exif' contains the EXIF metadata to be set.
.TP
.B xmp file.xmp
Set XMP metadata.
.P
Where: 'file.xmp' contains the XMP metadata to be set.
.SS STRIP_OPTIONS (\-strip) .SS STRIP_OPTIONS (\-strip)
.TP .TP
.B icc .B icc
Strip ICC Color profile. Strip ICC profile.
.TP .TP
.B meta .B exif
Strip XMP/EXIF metadata. Strip EXIF metadata.
.TP
.B xmp
Strip XMP metadata.
.SS TILE_OPTIONS (\-tile) .SS TILE_OPTIONS (\-tile)
.TP .TP
.B file_i +xi+yi .B file_i +xi+yi
Where: 'file_i' is the i'th tile (webp format) and 'xi','yi' specify the image Where: 'file_i' is the i'th tile (WebP format) and 'xi','yi' specify the image
offset for this tile. offset for this tile.
.SS FRAME_OPTIONS (\-frame) .SS FRAME_OPTIONS (\-frame)
.TP .TP
.B file_i +xi+yi+di .B file_i +xi+yi+di
Where: 'file_i' is the i'th frame (webp format), 'xi','yi' specify the image Where: 'file_i' is the i'th frame (WebP format), 'xi','yi' specify the image
offset for this frame and 'di' is the pause duration before next frame. offset for this frame and 'di' is the pause duration before next frame.
.TP .TP
.B \-loop n .B \-loop n
@ -102,6 +113,10 @@ Input file in WebP format.
.TP .TP
Output file in WebP format. Output file in WebP format.
.SS Note:
.TP
The nature of EXIF, XMP and ICC data is not checked and is assumed to be valid.
.SH BUGS .SH BUGS
Please report all bugs to our issue tracker: Please report all bugs to our issue tracker:
http://code.google.com/p/webp/issues http://code.google.com/p/webp/issues
@ -114,14 +129,29 @@ webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp
.br .br
webpmux \-get icc icc_container.webp \-o image_profile.icc webpmux \-get icc icc_container.webp \-o image_profile.icc
.br .br
webpmux \-set meta image_metadata.meta in.webp \-o meta_container.webp webpmux \-strip icc icc_container.webp \-o without_icc.webp
.br .br
webpmux \-get meta meta_container.webp \-o image_metadata.meta webpmux \-set xmp image_metadata.xmp in.webp \-o xmp_container.webp
.br
webpmux \-get xmp xmp_container.webp \-o image_metadata.xmp
.br
webpmux \-strip xmp xmp_container.webp \-o without_xmp.webp
.br
webpmux \-set exif image_metadata.exif in.webp \-o exif_container.webp
.br
webpmux \-get exif exif_container.webp \-o image_metadata.exif
.br
webpmux \-strip exif exif_container.webp \-o without_exif.webp
.br .br
webpmux \-frame anim_1.webp +0+0+0 \-frame anim_2.webp +50+50+0 \-loop 10 webpmux \-frame anim_1.webp +0+0+0 \-frame anim_2.webp +50+50+0 \-loop 10
\-o anim_container.webp \-o anim_container.webp
.br .br
webpmux \-get frame 2 anim_container.webp \-o frame_2.webp webpmux \-get frame 2 anim_container.webp \-o frame_2.webp
.br
webpmux \-tile tile_1.webp +0+0 \-tile tile_2.webp +960+0 \-tile tile_3.webp
+0+576 \-tile tile_4.webp +960+576 \-o tile_container.webp
.br
webpmux \-get tile 2 tile_container.webp \-o tile_2.webp
.SH AUTHORS .SH AUTHORS
\fBwebpmux\fP is written by the WebP team. \fBwebpmux\fP is written by the WebP team.

View File

@ -41,7 +41,7 @@ extern "C" {
// 24..26 Width of the Canvas Image. // 24..26 Width of the Canvas Image.
// 27..29 Height of the Canvas Image. // 27..29 Height of the Canvas Image.
// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
// META ...) // XMP, EXIF ...)
// All sizes are in little-endian order. // All sizes are in little-endian order.
// Note: chunk data size must be padded to multiple of 2 when written. // Note: chunk data size must be padded to multiple of 2 when written.

View File

@ -514,8 +514,12 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
goto Skip; goto Skip;
} }
case MKFOURCC('M', 'E', 'T', 'A'): { case MKFOURCC('X', 'M', 'P', ' '): {
store_chunk = !!(dmux->feature_flags_ & META_FLAG); store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
goto Skip;
}
case MKFOURCC('E', 'X', 'I', 'F'): {
store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
goto Skip; goto Skip;
} }
Skip: Skip:

View File

@ -48,7 +48,8 @@ static void MuxRelease(WebPMux* const mux) {
DeleteAllChunks(&mux->vp8x_); DeleteAllChunks(&mux->vp8x_);
DeleteAllChunks(&mux->iccp_); DeleteAllChunks(&mux->iccp_);
DeleteAllChunks(&mux->loop_); DeleteAllChunks(&mux->loop_);
DeleteAllChunks(&mux->meta_); DeleteAllChunks(&mux->exif_);
DeleteAllChunks(&mux->xmp_);
DeleteAllChunks(&mux->unknown_); DeleteAllChunks(&mux->unknown_);
} }
@ -82,7 +83,8 @@ static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth,
SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_); SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_);
SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_); SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_);
SWITCH_ID_LIST(IDX_LOOP, &mux->loop_); SWITCH_ID_LIST(IDX_LOOP, &mux->loop_);
SWITCH_ID_LIST(IDX_META, &mux->meta_); SWITCH_ID_LIST(IDX_EXIF, &mux->exif_);
SWITCH_ID_LIST(IDX_XMP, &mux->xmp_);
if (idx == IDX_UNKNOWN && data->size > TAG_SIZE) { if (idx == IDX_UNKNOWN && data->size > TAG_SIZE) {
// For raw-data unknown chunk, the first four bytes should be the tag to be // For raw-data unknown chunk, the first four bytes should be the tag to be
// used for the chunk. // used for the chunk.
@ -529,11 +531,12 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) { if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) {
flags |= ICCP_FLAG; flags |= ICCP_FLAG;
} }
if (mux->exif_ != NULL && mux->exif_->data_.bytes != NULL) {
if (mux->meta_ != NULL && mux->meta_->data_.bytes != NULL) { flags |= EXIF_FLAG;
flags |= META_FLAG; }
if (mux->xmp_ != NULL && mux->xmp_->data_.bytes != NULL) {
flags |= XMP_FLAG;
} }
if (images->header_ != NULL) { if (images->header_ != NULL) {
if (images->header_->tag_ == kChunks[IDX_FRGM].tag) { if (images->header_->tag_ == kChunks[IDX_FRGM].tag) {
// This is a tiled image. // This is a tiled image.
@ -543,7 +546,6 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
flags |= ANIMATION_FLAG; flags |= ANIMATION_FLAG;
} }
} }
if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) {
flags |= ALPHA_FLAG; // Some images have an alpha channel. flags |= ALPHA_FLAG; // Some images have an alpha channel.
} }
@ -610,8 +612,8 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
// Allocate data. // Allocate data.
size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_)
+ ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
+ ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) + ChunksListDiskSize(mux->exif_) + ChunksListDiskSize(mux->xmp_)
+ RIFF_HEADER_SIZE; + ChunksListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE;
data = (uint8_t*)malloc(size); data = (uint8_t*)malloc(size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR; if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
@ -622,7 +624,8 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
dst = ChunkListEmit(mux->iccp_, dst); dst = ChunkListEmit(mux->iccp_, dst);
dst = ChunkListEmit(mux->loop_, dst); dst = ChunkListEmit(mux->loop_, dst);
dst = MuxImageListEmit(mux->images_, dst); dst = MuxImageListEmit(mux->images_, dst);
dst = ChunkListEmit(mux->meta_, dst); dst = ChunkListEmit(mux->exif_, dst);
dst = ChunkListEmit(mux->xmp_, dst);
dst = ChunkListEmit(mux->unknown_, dst); dst = ChunkListEmit(mux->unknown_, dst);
assert(dst == data + size); assert(dst == data + size);

View File

@ -51,7 +51,8 @@ struct WebPMuxImage {
struct WebPMux { struct WebPMux {
WebPMuxImage* images_; WebPMuxImage* images_;
WebPChunk* iccp_; WebPChunk* iccp_;
WebPChunk* meta_; WebPChunk* exif_;
WebPChunk* xmp_;
WebPChunk* loop_; WebPChunk* loop_;
WebPChunk* vp8x_; WebPChunk* vp8x_;
@ -71,7 +72,8 @@ typedef enum {
IDX_ALPHA, IDX_ALPHA,
IDX_VP8, IDX_VP8,
IDX_VP8L, IDX_VP8L,
IDX_META, IDX_EXIF,
IDX_XMP,
IDX_UNKNOWN, IDX_UNKNOWN,
IDX_NIL, IDX_NIL,

View File

@ -28,7 +28,8 @@ const ChunkInfo kChunks[] = {
{ MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE }, { MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
{ NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE } { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
@ -446,7 +447,8 @@ WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_; case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_;
case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_; case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_;
case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_; case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_;
case WEBP_CHUNK_META: return (WebPChunk**)&mux->meta_; case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_;
case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_;
case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_; case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_;
default: return NULL; default: return NULL;
} }
@ -495,7 +497,8 @@ static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
WebPMuxError MuxValidate(const WebPMux* const mux) { WebPMuxError MuxValidate(const WebPMux* const mux) {
int num_iccp; int num_iccp;
int num_meta; int num_exif;
int num_xmp;
int num_loop_chunks; int num_loop_chunks;
int num_frames; int num_frames;
int num_tiles; int num_tiles;
@ -518,8 +521,12 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
// At most one EXIF metadata.
err = ValidateChunk(mux, IDX_EXIF, EXIF_FLAG, flags, 1, &num_exif);
if (err != WEBP_MUX_OK) return err;
// At most one XMP metadata. // At most one XMP metadata.
err = ValidateChunk(mux, IDX_META, META_FLAG, flags, 1, &num_meta); err = ValidateChunk(mux, IDX_XMP, XMP_FLAG, flags, 1, &num_xmp);
if (err != WEBP_MUX_OK) return err; if (err != WEBP_MUX_OK) return err;
// Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent. // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent.

View File

@ -42,7 +42,8 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_); SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_);
SWITCH_ID_LIST(IDX_ICCP, mux->iccp_); SWITCH_ID_LIST(IDX_ICCP, mux->iccp_);
SWITCH_ID_LIST(IDX_LOOP, mux->loop_); SWITCH_ID_LIST(IDX_LOOP, mux->loop_);
SWITCH_ID_LIST(IDX_META, mux->meta_); SWITCH_ID_LIST(IDX_EXIF, mux->exif_);
SWITCH_ID_LIST(IDX_XMP, mux->xmp_);
SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_); SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_);
return WEBP_MUX_NOT_FOUND; return WEBP_MUX_NOT_FOUND;
} }

View File

@ -70,12 +70,14 @@ typedef enum {
#define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk. #define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk.
#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used. // VP8X Feature Flags. These should be the same as the corresponding values in
#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected // the 'WebPFeatureFlags' enum defined in mux.h.
#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not. #define FRAGMENTS_FLAG_BIT 0x01
#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present. #define ANIMATION_FLAG_BIT 0x02
#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h #define XMP_FLAG_BIT 0x04
#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry #define EXIF_FLAG_BIT 0x08
#define ALPHA_FLAG_BIT 0x10
#define ICC_FLAG_BIT 0x20
#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height. #define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. #define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.

View File

@ -11,7 +11,7 @@
// Vikas (vikasa@google.com) // Vikas (vikasa@google.com)
// This API allows manipulation of WebP container images containing features // This API allows manipulation of WebP container images containing features
// like Color profile, XMP metadata, Animation and Tiling. // like color profile, metadata, animation and tiling.
// //
// Code Example#1: Creating a MUX with image data, color profile and XMP // Code Example#1: Creating a MUX with image data, color profile and XMP
// metadata. // metadata.
@ -23,7 +23,7 @@
// // ... (Prepare ICCP color profile data). // // ... (Prepare ICCP color profile data).
// WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); // WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
// // ... (Prepare XMP metadata). // // ... (Prepare XMP metadata).
// WebPMuxSetChunk(mux, "META", &xmp, copy_data); // WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
// // Get data from mux in WebP RIFF format. // // Get data from mux in WebP RIFF format.
// WebPMuxAssemble(mux, &output_data); // WebPMuxAssemble(mux, &output_data);
// WebPMuxDelete(mux); // WebPMuxDelete(mux);
@ -84,9 +84,10 @@ enum WebPMuxError {
enum WebPFeatureFlags { enum WebPFeatureFlags {
TILE_FLAG = 0x00000001, TILE_FLAG = 0x00000001,
ANIMATION_FLAG = 0x00000002, ANIMATION_FLAG = 0x00000002,
ICCP_FLAG = 0x00000004, XMP_FLAG = 0x00000004,
META_FLAG = 0x00000008, EXIF_FLAG = 0x00000008,
ALPHA_FLAG = 0x00000010 ALPHA_FLAG = 0x00000010,
ICCP_FLAG = 0x00000020
}; };
// IDs for different types of chunks. // IDs for different types of chunks.
@ -98,7 +99,8 @@ enum WebPChunkId {
WEBP_CHUNK_FRGM, // FRGM WEBP_CHUNK_FRGM, // FRGM
WEBP_CHUNK_ALPHA, // ALPH WEBP_CHUNK_ALPHA, // ALPH
WEBP_CHUNK_IMAGE, // VP8/VP8L WEBP_CHUNK_IMAGE, // VP8/VP8L
WEBP_CHUNK_META, // META WEBP_CHUNK_EXIF, // EXIF
WEBP_CHUNK_XMP, // XMP
WEBP_CHUNK_UNKNOWN, // Other chunks. WEBP_CHUNK_UNKNOWN, // Other chunks.
WEBP_CHUNK_NIL WEBP_CHUNK_NIL
}; };
@ -174,7 +176,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
// Parameters: // Parameters:
// mux - (in/out) object to which the chunk is to be added // mux - (in/out) object to which the chunk is to be added
// fourcc - (in) a character array containing the fourcc of the given chunk; // fourcc - (in) a character array containing the fourcc of the given chunk;
// e.g., "ICCP", "META" etc. // e.g., "ICCP", "XMP ", "EXIF" etc.
// chunk_data - (in) the chunk data to be added // chunk_data - (in) the chunk data to be added
// copy_data - (in) value 1 indicates given data WILL be copied to the mux // copy_data - (in) value 1 indicates given data WILL be copied to the mux
// and value 0 indicates data will NOT be copied. // and value 0 indicates data will NOT be copied.
@ -192,7 +194,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
// Parameters: // Parameters:
// mux - (in) object from which the chunk data is to be fetched // mux - (in) object from which the chunk data is to be fetched
// fourcc - (in) a character array containing the fourcc of the chunk; // fourcc - (in) a character array containing the fourcc of the chunk;
// e.g., "ICCP", "META" etc. // e.g., "ICCP", "XMP ", "EXIF" etc.
// chunk_data - (out) returned chunk data // chunk_data - (out) returned chunk data
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if either mux, fourcc or chunk_data is NULL // WEBP_MUX_INVALID_ARGUMENT - if either mux, fourcc or chunk_data is NULL
@ -206,7 +208,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
// Parameters: // Parameters:
// mux - (in/out) object from which the chunk is to be deleted // mux - (in/out) object from which the chunk is to be deleted
// fourcc - (in) a character array containing the fourcc of the chunk; // fourcc - (in) a character array containing the fourcc of the chunk;
// e.g., "ICCP", "META" etc. // e.g., "ICCP", "XMP ", "EXIF" etc.
// Returns: // Returns:
// WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL // WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL
// or if fourcc corresponds to an image chunk. // or if fourcc corresponds to an image chunk.
@ -481,7 +483,7 @@ struct WebPChunkIterator {
// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from // Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from
// 'dmux'. // 'dmux'.
// 'fourcc' is a character array containing the fourcc of the chunk to return, // 'fourcc' is a character array containing the fourcc of the chunk to return,
// e.g., "ICCP", "META", "EXIF", etc. // e.g., "ICCP", "XMP ", "EXIF", etc.
// Setting 'chunk_number' equal to 0 will return the last chunk in a set. // Setting 'chunk_number' equal to 0 will return the last chunk in a set.
// Returns true if the chunk is found, false otherwise. Image related chunk // Returns true if the chunk is found, false otherwise. Image related chunk
// payloads are accessed through WebPDemuxGetFrame() and related functions. // payloads are accessed through WebPDemuxGetFrame() and related functions.