mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
Merge "Alpha flag fix for lossless."
This commit is contained in:
commit
f5f2fff657
@ -13,7 +13,7 @@ end of this file.
|
|||||||
WebP Container Specification
|
WebP Container Specification
|
||||||
============================
|
============================
|
||||||
|
|
||||||
_Working Draft, v0.2, 20120207_
|
_Working Draft, v0.3, 20120523_
|
||||||
|
|
||||||
|
|
||||||
* TOC placeholder
|
* TOC placeholder
|
||||||
@ -271,7 +271,7 @@ Extended WebP file header:
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| ChunkHeader('VP8X') |
|
| ChunkHeader('VP8X') |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Rsrv |M|I|A|T| Reserved |
|
| Rsrv |AL|M|I|A|T| Reserved |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Canvas Width |
|
| Canvas Width |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
@ -295,11 +295,15 @@ Metadata (M): 1 bit
|
|||||||
|
|
||||||
: Set if the file contains a 'META' chunk.
|
: Set if the file contains a 'META' chunk.
|
||||||
|
|
||||||
Reserved (Rsrv): 4 bits
|
Alpha (AL): 1 bit
|
||||||
|
|
||||||
|
: Set if the file contains images with transparency information ("alpha").
|
||||||
|
|
||||||
|
Reserved (Rsrv): 3 bits
|
||||||
|
|
||||||
: SHOULD be `0`.
|
: SHOULD be `0`.
|
||||||
|
|
||||||
Reserved: 16 bits
|
Reserved: 24 bits
|
||||||
|
|
||||||
: SHOULD be `0`.
|
: SHOULD be `0`.
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux,
|
|||||||
if (mux == NULL || name == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
if (mux == NULL || name == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
|
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
chunk_list = GetChunkListFromId(mux, id);
|
chunk_list = MuxGetChunkListFromId(mux, id);
|
||||||
if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
return DeleteChunks(chunk_list, kChunks[idx].tag);
|
return DeleteChunks(chunk_list, kChunks[idx].tag);
|
||||||
@ -390,7 +390,7 @@ static WebPMuxError MuxAddFrameTileInternal(
|
|||||||
image_info = NULL; // Owned by 'chunk' now.
|
image_info = NULL; // Owned by 'chunk' now.
|
||||||
err = ChunkSetNth(&chunk, &wpi.img_, 1);
|
err = ChunkSetNth(&chunk, &wpi.img_, 1);
|
||||||
if (err != WEBP_MUX_OK) goto Err;
|
if (err != WEBP_MUX_OK) goto Err;
|
||||||
ChunkInit(&chunk); // chunk owned by wpi.vp8_ now.
|
ChunkInit(&chunk); // chunk owned by wpi.img_ now.
|
||||||
|
|
||||||
// Create frame/tile data from image_info.
|
// Create frame/tile data from image_info.
|
||||||
err = CreateDataFromImageInfo(wpi.img_->image_info_, is_frame,
|
err = CreateDataFromImageInfo(wpi.img_->image_info_, is_frame,
|
||||||
@ -452,7 +452,7 @@ WebPMuxError WebPMuxDeleteImage(WebPMux* const mux) {
|
|||||||
|
|
||||||
if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
err = ValidateForImage(mux);
|
err = MuxValidateForImage(mux);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
// All well, delete image.
|
// All well, delete image.
|
||||||
@ -623,6 +623,14 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
|
|||||||
err = GetImageCanvasWidthHeight(mux, flags, &width, &height);
|
err = GetImageCanvasWidthHeight(mux, flags, &width, &height);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
|
if (MuxHasLosslessImages(images)) {
|
||||||
|
// We have a file with a VP8X chunk having some lossless images.
|
||||||
|
// As lossless images implicitly contain alpha, force ALPHA_FLAG to be true.
|
||||||
|
// 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.
|
PutLE32(data + 0, flags); // VP8X chunk flags.
|
||||||
PutLE32(data + 4, width); // canvas width.
|
PutLE32(data + 4, width); // canvas width.
|
||||||
PutLE32(data + 8, height); // canvas height.
|
PutLE32(data + 8, height); // canvas height.
|
||||||
@ -695,7 +703,7 @@ WebPMuxError WebPMuxAssemble(WebPMux* const mux,
|
|||||||
assert(dst == data + size);
|
assert(dst == data + size);
|
||||||
|
|
||||||
// Validate mux.
|
// Validate mux.
|
||||||
err = WebPMuxValidate(mux);
|
err = MuxValidate(mux);
|
||||||
if (err != WEBP_MUX_OK) {
|
if (err != WEBP_MUX_OK) {
|
||||||
free(data);
|
free(data);
|
||||||
data = NULL;
|
data = NULL;
|
||||||
|
@ -257,19 +257,22 @@ size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list);
|
|||||||
// Write out the given list of images into 'dst'.
|
// Write out the given list of images into 'dst'.
|
||||||
uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst);
|
uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst);
|
||||||
|
|
||||||
|
// Checks if the given image list contains at least one lossless image.
|
||||||
|
int MuxHasLosslessImages(const WebPMuxImage* images);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helper methods for mux.
|
// Helper methods for mux.
|
||||||
|
|
||||||
// Returns the list where chunk with given ID is to be inserted in mux.
|
// Returns the list where chunk with given ID is to be inserted in mux.
|
||||||
// Return value is NULL if this chunk should be inserted in mux->images_ list
|
// Return value is NULL if this chunk should be inserted in mux->images_ list
|
||||||
// or if 'id' is not known.
|
// or if 'id' is not known.
|
||||||
WebPChunk** GetChunkListFromId(const WebPMux* mux, TAG_ID id);
|
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, TAG_ID id);
|
||||||
|
|
||||||
// Validates that the given mux has a single image.
|
// Validates that the given mux has a single image.
|
||||||
WebPMuxError ValidateForImage(const WebPMux* const mux);
|
WebPMuxError MuxValidateForImage(const WebPMux* const mux);
|
||||||
|
|
||||||
// Validates the given mux object.
|
// Validates the given mux object.
|
||||||
WebPMuxError WebPMuxValidate(const WebPMux* const mux);
|
WebPMuxError MuxValidate(const WebPMux* const mux);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -422,10 +422,21 @@ uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MuxHasLosslessImages(const WebPMuxImage* images) {
|
||||||
|
while (images != NULL) {
|
||||||
|
assert(images->img_ != NULL);
|
||||||
|
if (images->img_->tag_ == kChunks[IDX_VP8L].tag) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
images = images->next_;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Helper methods for mux.
|
// Helper methods for mux.
|
||||||
|
|
||||||
WebPChunk** GetChunkListFromId(const WebPMux* mux, TAG_ID id) {
|
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, TAG_ID id) {
|
||||||
assert(mux != NULL);
|
assert(mux != NULL);
|
||||||
switch(id) {
|
switch(id) {
|
||||||
case VP8X_ID: return (WebPChunk**)&mux->vp8x_;
|
case VP8X_ID: return (WebPChunk**)&mux->vp8x_;
|
||||||
@ -437,7 +448,7 @@ WebPChunk** GetChunkListFromId(const WebPMux* mux, TAG_ID id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError ValidateForImage(const WebPMux* const mux) {
|
WebPMuxError MuxValidateForImage(const WebPMux* const mux) {
|
||||||
const int num_images = MuxImageCount(mux->images_, IMAGE_ID);
|
const int num_images = MuxImageCount(mux->images_, IMAGE_ID);
|
||||||
const int num_frames = MuxImageCount(mux->images_, FRAME_ID);
|
const int num_frames = MuxImageCount(mux->images_, FRAME_ID);
|
||||||
const int num_tiles = MuxImageCount(mux->images_, TILE_ID);
|
const int num_tiles = MuxImageCount(mux->images_, TILE_ID);
|
||||||
@ -465,7 +476,8 @@ static int IsNotCompatible(int feature, int num_items) {
|
|||||||
// and feature incompatibility (use NO_FLAG to skip).
|
// and feature incompatibility (use NO_FLAG to skip).
|
||||||
// On success returns WEBP_MUX_OK and stores the chunk count in *num.
|
// On success returns WEBP_MUX_OK and stores the chunk count in *num.
|
||||||
static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
|
static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
|
||||||
FeatureFlags feature, FeatureFlags vp8x_flags,
|
WebPFeatureFlags feature,
|
||||||
|
WebPFeatureFlags vp8x_flags,
|
||||||
int max, int* num) {
|
int max, int* num) {
|
||||||
const WebPMuxError err =
|
const WebPMuxError err =
|
||||||
WebPMuxNumNamedElements(mux, kChunks[idx].name, num);
|
WebPMuxNumNamedElements(mux, kChunks[idx].name, num);
|
||||||
@ -477,7 +489,7 @@ static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
|
|||||||
return WEBP_MUX_OK;
|
return WEBP_MUX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
WebPMuxError WebPMuxValidate(const WebPMux* const mux) {
|
WebPMuxError MuxValidate(const WebPMux* const mux) {
|
||||||
int num_iccp;
|
int num_iccp;
|
||||||
int num_meta;
|
int num_meta;
|
||||||
int num_loop_chunks;
|
int num_loop_chunks;
|
||||||
@ -541,14 +553,19 @@ WebPMuxError WebPMuxValidate(const WebPMux* const mux) {
|
|||||||
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
|
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
|
||||||
// ALPHA_FLAG & alpha chunk(s) are consistent.
|
// ALPHA_FLAG & alpha chunk(s) are consistent.
|
||||||
err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha);
|
if (num_vp8x > 0 && MuxHasLosslessImages(mux->images_)) {
|
||||||
if (err != WEBP_MUX_OK) return err;
|
// Special case: we have a VP8X chunk as well as some lossless images.
|
||||||
|
if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
} else {
|
||||||
|
err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha);
|
||||||
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
// num_images & num_alpha_chunks are consistent.
|
// num_images & num_alpha_chunks are consistent.
|
||||||
if (num_alpha > 0 && num_alpha != num_images) {
|
if (num_alpha > 0 && num_alpha != num_images) {
|
||||||
// Note that "num_alpha > 0" is the correct check but "flags && ALPHA_FLAG"
|
// Note that "num_alpha > 0" is the correct test but "flags && ALPHA_FLAG"
|
||||||
// is NOT, because ALPHA_FLAG is based on first image only.
|
// is NOT, because ALPHA_FLAG is based on first image only.
|
||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// num_tiles & num_images are consistent.
|
// num_tiles & num_images are consistent.
|
||||||
|
@ -166,7 +166,7 @@ WebPMux* WebPMuxCreateInternal(const uint8_t* data, size_t size, int copy_data,
|
|||||||
WebPChunk** chunk_list;
|
WebPChunk** chunk_list;
|
||||||
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
|
if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
|
||||||
// getting all chunks of an image.
|
// getting all chunks of an image.
|
||||||
chunk_list = GetChunkListFromId(mux, id); // List for adding this chunk.
|
chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
|
||||||
if (chunk_list == NULL) chunk_list = &mux->unknown_;
|
if (chunk_list == NULL) chunk_list = &mux->unknown_;
|
||||||
if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
|
if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
|
||||||
}
|
}
|
||||||
@ -179,7 +179,7 @@ WebPMux* WebPMuxCreateInternal(const uint8_t* data, size_t size, int copy_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate mux if complete.
|
// Validate mux if complete.
|
||||||
if (WebPMuxValidate(mux) != WEBP_MUX_OK) goto Err;
|
if (MuxValidate(mux) != WEBP_MUX_OK) goto Err;
|
||||||
|
|
||||||
Ok:
|
Ok:
|
||||||
MuxImageDelete(wpi);
|
MuxImageDelete(wpi);
|
||||||
@ -234,7 +234,7 @@ WebPMuxError WebPMuxGetImage(const WebPMux* const mux,
|
|||||||
return WEBP_MUX_INVALID_ARGUMENT;
|
return WEBP_MUX_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ValidateForImage(mux);
|
err = MuxValidateForImage(mux);
|
||||||
if (err != WEBP_MUX_OK) return err;
|
if (err != WEBP_MUX_OK) return err;
|
||||||
|
|
||||||
// All well. Get the image.
|
// All well. Get the image.
|
||||||
@ -381,7 +381,7 @@ WebPMuxError WebPMuxNumNamedElements(const WebPMux* const mux, const char* name,
|
|||||||
if (IsWPI(id)) {
|
if (IsWPI(id)) {
|
||||||
*num_elements = MuxImageCount(mux->images_, id);
|
*num_elements = MuxImageCount(mux->images_, id);
|
||||||
} else {
|
} else {
|
||||||
WebPChunk* const* chunk_list = GetChunkListFromId(mux, id);
|
WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id);
|
||||||
if (chunk_list == NULL) {
|
if (chunk_list == NULL) {
|
||||||
*num_elements = 0;
|
*num_elements = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -78,7 +78,7 @@ typedef enum {
|
|||||||
ICCP_FLAG = 0x00000004,
|
ICCP_FLAG = 0x00000004,
|
||||||
META_FLAG = 0x00000008,
|
META_FLAG = 0x00000008,
|
||||||
ALPHA_FLAG = 0x00000010
|
ALPHA_FLAG = 0x00000010
|
||||||
} FeatureFlags;
|
} WebPFeatureFlags;
|
||||||
|
|
||||||
typedef struct WebPMux WebPMux; // main opaque object.
|
typedef struct WebPMux WebPMux; // main opaque object.
|
||||||
|
|
||||||
@ -430,7 +430,7 @@ WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* const mux, uint32_t nth);
|
|||||||
// mux - (in) object from which the features are to be fetched
|
// mux - (in) object from which the features are to be fetched
|
||||||
// flags - (out) the flags specifying which features are present in the
|
// flags - (out) the flags specifying which features are present in the
|
||||||
// mux object. This will be an OR of various flag values.
|
// mux object. This will be an OR of various flag values.
|
||||||
// Enum 'FeatureFlags' can be used to test for individual flag values.
|
// Enum 'WebPFeatureFlags' can be used to test individual flag values.
|
||||||
// Returns:
|
// Returns:
|
||||||
// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or flags is NULL
|
// 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_NOT_FOUND - if VP8X chunk is not present in mux object.
|
||||||
|
Loading…
Reference in New Issue
Block a user