diff --git a/README.mux b/README.mux index 74c8e930..184fb429 100644 --- a/README.mux +++ b/README.mux @@ -8,7 +8,7 @@ Description: ============ 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' are also provided in this package. @@ -32,56 +32,63 @@ Usage: webpmux -get GET_OPTIONS INPUT -o OUTPUT GET_OPTIONS: Extract relevant data. - icc Get ICCP Color profile. - meta Get XMP/EXIF metadata. + icc Get ICC profile. + exif Get EXIF metadata. + xmp Get XMP metadata. tile n Get nth tile. frame n Get nth frame. SET_OPTIONS: Set color profile/metadata. - icc file.icc Set ICC Color profile. - meta file.meta Set XMP/EXIF metadata. - where: 'file.icc' contains the color profile to be set, - 'file.meta' contains the metadata to be set + icc file.icc Set ICC profile. + exif file.exif Set EXIF metadata. + xmp file.xmp Set XMP metadata. + 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 color profile/metadata. - icc Strip ICCP color profile. - meta Strip XMP/EXIF metadata. + icc Strip ICC profile. + exif Strip EXIF metadata. + xmp Strip XMP metadata. TILE_OPTIONS(i): Create tiled image. 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. FRAME_OPTIONS(i): Create animation. 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. '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: ============== 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 -metadata, ICC color profile, animation & tiling. Other features will be added in -subsequent releases. +metadata, ICC profile, animation and tiling. Other features will be added +in subsequent releases. Example#1 (pseudo code): Creating a WebPMux object with image data, color -profile & XMP metadata. +profile and XMP metadata. int copy_data = 0; WebPMux* mux = WebPMuxNew(); // ... (Prepare image data). WebPMuxSetImage(mux, &image, copy_data); - // ... (Prepare ICCP color profile data). + // ... (Prepare ICC profile data). WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); // ... (Prepare XMP metadata). - WebPMuxSetChunk(mux, "META", &xmp, copy_data); + WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); // Get data from mux in WebP RIFF format. WebPMuxAssemble(mux, &output_data); WebPMuxDelete(mux); @@ -89,7 +96,7 @@ profile & XMP metadata. 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; // ... (Read data from file). diff --git a/examples/webpmux.c b/examples/webpmux.c index c2dd11d8..3ad753fe 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -31,17 +31,20 @@ -o out_animation_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: webpmux -get tile n in.webp -o out_tile.webp webpmux -get frame n in.webp -o out_frame.webp 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: 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: webpmux -info in.webp @@ -81,12 +84,23 @@ typedef struct { typedef enum { NIL_FEATURE = 0, - FEATURE_META, + FEATURE_EXIF, + FEATURE_XMP, FEATURE_ICCP, FEATURE_FRM, - FEATURE_TILE + FEATURE_TILE, + LAST_FEATURE } 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 { FeatureType type_; FeatureArg* args_; @@ -185,7 +199,8 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { if (flag & ANIMATION_FLAG) printf(" animation"); if (flag & TILE_FLAG) printf(" tiling"); 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"); printf("\n"); @@ -226,15 +241,22 @@ static WebPMuxError DisplayInfo(const WebPMux* mux) { if (flag & ICCP_FLAG) { WebPData icc_profile; err = WebPMuxGetChunk(mux, "ICCP", &icc_profile); - RETURN_IF_ERROR("Failed to retrieve the color profile\n"); - printf("Size of the color profile data: %zu\n", icc_profile.size); + RETURN_IF_ERROR("Failed to retrieve the ICC profile\n"); + printf("Size of the ICC profile data: %zu\n", icc_profile.size); } - if (flag & META_FLAG) { - WebPData metadata; - err = WebPMuxGetChunk(mux, "META", &metadata); - RETURN_IF_ERROR("Failed to retrieve the metadata\n"); - printf("Size of the metadata: %zu\n", metadata.size); + if (flag & EXIF_FLAG) { + WebPData exif; + err = WebPMuxGetChunk(mux, "EXIF", &exif); + RETURN_IF_ERROR("Failed to retrieve the EXIF metadata\n"); + 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))) { @@ -260,41 +282,48 @@ static void PrintHelp(void) { printf("\n"); printf("GET_OPTIONS:\n"); printf(" Extract relevant data.\n"); - printf(" icc Get ICCP Color profile.\n"); - printf(" meta Get XMP/EXIF metadata.\n"); + printf(" icc Get ICC profile.\n"); + printf(" exif Get EXIF metadata.\n"); + printf(" xmp Get XMP metadata.\n"); printf(" tile n Get nth tile.\n"); printf(" frame n Get nth frame.\n"); printf("\n"); printf("SET_OPTIONS:\n"); printf(" Set color profile/metadata.\n"); - printf(" icc file.icc Set ICC Color profile.\n"); - printf(" meta file.meta Set XMP/EXIF metadata.\n"); - printf(" where: 'file.icc' contains the color profile to be set,\n"); - printf(" 'file.meta' contains the metadata to be set\n"); + printf(" icc file.icc Set ICC profile.\n"); + printf(" exif file.exif Set EXIF metadata.\n"); + printf(" xmp file.xmp Set XMP metadata.\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("STRIP_OPTIONS:\n"); printf(" Strip color profile/metadata.\n"); - printf(" icc Strip ICCP color profile.\n"); - printf(" meta Strip XMP/EXIF metadata.\n"); + printf(" icc Strip ICC profile.\n"); + printf(" exif Strip EXIF metadata.\n"); + printf(" xmp Strip XMP metadata.\n"); printf("\n"); printf("TILE_OPTIONS(i):\n"); printf(" Create tiled image.\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("\n"); printf("FRAME_OPTIONS(i):\n"); printf(" Create animation.\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(" '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, @@ -421,7 +450,7 @@ static int ValidateCommandLine(int argc, const char* argv[], assert(ok == 1); 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; } else { // 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", 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) { feature->type_ = (!strcmp(argv[i], "icc")) ? FEATURE_ICCP : - FEATURE_META; + (!strcmp(argv[i], "exif")) ? FEATURE_EXIF : FEATURE_XMP; } else { ERROR_GOTO1("ERROR: Multiple features specified.\n", ErrParse); } @@ -723,7 +753,7 @@ static int GetFrameTile(const WebPMux* mux, // Read and process config. static int Process(const WebPMuxConfig* config) { WebPMux* mux = NULL; - WebPData metadata, color_profile; + WebPData chunk; WebPMuxError err = WEBP_MUX_OK; int index = 0; int ok = 1; @@ -735,28 +765,20 @@ static int Process(const WebPMuxConfig* config) { if (!ok) goto Err2; switch (feature->type_) { case FEATURE_FRM: - ok = GetFrameTile(mux, config, 1); - break; - case FEATURE_TILE: - ok = GetFrameTile(mux, config, 0); + ok = GetFrameTile(mux, config, + (feature->type_ == FEATURE_FRM) ? 1 : 0); break; 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) { - ERROR_GOTO2("ERROR (%s): Could not get color profile.\n", - ErrorString(err), Err2); + ERROR_GOTO3("ERROR (%s): Could not get the %s.\n", + ErrorString(err), kDescriptions[feature->type_], Err2); } - ok = WriteData(config->output_, &color_profile); - 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); + ok = WriteData(config->output_, &chunk); break; default: @@ -834,28 +856,17 @@ static int Process(const WebPMuxConfig* config) { break; case FEATURE_ICCP: + case FEATURE_EXIF: + case FEATURE_XMP: ok = CreateMux(config->input_, &mux); if (!ok) goto Err2; - ok = ReadFileToWebPData(feature->args_[0].filename_, &color_profile); + ok = ReadFileToWebPData(feature->args_[0].filename_, &chunk); if (!ok) goto Err2; - err = WebPMuxSetChunk(mux, "ICCP", &color_profile, 1); - free((void*)color_profile.bytes); + err = WebPMuxSetChunk(mux, kFourccList[feature->type_], &chunk, 1); + free((void*)chunk.bytes); if (err != WEBP_MUX_OK) { - ERROR_GOTO2("ERROR (%s): Could not set color profile.\n", - ErrorString(err), 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); + ERROR_GOTO3("ERROR (%s): Could not set the %s.\n", + ErrorString(err), kDescriptions[feature->type_], Err2); } break; @@ -869,22 +880,14 @@ static int Process(const WebPMuxConfig* config) { case ACTION_STRIP: ok = CreateMux(config->input_, &mux); if (!ok) goto Err2; - switch (feature->type_) { - case FEATURE_ICCP: - err = WebPMuxDeleteChunk(mux, "ICCP"); - if (err != WEBP_MUX_OK) { - ERROR_GOTO2("ERROR (%s): Could not delete color profile.\n", - ErrorString(err), Err2); - } - break; - 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: + if (feature->type_ == FEATURE_ICCP || feature->type_ == FEATURE_EXIF || + feature->type_ == FEATURE_XMP) { + err = WebPMuxDeleteChunk(mux, kFourccList[feature->type_]); + if (err != WEBP_MUX_OK) { + ERROR_GOTO3("ERROR (%s): Could not strip the %s.\n", + ErrorString(err), kDescriptions[feature->type_], Err2); + } + } else { ERROR_GOTO1("ERROR: Invalid feature for action 'strip'.\n", Err2); break; } diff --git a/man/webpmux.1 b/man/webpmux.1 index 44b2982b..c60e89ad 100644 --- a/man/webpmux.1 +++ b/man/webpmux.1 @@ -48,10 +48,13 @@ and extract/strip relevant data from the container file. .SS GET_OPTIONS (\-get): .TP .B icc -Get ICC Color profile. +Get ICC profile. .TP -.B meta -Get XMP/EXIF metadata. +.B exif +Get EXIF metadata. +.TP +.B xmp +Get XMP metadata. .TP .B tile n Get nth tile. @@ -62,33 +65,41 @@ Get nth frame. .SS SET_OPTIONS (\-set) .TP .B icc file.icc -Set ICC Color profile. +Set ICC profile. .P -Where: 'file.icc' contains the color profile to be set. +Where: 'file.icc' contains the ICC profile to be set. .TP -.B meta file.meta -Set XMP/EXIF metadata. +.B exif file.exif +Set EXIF metadata. .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) .TP .B icc -Strip ICC Color profile. +Strip ICC profile. .TP -.B meta -Strip XMP/EXIF metadata. +.B exif +Strip EXIF metadata. +.TP +.B xmp +Strip XMP metadata. .SS TILE_OPTIONS (\-tile) .TP .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. .SS FRAME_OPTIONS (\-frame) .TP .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. .TP .B \-loop n @@ -102,6 +113,10 @@ Input file in WebP format. .TP 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 Please report all bugs to our issue tracker: http://code.google.com/p/webp/issues @@ -114,14 +129,29 @@ webpmux \-set icc image_profile.icc in.webp \-o icc_container.webp .br webpmux \-get icc icc_container.webp \-o image_profile.icc .br -webpmux \-set meta image_metadata.meta in.webp \-o meta_container.webp +webpmux \-strip icc icc_container.webp \-o without_icc.webp .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 webpmux \-frame anim_1.webp +0+0+0 \-frame anim_2.webp +50+50+0 \-loop 10 \-o anim_container.webp .br 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 \fBwebpmux\fP is written by the WebP team. diff --git a/src/dec/webp.c b/src/dec/webp.c index 7455da94..a29f92d9 100644 --- a/src/dec/webp.c +++ b/src/dec/webp.c @@ -41,7 +41,7 @@ extern "C" { // 24..26 Width of the Canvas Image. // 27..29 Height of the Canvas Image. // There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8, -// META ...) +// XMP, EXIF ...) // All sizes are in little-endian order. // Note: chunk data size must be padded to multiple of 2 when written. diff --git a/src/mux/demux.c b/src/mux/demux.c index 0643cbe0..4f7a5d37 100644 --- a/src/mux/demux.c +++ b/src/mux/demux.c @@ -514,8 +514,12 @@ static ParseStatus ParseVP8X(WebPDemuxer* const dmux) { store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG); goto Skip; } - case MKFOURCC('M', 'E', 'T', 'A'): { - store_chunk = !!(dmux->feature_flags_ & META_FLAG); + case MKFOURCC('X', 'M', 'P', ' '): { + store_chunk = !!(dmux->feature_flags_ & XMP_FLAG); + goto Skip; + } + case MKFOURCC('E', 'X', 'I', 'F'): { + store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG); goto Skip; } Skip: diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index f85500fa..82978533 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -48,7 +48,8 @@ static void MuxRelease(WebPMux* const mux) { DeleteAllChunks(&mux->vp8x_); DeleteAllChunks(&mux->iccp_); DeleteAllChunks(&mux->loop_); - DeleteAllChunks(&mux->meta_); + DeleteAllChunks(&mux->exif_); + DeleteAllChunks(&mux->xmp_); 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_ICCP, &mux->iccp_); 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) { // For raw-data unknown chunk, the first four bytes should be the tag to be // used for the chunk. @@ -529,11 +531,12 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) { flags |= ICCP_FLAG; } - - if (mux->meta_ != NULL && mux->meta_->data_.bytes != NULL) { - flags |= META_FLAG; + if (mux->exif_ != NULL && mux->exif_->data_.bytes != NULL) { + flags |= EXIF_FLAG; + } + if (mux->xmp_ != NULL && mux->xmp_->data_.bytes != NULL) { + flags |= XMP_FLAG; } - if (images->header_ != NULL) { if (images->header_->tag_ == kChunks[IDX_FRGM].tag) { // This is a tiled image. @@ -543,7 +546,6 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { flags |= ANIMATION_FLAG; } } - if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { flags |= ALPHA_FLAG; // Some images have an alpha channel. } @@ -610,8 +612,8 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { // Allocate data. size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_) + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_) - + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_) - + RIFF_HEADER_SIZE; + + ChunksListDiskSize(mux->exif_) + ChunksListDiskSize(mux->xmp_) + + ChunksListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE; data = (uint8_t*)malloc(size); 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->loop_, 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); assert(dst == data + size); diff --git a/src/mux/muxi.h b/src/mux/muxi.h index 64811624..60c43c45 100644 --- a/src/mux/muxi.h +++ b/src/mux/muxi.h @@ -51,7 +51,8 @@ struct WebPMuxImage { struct WebPMux { WebPMuxImage* images_; WebPChunk* iccp_; - WebPChunk* meta_; + WebPChunk* exif_; + WebPChunk* xmp_; WebPChunk* loop_; WebPChunk* vp8x_; @@ -71,7 +72,8 @@ typedef enum { IDX_ALPHA, IDX_VP8, IDX_VP8L, - IDX_META, + IDX_EXIF, + IDX_XMP, IDX_UNKNOWN, IDX_NIL, diff --git a/src/mux/muxinternal.c b/src/mux/muxinternal.c index 4e2e5e61..bddb1418 100644 --- a/src/mux/muxinternal.c +++ b/src/mux/muxinternal.c @@ -28,7 +28,8 @@ const ChunkInfo kChunks[] = { { 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', '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 }, { 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_ICCP: return (WebPChunk**)&mux->iccp_; 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_; default: return NULL; } @@ -495,7 +497,8 @@ static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx, WebPMuxError MuxValidate(const WebPMux* const mux) { int num_iccp; - int num_meta; + int num_exif; + int num_xmp; int num_loop_chunks; int num_frames; int num_tiles; @@ -518,8 +521,12 @@ WebPMuxError MuxValidate(const WebPMux* const mux) { err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp); 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. - 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; // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent. diff --git a/src/mux/muxread.c b/src/mux/muxread.c index fb83987c..e16f087d 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -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_ICCP, mux->iccp_); 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_); return WEBP_MUX_NOT_FOUND; } diff --git a/src/webp/format_constants.h b/src/webp/format_constants.h index 4accd83d..779932b0 100644 --- a/src/webp/format_constants.h +++ b/src/webp/format_constants.h @@ -70,12 +70,14 @@ typedef enum { #define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk. #define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk. -#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used. -#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected -#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not. -#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present. -#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h -#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry +// VP8X Feature Flags. These should be the same as the corresponding values in +// the 'WebPFeatureFlags' enum defined in mux.h. +#define FRAGMENTS_FLAG_BIT 0x01 +#define ANIMATION_FLAG_BIT 0x02 +#define XMP_FLAG_BIT 0x04 +#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_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height. diff --git a/src/webp/mux.h b/src/webp/mux.h index 41ea158d..62dc2afe 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -11,7 +11,7 @@ // Vikas (vikasa@google.com) // 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 // metadata. @@ -23,7 +23,7 @@ // // ... (Prepare ICCP color profile data). // WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data); // // ... (Prepare XMP metadata). -// WebPMuxSetChunk(mux, "META", &xmp, copy_data); +// WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data); // // Get data from mux in WebP RIFF format. // WebPMuxAssemble(mux, &output_data); // WebPMuxDelete(mux); @@ -84,9 +84,10 @@ enum WebPMuxError { enum WebPFeatureFlags { TILE_FLAG = 0x00000001, ANIMATION_FLAG = 0x00000002, - ICCP_FLAG = 0x00000004, - META_FLAG = 0x00000008, - ALPHA_FLAG = 0x00000010 + XMP_FLAG = 0x00000004, + EXIF_FLAG = 0x00000008, + ALPHA_FLAG = 0x00000010, + ICCP_FLAG = 0x00000020 }; // IDs for different types of chunks. @@ -98,7 +99,8 @@ enum WebPChunkId { WEBP_CHUNK_FRGM, // FRGM WEBP_CHUNK_ALPHA, // ALPH WEBP_CHUNK_IMAGE, // VP8/VP8L - WEBP_CHUNK_META, // META + WEBP_CHUNK_EXIF, // EXIF + WEBP_CHUNK_XMP, // XMP WEBP_CHUNK_UNKNOWN, // Other chunks. WEBP_CHUNK_NIL }; @@ -174,7 +176,7 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream, // Parameters: // mux - (in/out) object to which the chunk is to be added // 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 // copy_data - (in) value 1 indicates given data WILL be copied to the mux // and value 0 indicates data will NOT be copied. @@ -192,7 +194,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk( // Parameters: // mux - (in) object from which the chunk data is to be fetched // 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 // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux, fourcc or chunk_data is NULL @@ -206,7 +208,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk( // Parameters: // mux - (in/out) object from which the chunk is to be deleted // fourcc - (in) a character array containing the fourcc of the chunk; -// e.g., "ICCP", "META" etc. +// e.g., "ICCP", "XMP ", "EXIF" etc. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL // 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 // 'dmux'. // '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. // Returns true if the chunk is found, false otherwise. Image related chunk // payloads are accessed through WebPDemuxGetFrame() and related functions.