mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Merge "Improved alpha cleanup for the webp encoder when prediction transform is used."
This commit is contained in:
commit
7eb01ff3e8
@ -161,7 +161,7 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
|
|||||||
|
|
||||||
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
||||||
uint32_t* const argb, uint32_t* const argb_scratch,
|
uint32_t* const argb, uint32_t* const argb_scratch,
|
||||||
uint32_t* const image);
|
uint32_t* const image, int exact);
|
||||||
|
|
||||||
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
|
||||||
uint32_t* const argb, uint32_t* image);
|
uint32_t* const argb, uint32_t* image);
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#define MAX_DIFF_COST (1e30f)
|
#define MAX_DIFF_COST (1e30f)
|
||||||
|
|
||||||
static const int kPredLowEffort = 11;
|
static const int kPredLowEffort = 11;
|
||||||
|
static const uint32_t kMaskAlpha = 0xff000000;
|
||||||
|
|
||||||
// lookup table for small values of log2(int)
|
// lookup table for small values of log2(int)
|
||||||
const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
|
const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
|
||||||
@ -659,7 +660,8 @@ static WEBP_INLINE uint32_t Predict(VP8LPredictorFunc pred_func,
|
|||||||
static int GetBestPredictorForTile(int width, int height,
|
static int GetBestPredictorForTile(int width, int height,
|
||||||
int tile_x, int tile_y, int bits,
|
int tile_x, int tile_y, int bits,
|
||||||
int accumulated[4][256],
|
int accumulated[4][256],
|
||||||
const uint32_t* const argb_scratch) {
|
const uint32_t* const argb_scratch,
|
||||||
|
int exact) {
|
||||||
const int kNumPredModes = 14;
|
const int kNumPredModes = 14;
|
||||||
const int col_start = tile_x << bits;
|
const int col_start = tile_x << bits;
|
||||||
const int row_start = tile_y << bits;
|
const int row_start = tile_y << bits;
|
||||||
@ -691,7 +693,11 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
const int col = col_start + x;
|
const int col = col_start + x;
|
||||||
const uint32_t predict =
|
const uint32_t predict =
|
||||||
Predict(pred_func, col, row, current_row, upper_row);
|
Predict(pred_func, col, row, current_row, upper_row);
|
||||||
UpdateHisto(histo_argb, VP8LSubPixels(current_row[col], predict));
|
uint32_t residual = VP8LSubPixels(current_row[col], predict);
|
||||||
|
if (!exact && (current_row[col] & kMaskAlpha) == 0) {
|
||||||
|
residual &= kMaskAlpha; // See CopyTileWithPrediction.
|
||||||
|
}
|
||||||
|
UpdateHisto(histo_argb, residual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cur_diff = PredictionCostSpatialHistogram(
|
cur_diff = PredictionCostSpatialHistogram(
|
||||||
@ -717,7 +723,8 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
static void CopyImageWithPrediction(int width, int height,
|
static void CopyImageWithPrediction(int width, int height,
|
||||||
int bits, uint32_t* const modes,
|
int bits, uint32_t* const modes,
|
||||||
uint32_t* const argb_scratch,
|
uint32_t* const argb_scratch,
|
||||||
uint32_t* const argb, int low_effort) {
|
uint32_t* const argb,
|
||||||
|
int low_effort, int exact) {
|
||||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||||
const int mask = (1 << bits) - 1;
|
const int mask = (1 << bits) - 1;
|
||||||
// The row size is one pixel longer to allow the top right pixel to point to
|
// The row size is one pixel longer to allow the top right pixel to point to
|
||||||
@ -744,14 +751,25 @@ static void CopyImageWithPrediction(int width, int height,
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (x = 0; x < width; ++x) {
|
for (x = 0; x < width; ++x) {
|
||||||
uint32_t predict;
|
uint32_t predict, residual;
|
||||||
if ((x & mask) == 0) {
|
if ((x & mask) == 0) {
|
||||||
const int mode =
|
const int mode =
|
||||||
(modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
|
(modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
|
||||||
pred_func = VP8LPredictors[mode];
|
pred_func = VP8LPredictors[mode];
|
||||||
}
|
}
|
||||||
predict = Predict(pred_func, x, y, current_row, upper_row);
|
predict = Predict(pred_func, x, y, current_row, upper_row);
|
||||||
argb[y * width + x] = VP8LSubPixels(current_row[x], predict);
|
residual = VP8LSubPixels(current_row[x], predict);
|
||||||
|
if (!exact && (current_row[x] & kMaskAlpha) == 0) {
|
||||||
|
// If alpha is 0, cleanup RGB. We can choose the RGB values of the
|
||||||
|
// residual for best compression. The prediction of alpha itself can
|
||||||
|
// be non-zero and must be kept though. We choose RGB of the residual
|
||||||
|
// to be 0.
|
||||||
|
residual &= kMaskAlpha;
|
||||||
|
// Update input image so that next predictions use correct RGB value.
|
||||||
|
current_row[x] = predict & ~kMaskAlpha;
|
||||||
|
if (x == 0 && y != 0) upper_row[width] = current_row[x];
|
||||||
|
}
|
||||||
|
argb[y * width + x] = residual;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -759,7 +777,7 @@ static void CopyImageWithPrediction(int width, int height,
|
|||||||
|
|
||||||
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
||||||
uint32_t* const argb, uint32_t* const argb_scratch,
|
uint32_t* const argb, uint32_t* const argb_scratch,
|
||||||
uint32_t* const image) {
|
uint32_t* const image, int exact) {
|
||||||
const int max_tile_size = 1 << bits;
|
const int max_tile_size = 1 << bits;
|
||||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||||
const int tiles_per_col = VP8LSubSampleSize(height, bits);
|
const int tiles_per_col = VP8LSubSampleSize(height, bits);
|
||||||
@ -787,15 +805,14 @@ void VP8LResidualImage(int width, int height, int bits, int low_effort,
|
|||||||
this_tile_height * width * sizeof(*current_tile_rows));
|
this_tile_height * width * sizeof(*current_tile_rows));
|
||||||
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
|
||||||
const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
|
const int pred = GetBestPredictorForTile(width, height, tile_x, tile_y,
|
||||||
bits, (int (*)[256])histo,
|
bits, (int (*)[256])histo, argb_scratch, exact);
|
||||||
argb_scratch);
|
|
||||||
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
|
image[tile_y * tiles_per_row + tile_x] = ARGB_BLACK | (pred << 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CopyImageWithPrediction(width, height, bits,
|
CopyImageWithPrediction(width, height, bits,
|
||||||
image, argb_scratch, argb, low_effort);
|
image, argb_scratch, argb, low_effort, exact);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
|
void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
|
||||||
|
@ -67,6 +67,11 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
|
|||||||
|
|
||||||
WebPConfigInit(&config);
|
WebPConfigInit(&config);
|
||||||
config.lossless = 1;
|
config.lossless = 1;
|
||||||
|
// Enable exact, or it would alter RGB values of transparent alpha, which is
|
||||||
|
// normally OK but not here since we are not encoding the input image but an
|
||||||
|
// internal encoding-related image containing necessary exact information in
|
||||||
|
// RGB channels.
|
||||||
|
config.exact = 1;
|
||||||
config.method = effort_level; // impact is very small
|
config.method = effort_level; // impact is very small
|
||||||
// Set a low default quality for encoding alpha. Ensure that Alpha quality at
|
// Set a low default quality for encoding alpha. Ensure that Alpha quality at
|
||||||
// lower methods (3 and below) is less than the threshold for triggering
|
// lower methods (3 and below) is less than the threshold for triggering
|
||||||
|
@ -1012,7 +1012,8 @@ static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
|
|||||||
const int transform_height = VP8LSubSampleSize(height, pred_bits);
|
const int transform_height = VP8LSubSampleSize(height, pred_bits);
|
||||||
|
|
||||||
VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
|
VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
|
||||||
enc->argb_scratch_, enc->transform_data_);
|
enc->argb_scratch_, enc->transform_data_,
|
||||||
|
enc->config_->exact);
|
||||||
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
|
VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
|
||||||
VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
|
VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
|
||||||
assert(pred_bits >= 2);
|
assert(pred_bits >= 2);
|
||||||
|
Loading…
Reference in New Issue
Block a user