From 74356eb558cca11e13f7a2d7493c14d249d29502 Mon Sep 17 00:00:00 2001 From: Urvang Joshi Date: Wed, 7 Nov 2012 13:16:09 -0800 Subject: [PATCH] Add a simple cleanup step in mux assembly: In particular, this removes any unnecessary FRGM/ANMF/ANIM chunks, and indirectly leads to removal of unnecessary VP8X chunks as well. This is especially useful for GIF to WebP conversion - it saves 56 bytes (ANMF: 16+8 bytes, ANIM: 6+8 bytes, VP8X: 10+8 bytes) for non-animated GIFs. Change-Id: I3b50a96ca585844c421b0fa4cd8593e52c3f95c5 --- src/mux/muxedit.c | 54 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index e84a89fa..fd79e733 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -585,31 +585,55 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { return err; } +// Cleans up 'mux' by removing any unnecessary chunks. +static WebPMuxError MuxCleanup(WebPMux* const mux) { + int num_frames; + int num_fragments; + int num_anim_chunks; + + // If we have an image with single fragment or frame, convert it to a + // non-animated non-fragmented image (to avoid writing FRGM/ANMF chunk + // unnecessarily). + WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames); + if (err != WEBP_MUX_OK) return err; + err = WebPMuxNumChunks(mux, kChunks[IDX_FRGM].id, &num_fragments); + if (err != WEBP_MUX_OK) return err; + if (num_frames == 1 || num_fragments == 1) { + WebPMuxImage* frame_frag; + err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame_frag); + assert(err == WEBP_MUX_OK); // We know that one frame/fragment does exist. + if (frame_frag->header_ != NULL) { + assert(frame_frag->header_->tag_ == kChunks[IDX_ANMF].tag || + frame_frag->header_->tag_ == kChunks[IDX_FRGM].tag); + ChunkDelete(frame_frag->header_); // Removes ANMF/FRGM chunk. + frame_frag->header_ = NULL; + } + num_frames = 0; + num_fragments = 0; + } + // Remove ANIM chunk if this is a non-animated image. + err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks); + if (err != WEBP_MUX_OK) return err; + if (num_anim_chunks >= 1 && num_frames == 0) { + err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); + if (err != WEBP_MUX_OK) return err; + } + return WEBP_MUX_OK; +} + WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { size_t size = 0; uint8_t* data = NULL; uint8_t* dst = NULL; - int num_frames; - int num_anim_chunks; WebPMuxError err; if (mux == NULL || assembled_data == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } - // Remove ANIM chunk if unnecessary. - err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks); + // Finalize mux. + err = MuxCleanup(mux); if (err != WEBP_MUX_OK) return err; - if (num_anim_chunks >= 1) { - err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames); - if (err != WEBP_MUX_OK) return err; - if (num_frames == 0) { - err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag); - if (err != WEBP_MUX_OK) return err; - } - } - - // Create VP8X chunk. err = CreateVP8XChunk(mux); if (err != WEBP_MUX_OK) return err; @@ -641,7 +665,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) { size = 0; } - // Finalize. + // Finalize data. assembled_data->bytes = data; assembled_data->size = size;