webpinfo: add support to parse Alpha bitstream

BUG=webp:330

Change-Id: I9ed0923d19558052d63bdbe93a542c51595fdce7
This commit is contained in:
hui su 2017-05-17 09:35:58 -07:00
parent 4c1176432a
commit dabda70733

View File

@ -55,6 +55,13 @@ static const char* const kLosslessTransforms[4] = {
"Color Indexing" "Color Indexing"
}; };
static const char* const kAlphaFilterMethods[4] = {
"None",
"Horizontal",
"Vertical",
"Gradient"
};
typedef enum { typedef enum {
WEBP_INFO_OK = 0, WEBP_INFO_OK = 0,
WEBP_INFO_TRUNCATED_DATA, WEBP_INFO_TRUNCATED_DATA,
@ -473,7 +480,7 @@ static WebPInfoStatus ParseLosslessTransform(WebPInfo* const webp_info,
if (use_transform) { if (use_transform) {
int type; int type;
LL_GET_BITS(type, 2); LL_GET_BITS(type, 2);
printf(" 1st transform: %s\n", kLosslessTransforms[type]); printf(" 1st transform: %s (%d)\n", kLosslessTransforms[type], type);
switch (type) { switch (type) {
case PREDICTOR_TRANSFORM: case PREDICTOR_TRANSFORM:
case CROSS_COLOR_TRANSFORM: case CROSS_COLOR_TRANSFORM:
@ -528,6 +535,47 @@ static WebPInfoStatus ParseLosslessHeader(const ChunkData* const chunk_data,
return WEBP_INFO_OK; return WEBP_INFO_OK;
} }
static WebPInfoStatus ParseAlphaHeader(const ChunkData* const chunk_data,
WebPInfo* const webp_info) {
const uint8_t* data = chunk_data->payload_;
size_t data_size = chunk_data->size_ - CHUNK_HEADER_SIZE;
if (data_size <= ALPHA_HEADER_LEN) {
LOG_ERROR("Truncated ALPH chunk.");
return WEBP_INFO_TRUNCATED_DATA;
}
printf(" Parsing ALPH chunk...\n");
{
const int compression_method = (data[0] >> 0) & 0x03;
const int filter = (data[0] >> 2) & 0x03;
const int pre_processing = (data[0] >> 4) & 0x03;
const int reserved_bits = (data[0] >> 6) & 0x03;
printf(" Compression: %d\n", compression_method);
printf(" Filter: %s (%d)\n",
kAlphaFilterMethods[filter], filter);
printf(" Pre-processing: %d\n", pre_processing);
if (compression_method > ALPHA_LOSSLESS_COMPRESSION) {
LOG_ERROR("Invalid Alpha compression method.");
return WEBP_INFO_BITSTREAM_ERROR;
}
if (pre_processing > ALPHA_PREPROCESSED_LEVELS) {
LOG_ERROR("Invalid Alpha pre-processing method.");
return WEBP_INFO_BITSTREAM_ERROR;
}
if (reserved_bits != 0) {
LOG_WARN("Reserved bits in ALPH chunk header are not all 0.");
}
data += ALPHA_HEADER_LEN;
data_size -= ALPHA_HEADER_LEN;
if (compression_method == ALPHA_LOSSLESS_COMPRESSION) {
uint64_t bit_pos = 0;
WebPInfoStatus status =
ParseLosslessTransform(webp_info, data, data_size, &bit_pos);
if (status != WEBP_INFO_OK) return status;
}
}
return WEBP_INFO_OK;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Chunk parsing. // Chunk parsing.
@ -751,9 +799,9 @@ static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
if (!webp_info->quiet_) { if (!webp_info->quiet_) {
assert(features.format >= 0 && features.format <= 2); assert(features.format >= 0 && features.format <= 2);
printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n" printf(" Width: %d\n Height: %d\n Alpha: %d\n Animation: %d\n"
" Format: %s\n", " Format: %s (%d)\n",
features.width, features.height, features.has_alpha, features.width, features.height, features.has_alpha,
features.has_animation, kFormats[features.format]); features.has_animation, kFormats[features.format], features.format);
} }
if (webp_info->is_processing_anim_frame_) { if (webp_info->is_processing_anim_frame_) {
++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1]; ++webp_info->anmf_subchunk_counts_[chunk_data->id_ == CHUNK_VP8 ? 0 : 1];
@ -821,7 +869,6 @@ static WebPInfoStatus ProcessImageChunk(const ChunkData* const chunk_data,
static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data, static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
WebPInfo* const webp_info) { WebPInfo* const webp_info) {
(void)chunk_data;
if (webp_info->is_processing_anim_frame_) { if (webp_info->is_processing_anim_frame_) {
++webp_info->anmf_subchunk_counts_[2]; ++webp_info->anmf_subchunk_counts_[2];
if (webp_info->seen_alpha_subchunk_) { if (webp_info->seen_alpha_subchunk_) {
@ -855,8 +902,11 @@ static WebPInfoStatus ProcessALPHChunk(const ChunkData* const chunk_data,
} }
++webp_info->chunk_counts_[CHUNK_ALPHA]; ++webp_info->chunk_counts_[CHUNK_ALPHA];
} }
// TODO(huisu): parse alpha bitstream information.
webp_info->has_alpha_ = 1; webp_info->has_alpha_ = 1;
if (webp_info->parse_bitstream_) {
const WebPInfoStatus status = ParseAlphaHeader(chunk_data, webp_info);
if (status != WEBP_INFO_OK) return status;
}
return WEBP_INFO_OK; return WEBP_INFO_OK;
} }