// VP8X format: // Total Size : 10, // Flags : 4 bytes, // Width : 3 bytes, // Height : 3 bytes. static WebPMuxError CreateVP8XChunk(WebPMux* const mux) { WebPMuxError err = WEBP_MUX_OK; uint32_t flags = 0; int width = 0; int height = 0; uint8_t data[VP8X_CHUNK_SIZE]; const WebPData vp8x = { data, VP8X_CHUNK_SIZE }; const WebPMuxImage* images = NULL; assert(mux != NULL); images = mux->images_; // First image. if (images == NULL || images->img_ == NULL || images->img_->data_.bytes == NULL) { return WEBP_MUX_INVALID_ARGUMENT; } // If VP8X chunk(s) is(are) already present, remove them (and later add new // VP8X chunk with updated flags). err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag); if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; // Set flags. if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) { flags |= ICCP_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 fragmented image. flags |= FRAGMENTS_FLAG; } else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) { // This is an image with animation. flags |= ANIMATION_FLAG; } } if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) { flags |= ALPHA_FLAG; // Some images have an alpha channel. } if (flags == 0) { // For Simple Image, VP8X chunk should not be added. return WEBP_MUX_OK; } err = GetImageCanvasWidthHeight(mux, flags, &width, &height); if (err != WEBP_MUX_OK) return err; if (width <= 0 || height <= 0) { return WEBP_MUX_INVALID_ARGUMENT; } if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) { return WEBP_MUX_INVALID_ARGUMENT; } if (MuxHasAlpha(images)) { // This means some frames explicitly/implicitly contain alpha. // Note: This 'flags' update must NOT be done for a lossless image // without a VP8X chunk! flags |= ALPHA_FLAG; } PutLE32(data + 0, flags); // VP8X chunk flags. PutLE24(data + 4, width - 1); // canvas width. PutLE24(data + 7, height - 1); // canvas height. return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1); }
WebPMuxError MuxValidate(const WebPMux* const mux) { int num_iccp; int num_exif; int num_xmp; int num_anim; int num_frames; int num_fragments; int num_vp8x; int num_images; int num_alpha; uint32_t flags; WebPMuxError err; // Verify mux is not NULL. if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT; // Verify mux has at least one image. if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT; err = WebPMuxGetFeatures(mux, &flags); if (err != WEBP_MUX_OK) return err; // At most one color profile chunk. 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_XMP, XMP_FLAG, flags, 1, &num_xmp); if (err != WEBP_MUX_OK) return err; // Animation: ANIMATION_FLAG, ANIM chunk and ANMF chunk(s) are consistent. // At most one ANIM chunk. err = ValidateChunk(mux, IDX_ANIM, NO_FLAG, flags, 1, &num_anim); if (err != WEBP_MUX_OK) return err; err = ValidateChunk(mux, IDX_ANMF, NO_FLAG, flags, -1, &num_frames); if (err != WEBP_MUX_OK) return err; { const int has_animation = !!(flags & ANIMATION_FLAG); if (has_animation && (num_anim == 0 || num_frames == 0)) { return WEBP_MUX_INVALID_ARGUMENT; } if (!has_animation && (num_anim == 1 || num_frames > 0)) { return WEBP_MUX_INVALID_ARGUMENT; } } // Fragmentation: FRAGMENTS_FLAG and FRGM chunk(s) are consistent. err = ValidateChunk(mux, IDX_FRGM, FRAGMENTS_FLAG, flags, -1, &num_fragments); if (err != WEBP_MUX_OK) return err; // Verify either VP8X chunk is present OR there is only one elem in // mux->images_. err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x); if (err != WEBP_MUX_OK) return err; err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images); if (err != WEBP_MUX_OK) return err; if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT; // ALPHA_FLAG & alpha chunk(s) are consistent. if (MuxHasAlpha(mux->images_)) { if (num_vp8x > 0) { // VP8X chunk is present, so it should contain ALPHA_FLAG. if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT; } else { // VP8X chunk is not present, so ALPH chunks should NOT be present either. err = WebPMuxNumChunks(mux, WEBP_CHUNK_ALPHA, &num_alpha); if (err != WEBP_MUX_OK) return err; if (num_alpha > 0) return WEBP_MUX_INVALID_ARGUMENT; } } else { // Mux doesn't need alpha. So, ALPHA_FLAG should NOT be present. if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT; } // num_fragments & num_images are consistent. if (num_fragments > 0 && num_images != num_fragments) { return WEBP_MUX_INVALID_ARGUMENT; } return WEBP_MUX_OK; }