diff --git a/examples/webpmux.c b/examples/webpmux.c index bccd5c64..e8afe3ad 100644 --- a/examples/webpmux.c +++ b/examples/webpmux.c @@ -430,6 +430,8 @@ static int ParseFrameArgs(const char* args, WebPMuxFrameInfo* const info) { // Note: The sanity of the following conversion is checked by // WebPMuxSetAnimationParams(). info->dispose_method = (WebPMuxAnimDispose)dispose_method; + // TODO(urvang): Add support for parsing blending method too. + info->blend_method = WEBP_MUX_BLEND; return 1; } diff --git a/src/demux/demux.c b/src/demux/demux.c index 8711baa3..7b20487a 100644 --- a/src/demux/demux.c +++ b/src/demux/demux.c @@ -50,6 +50,7 @@ typedef struct Frame { int has_alpha_; int duration_; WebPMuxAnimDispose dispose_method_; + WebPMuxAnimBlend blend_method_; int is_fragment_; // this is a frame fragment (and not a full frame). int frame_num_; // the referent frame number for use in assembling fragments. int complete_; // img_components_ contains a full image. @@ -303,6 +304,7 @@ static ParseStatus ParseAnimationFrame( const int has_frames = !!(dmux->feature_flags_ & ANIMATION_FLAG); const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE; int added_frame = 0; + int bits; MemBuffer* const mem = &dmux->mem_; Frame* frame; ParseStatus status = @@ -314,7 +316,10 @@ static ParseStatus ParseAnimationFrame( frame->width_ = 1 + ReadLE24s(mem); frame->height_ = 1 + ReadLE24s(mem); frame->duration_ = ReadLE24s(mem); - frame->dispose_method_ = (WebPMuxAnimDispose)(ReadByte(mem) & 1); + bits = ReadByte(mem); + frame->dispose_method_ = + (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; + frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) { free(frame); return PARSE_ERROR; @@ -845,6 +850,7 @@ static int SynthesizeFrame(const WebPDemuxer* const dmux, iter->has_alpha = fragment->has_alpha_; iter->duration = fragment->duration_; iter->dispose_method = fragment->dispose_method_; + iter->blend_method = fragment->blend_method_; iter->complete = fragment->complete_; iter->fragment.bytes = payload; iter->fragment.size = payload_size; diff --git a/src/mux/muxedit.c b/src/mux/muxedit.c index 1cbfb216..21ddaf8d 100644 --- a/src/mux/muxedit.c +++ b/src/mux/muxedit.c @@ -116,7 +116,9 @@ static WebPMuxError CreateFrameFragmentData( PutLE24(frame_frgm_bytes + 6, width - 1); PutLE24(frame_frgm_bytes + 9, height - 1); PutLE24(frame_frgm_bytes + 12, info->duration); - frame_frgm_bytes[15] = (info->dispose_method & 1); + frame_frgm_bytes[15] = + (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) | + (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0); } frame_frgm->bytes = frame_frgm_bytes; @@ -310,7 +312,8 @@ WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame, tmp.y_offset &= ~1; if (!is_frame) { // Reset unused values. tmp.duration = 1; - tmp.dispose_method = 0; + tmp.dispose_method = WEBP_MUX_DISPOSE_NONE; + tmp.blend_method = WEBP_MUX_BLEND; } if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET || tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET || diff --git a/src/mux/muxread.c b/src/mux/muxread.c index 03259d9d..39d07d43 100644 --- a/src/mux/muxread.c +++ b/src/mux/muxread.c @@ -426,6 +426,8 @@ static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi, info->x_offset = 0; info->y_offset = 0; info->duration = 1; + info->dispose_method = WEBP_MUX_DISPOSE_NONE; + info->blend_method = WEBP_MUX_BLEND; // Extract data for related fields. info->id = ChunkGetIdFromTag(wpi->img_->tag_); return SynthesizeBitstream(wpi, &info->bitstream); @@ -446,10 +448,17 @@ static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi, // Extract info. frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0); frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3); - frame->duration = is_frame ? GetLE24(frame_frgm_data->bytes + 12) : 1; - frame->dispose_method = - is_frame ? (WebPMuxAnimDispose)(frame_frgm_data->bytes[15] & 1) - : WEBP_MUX_DISPOSE_NONE; + if (is_frame) { + const uint8_t bits = frame_frgm_data->bytes[15]; + frame->duration = GetLE24(frame_frgm_data->bytes + 12); + frame->dispose_method = + (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE; + frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND; + } else { // Defaults for unused values. + frame->duration = 1; + frame->dispose_method = WEBP_MUX_DISPOSE_NONE; + frame->blend_method = WEBP_MUX_BLEND; + } frame->id = ChunkGetIdFromTag(wpi->header_->tag_); return SynthesizeBitstream(wpi, &frame->bitstream); } diff --git a/src/webp/demux.h b/src/webp/demux.h index f9b3fd1e..670adbe7 100644 --- a/src/webp/demux.h +++ b/src/webp/demux.h @@ -140,8 +140,9 @@ struct WebPIterator { WebPData fragment; // The frame or fragment given by 'frame_num' and // 'fragment_num'. int has_alpha; // True if the frame or fragment contains transparency. + WebPMuxAnimBlend blend_method; // Blend operation for the frame. - uint32_t pad[3]; // padding for later use. + uint32_t pad[2]; // padding for later use. void* private_; // for internal use only. }; diff --git a/src/webp/mux.h b/src/webp/mux.h index 864c0cce..e31242f2 100644 --- a/src/webp/mux.h +++ b/src/webp/mux.h @@ -199,7 +199,8 @@ struct WebPMuxFrameInfo { WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF, // WEBP_CHUNK_FRGM or WEBP_CHUNK_IMAGE WebPMuxAnimDispose dispose_method; // Disposal method for the frame. - uint32_t pad[2]; // padding for later use + WebPMuxAnimBlend blend_method; // Blend operation for the frame. + uint32_t pad[1]; // padding for later use }; // Sets the (non-animated and non-fragmented) image in the mux object. diff --git a/src/webp/mux_types.h b/src/webp/mux_types.h index b8bce363..94d8806e 100644 --- a/src/webp/mux_types.h +++ b/src/webp/mux_types.h @@ -26,6 +26,7 @@ extern "C" { // the types are left here for reference. // typedef enum WebPFeatureFlags WebPFeatureFlags; // typedef enum WebPMuxAnimDispose WebPMuxAnimDispose; +// typedef enum WebPMuxAnimBlend WebPMuxAnimBlend; typedef struct WebPData WebPData; // VP8X Feature Flags. @@ -45,6 +46,13 @@ typedef enum WebPMuxAnimDispose { WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color. } WebPMuxAnimDispose; +// Blend operation (animation only). Indicates how transparent pixels of the +// current frame are blended with those of the previous canvas. +typedef enum WebPMuxAnimBlend { + WEBP_MUX_BLEND, // Blend. + WEBP_MUX_NO_BLEND // Do not blend. +} WebPMuxAnimBlend; + // Data type used to describe 'raw' data, e.g., chunk data // (ICC profile, metadata) and WebP compressed image data. struct WebPData {