static WebPMuxError MuxGet(WebPMux* mux, TAG_ID id, uint nth, WebPData* data) { assert(mux != null); memset(data, 0, sizeof(*data)); assert(!IsWPI(id)); SWITCH_ID_LIST(VP8X_ID, mux.vp8x_); SWITCH_ID_LIST(ICCP_ID, mux.iccp_); SWITCH_ID_LIST(LOOP_ID, mux.loop_); SWITCH_ID_LIST(META_ID, mux.meta_); SWITCH_ID_LIST(UNKNOWN_ID, mux.unknown_); return WEBP_MUX_NOT_FOUND; }
static WebPMuxError MuxSet(WebPMux* mux, TAG_ID id, uint nth, byte* data, uint size, WebPImageInfo* image_info, int copy_data) { WebPChunk chunk; WebPMuxError err = WEBP_MUX_NOT_FOUND; if (mux == null) return WEBP_MUX_INVALID_ARGUMENT; assert(!IsWPI(id)); ChunkInit(&chunk); SWITCH_ID_LIST(VP8X_ID, &mux.vp8x_); SWITCH_ID_LIST(ICCP_ID, &mux.iccp_); SWITCH_ID_LIST(LOOP_ID, &mux.loop_); SWITCH_ID_LIST(META_ID, &mux.meta_); if (id == UNKNOWN_ID && size > TAG_SIZE) { // For raw-data unknown chunk, the first four bytes should be the tag to be // used for the chunk. err = ChunkAssignDataImageInfo(&chunk, data + TAG_SIZE, size - TAG_SIZE, image_info, copy_data, GetLE32(data + 0)); if (err == WEBP_MUX_OK) err = ChunkSetNth(&chunk, &mux.unknown_, nth); } return err; }
WebPMuxError ValidateForImage(WebPMux* mux) { int num_vp8 = MuxImageCount(mux.images_, IMAGE_ID); int num_frames = MuxImageCount(mux.images_, FRAME_ID); int num_tiles = MuxImageCount(mux.images_, TILE_ID); if (num_vp8 == 0) { // No images in mux. return WEBP_MUX_NOT_FOUND; } else if (num_vp8 == 1 && num_frames == 0 && num_tiles == 0) { // Valid case (single image). return WEBP_MUX_OK; } else { // Frame/Tile case OR an invalid mux. return WEBP_MUX_INVALID_ARGUMENT; } }
// Gets a reference to the nth tile from the mux object. // The caller should NOT free the returned data. // nth=0 has a special meaning - last position. // Parameters: // mux - (in) object from which the info is to be fetched // nth - (in) index of the tile in the mux object // image - (out) the image data // alpha - (out) the alpha data corresponding to tile image (if present) // x_offset - (out) x-offset of the returned tile // y_offset - (out) y-offset of the returned tile // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux, image, x_offset or // y_offset is null // WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object. // WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxGetTile(WebPMux* mux, uint nth, WebPData* image, WebPData* alpha, uint* x_offset, uint* y_offset) { return MuxGetFrameTileInternal(mux, nth, image, alpha, x_offset, y_offset, null, kChunks[TILE_ID].chunkTag); }
static WebPMuxError MuxGetFrameTileInternal(WebPMux* mux, uint nth, WebPData* image, WebPData* alpha, uint* x_offset, uint* y_offset, uint* duration, uint tag) { byte* frame_tile_data; uint frame_tile_size; WebPMuxError err; WebPMuxImage* wpi; int is_frame = (tag == kChunks[FRAME_ID].chunkTag) ? 1 : 0; TAG_ID id = is_frame ? FRAME_ID : TILE_ID; if (mux == null || image == null || x_offset == null || y_offset == null || (is_frame && duration == null)) { return WEBP_MUX_INVALID_ARGUMENT; } // Get the nth WebPMuxImage. err = MuxImageGetNth((WebPMuxImage**)&mux.images_, nth, id, &wpi); if (err != WEBP_MUX_OK) return err; // Get frame chunk. assert(wpi.header_ != null); // As GetNthImage() already checked header_. frame_tile_data = wpi.header_.data_; frame_tile_size = wpi.header_.payload_size_; if (frame_tile_size < kChunks[id].chunkSize) return WEBP_MUX_BAD_DATA; *x_offset = GetLE32(frame_tile_data + 0); *y_offset = GetLE32(frame_tile_data + 4); if (is_frame) *duration = GetLE32(frame_tile_data + 16); // Get alpha chunk (if present & requested). if (alpha != null) { memset(alpha, 0, sizeof(*alpha)); if (wpi.alpha_ != null) { alpha.bytes_ = wpi.alpha_.data_; alpha.size_ = wpi.alpha_.payload_size_; } } // Get image chunk. memset(image, 0, sizeof(*image)); if (wpi.vp8_ != null) { image.bytes_ = wpi.vp8_.data_; image.size_ = wpi.vp8_.payload_size_; } return WEBP_MUX_OK; }
// Gets a reference to the color profile in the mux object. // The caller should NOT free the returned data. // Parameters: // mux - (in) object from which the color profile data is to be fetched // color_profile - (out) color profile data // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux or color_profile is null. // WEBP_MUX_NOT_FOUND - if color profile is not present in mux object. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxGetColorProfile(WebPMux* mux, WebPData* color_profile) { if (mux == null || color_profile == null) { return WEBP_MUX_INVALID_ARGUMENT; } return MuxGet(mux, ICCP_ID, 1, color_profile); }
//------------------------------------------------------------------------------ // Get API(s). // Gets the feature flags from the mux object. // Parameters: // mux - (in) object from which the features are to be fetched // flags - (out) the flags specifying which features are present in the // mux object. This will be an OR of various flag values. // Enum 'FeatureFlags' can be used to test for individual flag values. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null or flags is null // WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object. // WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid. // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxGetFeatures(WebPMux* mux, uint* flags) { WebPData data; WebPMuxError err; if (mux == null || flags == null) return WEBP_MUX_INVALID_ARGUMENT; *flags = 0; // Check if VP8X chunk is present. err = MuxGet(mux, VP8X_ID, 1, &data); if (err == WEBP_MUX_NOT_FOUND) { // Check if VP8 chunk is present. err = WebPMuxGetImage(mux, &data, null); if (err == WEBP_MUX_NOT_FOUND && // Data not available (yet). mux.state_ == WEBP_MUX_STATE_PARTIAL) { // Incremental case. return WEBP_MUX_NOT_ENOUGH_DATA; } else { return err; } } else if (err != WEBP_MUX_OK) { return err; } // TODO(urvang): Add a '#define CHUNK_SIZE_BYTES 4' and use it instead of // hard-coded value of 4 everywhere. if (data.size_ < 4) return WEBP_MUX_BAD_DATA; // All OK. Fill up flags. *flags = GetLE32(data.bytes_); return WEBP_MUX_OK; }
// Sets the color profile in the mux object. Any existing color profile chunk(s) // will be removed. // Parameters: // mux - (in/out) object to which the color profile is to be added // data - (in) the color profile data to be added // size - (in) size of the color profile data // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null or data is null // WEBP_MUX_MEMORY_ERROR - on memory allocation error // WEBP_MUX_OK - on success WebPMuxError WebPMuxSetColorProfile(WebPMux* mux, byte* data, uint size, int copy_data) { WebPMuxError err; if (mux == null || data == null || size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // Delete the existing ICCP chunk(s). err = WebPMuxDeleteColorProfile(mux); if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; // Add the given ICCP chunk. return MuxSet(mux, ICCP_ID, 1, data, size, null, copy_data); }
// Sets the animation loop count in the mux object. Any existing loop count // value(s) will be removed. // Parameters: // mux - (in/out) object in which loop chunk is to be set/added // loop_count - (in) animation loop count value. // Note that loop_count of zero denotes infinite loop. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, uint loop_count) { WebPMuxError err; byte* data = null; if (mux == null) return WEBP_MUX_INVALID_ARGUMENT; // Delete the existing LOOP chunk(s). err = DeleteLoopCount(mux); if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; // Add the given loop count. data = (byte*)malloc(kChunks[LOOP_ID].chunkSize); if (data == null) return WEBP_MUX_MEMORY_ERROR; PutLE32(data, loop_count); err = MuxAddChunk(mux, 1, kChunks[LOOP_ID].chunkTag, data, kChunks[LOOP_ID].chunkSize, null, 1); free(data); return err; }
//------------------------------------------------------------------------------ // Set API(s). // Sets the image in the mux object. Any existing images (including frame/tile) // will be removed. // Parameters: // mux - (in/out) object in which the image is to be set // data - (in) the image data to be set. The data can be either a VP8 // bitstream or a single-image WebP file (non-animated & non-tiled) // size - (in) size of the image data // alpha_data - (in) the alpha data corresponding to the image (if present) // alpha_size - (in) size of alpha chunk data // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null or data is null. // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxSetImage(WebPMux* mux, byte* data, uint size, byte* alpha_data, uint alpha_size, int copy_data) { WebPMuxError err; WebPChunk chunk; WebPMuxImage wpi; WebPData image; int has_alpha = (alpha_data != null && alpha_size != 0); if (mux == null || data == null || size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // If given data is for a whole webp file, extract only the VP8 data from it. err = GetImageData(data, size, &image, null); if (err != WEBP_MUX_OK) return err; // Delete the existing images. MuxImageDeleteAll(&mux.images_); MuxImageInit(&wpi); if (has_alpha) { // Add alpha chunk. ChunkInit(&chunk); err = ChunkAssignDataImageInfo(&chunk, alpha_data, alpha_size, null, copy_data, kChunks[ALPHA_ID].chunkTag); if (err != WEBP_MUX_OK) return err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) return err; } // Add image chunk. ChunkInit(&chunk); err = ChunkAssignDataImageInfo(&chunk, image.bytes_, image.size_, null, copy_data, kChunks[IMAGE_ID].chunkTag); if (err != WEBP_MUX_OK) return err; err = ChunkSetNth(&chunk, &wpi.vp8_, 1); if (err != WEBP_MUX_OK) return err; // Add this image to mux. return MuxImageSetNth(&wpi, &mux.images_, 1); }
// Sets the XMP metadata in the mux object. Any existing metadata chunk(s) will // be removed. // Parameters: // mux - (in/out) object to which the XMP metadata is to be added // data - (in) the XMP metadata data to be added // size - (in) size of the XMP metadata data // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null or data is null. // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxSetMetadata(WebPMux* mux, byte* data, uint size, int copy_data) { WebPMuxError err; if (mux == null || data == null || size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // Delete the existing metadata chunk(s). err = WebPMuxDeleteMetadata(mux); if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err; // Add the given metadata chunk. return MuxSet(mux, META_ID, 1, data, size, null, copy_data); }
static WebPMuxError DeleteLoopCount(WebPMux* mux) { return MuxDeleteAllNamedData(mux, kChunks[LOOP_ID].chunkName); }
static WebPMuxError MuxDeleteAllNamedData(WebPMux* mux, char* tag) { TAG_ID id; WebPChunk** chunk_list; if (mux == null || tag == null) return WEBP_MUX_INVALID_ARGUMENT; id = ChunkGetIdFromName(tag); if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT; chunk_list = GetChunkListFromId(mux, id); if (chunk_list == null) return WEBP_MUX_INVALID_ARGUMENT; return DeleteChunks(chunk_list, kChunks[id].chunkTag); }
WebPMuxError WebPMuxValidate(WebPMux* mux) { int num_iccp; int num_meta; int num_loop_chunks; int num_frames; int num_tiles; int num_vp8x; int num_images; int num_alpha; uint flags; WebPMuxError err; // Verify mux is not null. if (mux == null || mux.state_ == WEBP_MUX_STATE_ERROR) { return WEBP_MUX_INVALID_ARGUMENT; } // No further checks if mux is partial. if (mux.state_ == WEBP_MUX_STATE_PARTIAL) return WEBP_MUX_OK; // 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 = WebPMuxNumNamedElements(mux, kChunks[ICCP_ID].chunkName, &num_iccp); if (err != WEBP_MUX_OK) return err; if (num_iccp > 1) return WEBP_MUX_INVALID_ARGUMENT; // ICCP_FLAG and color profile chunk is consistent. if (IsNotCompatible(flags & ICCP_FLAG, num_iccp)) { return WEBP_MUX_INVALID_ARGUMENT; } // At most one XMP metadata. err = WebPMuxNumNamedElements(mux, kChunks[META_ID].chunkName, &num_meta); if (err != WEBP_MUX_OK) return err; if (num_meta > 1) return WEBP_MUX_INVALID_ARGUMENT; // META_FLAG and XMP metadata chunk is consistent. if (IsNotCompatible(flags & META_FLAG, num_meta)) { return WEBP_MUX_INVALID_ARGUMENT; } // At most one loop chunk. err = WebPMuxNumNamedElements(mux, kChunks[LOOP_ID].chunkName, &num_loop_chunks); if (err != WEBP_MUX_OK) return err; if (num_loop_chunks > 1) return WEBP_MUX_INVALID_ARGUMENT; // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent. err = WebPMuxNumNamedElements(mux, kChunks[FRAME_ID].chunkName, &num_frames); if (err != WEBP_MUX_OK) return err; if ((flags & ANIMATION_FLAG) && ((num_loop_chunks == 0) || (num_frames == 0))) { return WEBP_MUX_INVALID_ARGUMENT; } else if (((num_loop_chunks == 1) || (num_frames > 0)) && !(flags & ANIMATION_FLAG)) { return WEBP_MUX_INVALID_ARGUMENT; } // Tiling: TILE_FLAG and tile chunk(s) are consistent. err = WebPMuxNumNamedElements(mux, kChunks[TILE_ID].chunkName, &num_tiles); if (err != WEBP_MUX_OK) return err; if (IsNotCompatible(flags & TILE_FLAG, num_tiles)) { return WEBP_MUX_INVALID_ARGUMENT; } // Verify either VP8X chunk is present OR there is only one elem in // mux.images_. err = WebPMuxNumNamedElements(mux, kChunks[VP8X_ID].chunkName, &num_vp8x); if (err != WEBP_MUX_OK) return err; err = WebPMuxNumNamedElements(mux, kChunks[IMAGE_ID].chunkName, &num_images); if (err != WEBP_MUX_OK) return err; if (num_vp8x > 1) { return WEBP_MUX_INVALID_ARGUMENT; } else if ((num_vp8x == 0) && (num_images != 1)) { return WEBP_MUX_INVALID_ARGUMENT; } // ALPHA_FLAG & alpha chunk(s) are consistent. err = WebPMuxNumNamedElements(mux, kChunks[ALPHA_ID].chunkName, &num_alpha); if (err != WEBP_MUX_OK) return err; if (IsNotCompatible(flags & ALPHA_FLAG, num_alpha)) { return WEBP_MUX_INVALID_ARGUMENT; } // num_images & num_alpha_chunks are consistent. if ((num_alpha > 0) && (num_alpha != num_images)) { // Note that "num_alpha > 0" is the correct check but "flags && ALPHA_FLAG" // is NOT, because ALPHA_FLAG is based on first image only. return WEBP_MUX_INVALID_ARGUMENT; } return WEBP_MUX_OK; }
//------------------------------------------------------------------------------ // Assembly of the WebP RIFF file. static WebPMuxError GetImageCanvasHeightWidth(WebPMux* mux, uint flags, uint* width, uint* height) { uint max_x = 0; uint max_y = 0; ulong image_area = 0; WebPMuxImage* wpi = null; assert(mux != null); assert(width && height); wpi = mux.images_; assert(wpi != null); assert(wpi.vp8_ != null); if (wpi.next_) { // Aggregate the bounding box for animation frames & tiled images. for (; wpi != null; wpi = wpi.next_) { WebPImageInfo* image_info = wpi.vp8_.image_info_; if (image_info != null) { uint max_x_pos = image_info.x_offset_ + image_info.width_; uint max_y_pos = image_info.y_offset_ + image_info.height_; if (max_x_pos < image_info.x_offset_) { // Overflow occurred. return WEBP_MUX_INVALID_ARGUMENT; } if (max_y_pos < image_info.y_offset_) { // Overflow occurred. return WEBP_MUX_INVALID_ARGUMENT; } if (max_x_pos > max_x) max_x = max_x_pos; if (max_y_pos > max_y) max_y = max_y_pos; image_area += (image_info.width_ * image_info.height_); } } *width = max_x; *height = max_y; // Crude check to validate that there are no image overlaps/holes for tile // images. Check that the aggregated image area for individual tiles exactly // matches the image area of the constructed canvas. However, the area-match // is necessary but not sufficient condition. if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) { *width = 0; *height = 0; return WEBP_MUX_INVALID_ARGUMENT; } } else { // For a single image, extract the width & height from VP8 image-data. int w, h; WebPChunk* image_chunk = wpi.vp8_; assert(image_chunk != null); if (VP8GetInfo(image_chunk.data_, image_chunk.payload_size_, image_chunk.payload_size_, &w, &h)) { *width = w; *height = h; } } return WEBP_MUX_OK; }
static WebPMuxError MuxAddFrameTileInternal(WebPMux* mux, uint nth, byte* data, uint size, byte* alpha_data, uint alpha_size, uint x_offset, uint y_offset, uint duration, int copy_data, uint tag) { WebPChunk chunk; WebPData image; WebPMuxImage wpi; WebPMuxError err; WebPImageInfo* image_info = null; byte* frame_tile_data = null; uint frame_tile_data_size = 0; int is_frame = (tag == kChunks[FRAME_ID].chunkTag) ? 1 : 0; int has_alpha = (alpha_data != null && alpha_size != 0); if (mux == null || data == null || size > MAX_CHUNK_PAYLOAD) { return WEBP_MUX_INVALID_ARGUMENT; } // If given data is for a whole webp file, extract only the VP8 data from it. err = GetImageData(data, size, &image, null); if (err != WEBP_MUX_OK) return err; ChunkInit(&chunk); MuxImageInit(&wpi); if (has_alpha) { // Add alpha chunk. err = ChunkAssignDataImageInfo(&chunk, alpha_data, alpha_size, null, copy_data, kChunks[ALPHA_ID].chunkTag); if (err != WEBP_MUX_OK) return err; err = ChunkSetNth(&chunk, &wpi.alpha_, 1); if (err != WEBP_MUX_OK) return err; ChunkInit(&chunk); // chunk owned by wpi.alpha_ now. } // Create image_info object. image_info = CreateImageInfo(x_offset, y_offset, duration, image.bytes_, image.size_); if (image_info == null) { MuxImageRelease(&wpi); return WEBP_MUX_MEMORY_ERROR; } // Add image chunk. err = ChunkAssignDataImageInfo(&chunk, image.bytes_, image.size_, image_info, copy_data, kChunks[IMAGE_ID].chunkTag); if (err != WEBP_MUX_OK) goto Err; image_info = null; // Owned by 'chunk' now. err = ChunkSetNth(&chunk, &wpi.vp8_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.vp8_ now. // Create frame/tile data from image_info. err = CreateDataFromImageInfo(wpi.vp8_.image_info_, is_frame, &frame_tile_data, &frame_tile_data_size); if (err != WEBP_MUX_OK) goto Err; // Add frame/tile chunk (with copy_data = 1). err = ChunkAssignDataImageInfo(&chunk, frame_tile_data, frame_tile_data_size, null, 1, tag); if (err != WEBP_MUX_OK) goto Err; free(frame_tile_data); frame_tile_data = null; err = ChunkSetNth(&chunk, &wpi.header_, 1); if (err != WEBP_MUX_OK) goto Err; ChunkInit(&chunk); // chunk owned by wpi.header_ now. // Add this WebPMuxImage to mux. err = MuxImageSetNth(&wpi, &mux.images_, nth); if (err != WEBP_MUX_OK) goto Err; // All is well. return WEBP_MUX_OK; Err: // Something bad happened. free(image_info); free(frame_tile_data); ChunkRelease(&chunk); MuxImageRelease(&wpi); return err; }
// VP8X format: // Total Size : 12, // Flags : 4 bytes, // Width : 4 bytes, // Height : 4 bytes. static WebPMuxError CreateVP8XChunk(WebPMux* mux) { WebPMuxError err = WEBP_MUX_OK; uint flags = 0; uint width = 0; uint height = 0; byte data[VP8X_CHUNK_SIZE];
// Adds a tile to the mux object. // nth=0 has a special meaning - last position. // Parameters: // mux - (in/out) object to which a tile is to be added // nth - (in) The position at which the tile is to be added. // data - (in) the raw VP8 image data corresponding to tile image. The data // can be either a VP8 bitstream or a single-image WebP file // (non-animated & non-tiled) // size - (in) size of tile chunk data // alpha_data - (in) the alpha data corresponding to tile image (if present) // alpha_size - (in) size of alpha chunk data // x_offset - (in) x-offset of the tile to be added // y_offset - (in) y-offset of the tile to be added // copy_data - (in) value 1 indicates given data WILL copied to the mux, and // value 0 indicates data will NOT be copied. // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null or data is null // WEBP_MUX_NOT_FOUND - If we have less than (nth-1) tiles before adding. // WEBP_MUX_MEMORY_ERROR - on memory allocation error. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxAddTile(WebPMux* mux, uint nth, byte* data, uint size, byte* alpha_data, uint alpha_size, uint x_offset, uint y_offset, int copy_data) { return MuxAddFrameTileInternal(mux, nth, data, size, alpha_data, alpha_size, x_offset, y_offset, 1, copy_data, kChunks[TILE_ID].chunkTag); }
static WebPMuxError MuxAddChunk(WebPMux* mux, uint nth, uint tag, byte* data, uint size, WebPImageInfo* image_info, int copy_data) { TAG_ID id; assert(mux != null); assert(size <= MAX_CHUNK_PAYLOAD); id = ChunkGetIdFromTag(tag); if (id == NIL_ID) return WEBP_MUX_INVALID_PARAMETER; return MuxSet(mux, id, nth, data, size, image_info, copy_data); }
//------------------------------------------------------------------------------ // Delete API(s). // Deletes the image in the mux object. // Parameters: // mux - (in/out) object from which the image is to be deleted // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null // OR if mux contains animation/tiling. // WEBP_MUX_NOT_FOUND - if image is not present in mux object. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxDeleteImage(WebPMux* mux) { WebPMuxError err; if (mux == null) return WEBP_MUX_INVALID_ARGUMENT; err = ValidateForImage(mux); if (err != WEBP_MUX_OK) return err; // All Well, delete Image. MuxImageDeleteAll(&mux.images_); return WEBP_MUX_OK; }
// Gets a reference to the image in the mux object. // The caller should NOT free the returned data. // Parameters: // mux - (in) object from which the image is to be fetched // image - (out) the image data // alpha - (out) the alpha data of the image (if present) // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux or image is null // OR if mux contains animation/tiling. // WEBP_MUX_NOT_FOUND - if image is not present in mux object. // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxGetImage(WebPMux* mux, WebPData* image, WebPData* alpha) { WebPMuxError err; WebPMuxImage* wpi = null; if (mux == null || image == null) { return WEBP_MUX_INVALID_ARGUMENT; } memset(image, 0, sizeof(*image)); err = ValidateForImage(mux); if (err != WEBP_MUX_OK) return err; // All well. Get the image. err = MuxImageGetNth((WebPMuxImage**)&mux.images_, 1, IMAGE_ID, &wpi); assert(err == WEBP_MUX_OK); // Already tested above. // Get alpha chunk (if present & requested). if (alpha != null) { memset(alpha, 0, sizeof(*alpha)); if (wpi.alpha_ != null) { alpha.bytes_ = wpi.alpha_.data_; alpha.size_ = wpi.alpha_.payload_size_; } } // Get image chunk. if (wpi.vp8_ != null) { image.bytes_ = wpi.vp8_.data_; image.size_ = wpi.vp8_.payload_size_; } return WEBP_MUX_OK; }
// Deletes the XMP metadata in the mux object. // Parameters: // mux - (in/out) object from which XMP metadata is to be deleted // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null // WEBP_MUX_NOT_FOUND - If mux does not contain metadata. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxDeleteMetadata(WebPMux* mux) { return MuxDeleteAllNamedData(mux, kChunks[META_ID].chunkName); }
// Gets a reference to the XMP metadata in the mux object. // The caller should NOT free the returned data. // Parameters: // mux - (in) object from which the XMP metadata is to be fetched // metadata - (out) XMP metadata // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux or metadata is null. // WEBP_MUX_NOT_FOUND - if metadata is not present in mux object. // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxGetMetadata(WebPMux* mux, WebPData* metadata) { if (mux == null || metadata == null) { return WEBP_MUX_INVALID_ARGUMENT; } return MuxGet(mux, META_ID, 1, metadata); }
// Deletes the color profile in the mux object. // Parameters: // mux - (in/out) object from which color profile is to be deleted // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null // WEBP_MUX_NOT_FOUND - If mux does not contain color profile. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxDeleteColorProfile(WebPMux* mux) { return MuxDeleteAllNamedData(mux, kChunks[ICCP_ID].chunkName); }
// Gets the animation loop count from the mux object. // Parameters: // mux - (in) object from which the loop count is to be fetched // loop_count - (out) the loop_count value present in the LOOP chunk // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either of mux or loop_count is null // WEBP_MUX_NOT_FOUND - if loop chunk is not present in mux object. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxGetLoopCount(WebPMux* mux, uint* loop_count) { WebPData image; WebPMuxError err; if (mux == null || loop_count == null) return WEBP_MUX_INVALID_ARGUMENT; err = MuxGet(mux, LOOP_ID, 1, &image); if (err != WEBP_MUX_OK) return err; if (image.size_ < kChunks[LOOP_ID].chunkSize) return WEBP_MUX_BAD_DATA; *loop_count = GetLE32(image.bytes_); return WEBP_MUX_OK; }
static WebPMuxError DeleteFrameTileInternal(WebPMux* mux, uint nth, char* tag) { TAG_ID id; if (mux == null) return WEBP_MUX_INVALID_ARGUMENT; id = ChunkGetIdFromName(tag); assert(id == FRAME_ID || id == TILE_ID); return MuxImageDeleteNth(&mux.images_, nth, id); }
// Gets a reference to the nth animation frame from the mux object. // The caller should NOT free the returned data. // nth=0 has a special meaning - last position. // Parameters: // mux - (in) object from which the info is to be fetched // nth - (in) index of the frame in the mux object // image - (out) the image data // alpha - (out) the alpha data corresponding to frame image (if present) // x_offset - (out) x-offset of the returned frame // y_offset - (out) y-offset of the returned frame // duration - (out) duration of the returned frame (in milliseconds) // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux, image, x_offset, // y_offset, or duration is null // WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object. // WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxGetFrame(WebPMux* mux, uint nth, WebPData* image, WebPData* alpha, uint* x_offset, uint* y_offset, uint* duration) { return MuxGetFrameTileInternal(mux, nth, image, alpha, x_offset, y_offset, duration, kChunks[FRAME_ID].chunkTag); }
// Deletes a tile from the mux object. // nth=0 has a special meaning - last position // Parameters: // mux - (in/out) object from which a tile is to be deleted // nth - (in) The position from which the tile is to be deleted // Returns: // WEBP_MUX_INVALID_ARGUMENT - if mux is null // WEBP_MUX_NOT_FOUND - If there are less than nth tiles in the mux object // before deletion. // WEBP_MUX_OK - on success. WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint nth) { return DeleteFrameTileInternal(mux, nth, kChunks[TILE_ID].chunkName); }
// Gets number of chunks having tag value tag in the mux object. // Parameters: // mux - (in) object from which the info is to be fetched // tag - (in) tag name specifying the type of chunk // num_elements - (out) number of chunks corresponding to the specified tag // Returns: // WEBP_MUX_INVALID_ARGUMENT - if either mux, tag or num_elements is null // WEBP_MUX_OK - on success. public WebPMuxError WebPMuxNumNamedElements(WebPMux* mux, char* tag, int* num_elements) { TAG_ID id; WebPChunk** chunk_list; if (mux == null || tag == null || num_elements == null) { return WEBP_MUX_INVALID_ARGUMENT; } id = ChunkGetIdFromName(tag); if (IsWPI(id)) { *num_elements = MuxImageCount(mux.images_, id); } else { chunk_list = GetChunkListFromId(mux, id); if (chunk_list == null) { *num_elements = 0; } else { *num_elements = CountChunks(*chunk_list, kChunks[id].chunkTag); } } return WEBP_MUX_OK; }
//------------------------------------------------------------------------------ // Helper methods for mux. WebPChunk** GetChunkListFromId(WebPMux* mux, TAG_ID id) { assert(mux != null); switch(id) { case VP8X_ID: return (WebPChunk**)&mux.vp8x_; case ICCP_ID: return (WebPChunk**)&mux.iccp_; case LOOP_ID: return (WebPChunk**)&mux.loop_; case META_ID: return (WebPChunk**)&mux.meta_; case UNKNOWN_ID: return (WebPChunk**)&mux.unknown_; default: return null; } }