mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
gif2webp: detect and flatten uniformly similar blocks
helps during lossless compression. 10% average saving, but that's mostly on what was previously 'difficult' cases, where the gain is ~30-50% actually. Non-difficult cases are mostly unchanged. Tested over ~7k random web gifs. Change-Id: I09db4560e4ab09105d1cad28e6dbf83842eda8e9
This commit is contained in:
parent
6a8c0eb718
commit
00125196f3
@ -170,6 +170,7 @@ static int OptimizeAndEncodeFrame(
|
|||||||
// For lossy compression, it's better to replace transparent pixels of
|
// For lossy compression, it's better to replace transparent pixels of
|
||||||
// 'curr' with actual RGB values, whenever possible.
|
// 'curr' with actual RGB values, whenever possible.
|
||||||
WebPUtilReduceTransparency(prev_canvas, &rect, curr);
|
WebPUtilReduceTransparency(prev_canvas, &rect, curr);
|
||||||
|
WebPUtilFlattenSimilarBlocks(prev_canvas, &rect, curr);
|
||||||
}
|
}
|
||||||
if (!WebPFrameCacheShouldTryKeyFrame(cache)) {
|
if (!WebPFrameCacheShouldTryKeyFrame(cache)) {
|
||||||
// Add this as a frame rectangle.
|
// Add this as a frame rectangle.
|
||||||
|
@ -290,10 +290,10 @@ void WebPUtilBlendPixels(const WebPPicture* const src,
|
|||||||
void WebPUtilReduceTransparency(const WebPPicture* const src,
|
void WebPUtilReduceTransparency(const WebPPicture* const src,
|
||||||
const WebPFrameRect* const rect,
|
const WebPFrameRect* const rect,
|
||||||
WebPPicture* const dst) {
|
WebPPicture* const dst) {
|
||||||
int j;
|
int i, j;
|
||||||
|
assert(src != NULL && dst != NULL && rect != NULL);
|
||||||
assert(src->width == dst->width && src->height == dst->height);
|
assert(src->width == dst->width && src->height == dst->height);
|
||||||
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
|
for (j = rect->y_offset; j < rect->y_offset + rect->height; ++j) {
|
||||||
int i;
|
|
||||||
for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) {
|
for (i = rect->x_offset; i < rect->x_offset + rect->width; ++i) {
|
||||||
const uint32_t src_pixel = src->argb[j * src->argb_stride + i];
|
const uint32_t src_pixel = src->argb[j * src->argb_stride + i];
|
||||||
const int src_alpha = src_pixel >> 24;
|
const int src_alpha = src_pixel >> 24;
|
||||||
@ -306,6 +306,56 @@ void WebPUtilReduceTransparency(const WebPPicture* const src,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebPUtilFlattenSimilarBlocks(const WebPPicture* const src,
|
||||||
|
const WebPFrameRect* const rect,
|
||||||
|
WebPPicture* const dst) {
|
||||||
|
int i, j;
|
||||||
|
const int block_size = 8;
|
||||||
|
const int y_start = (rect->y_offset + block_size) & ~(block_size - 1);
|
||||||
|
const int y_end = (rect->y_offset + rect->height) & ~(block_size - 1);
|
||||||
|
const int x_start = (rect->x_offset + block_size) & ~(block_size - 1);
|
||||||
|
const int x_end = (rect->x_offset + rect->width) & ~(block_size - 1);
|
||||||
|
assert(src != NULL && dst != NULL && rect != NULL);
|
||||||
|
assert(src->width == dst->width && src->height == dst->height);
|
||||||
|
assert((block_size & (block_size - 1)) == 0); // must be a power of 2
|
||||||
|
// Iterate over each block and count similar pixels.
|
||||||
|
for (j = y_start; j < y_end; j += block_size) {
|
||||||
|
for (i = x_start; i < x_end; i += block_size) {
|
||||||
|
int cnt = 0;
|
||||||
|
int avg_r = 0, avg_g = 0, avg_b = 0;
|
||||||
|
int x, y;
|
||||||
|
const uint32_t* const psrc = src->argb + j * src->argb_stride + i;
|
||||||
|
uint32_t* const pdst = dst->argb + j * dst->argb_stride + i;
|
||||||
|
for (y = 0; y < block_size; ++y) {
|
||||||
|
for (x = 0; x < block_size; ++x) {
|
||||||
|
const uint32_t src_pixel = psrc[x + y * src->argb_stride];
|
||||||
|
const int alpha = src_pixel >> 24;
|
||||||
|
if (alpha == 0xff &&
|
||||||
|
src_pixel == pdst[x + y * dst->argb_stride]) {
|
||||||
|
++cnt;
|
||||||
|
avg_r += (src_pixel >> 16) & 0xff;
|
||||||
|
avg_g += (src_pixel >> 8) & 0xff;
|
||||||
|
avg_b += (src_pixel >> 0) & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we have a fully similar block, we replace it with an
|
||||||
|
// average transparent block. This compresses better in lossy mode.
|
||||||
|
if (cnt == block_size * block_size) {
|
||||||
|
const uint32_t color = (0x00 << 24) |
|
||||||
|
((avg_r / cnt) << 16) |
|
||||||
|
((avg_g / cnt) << 8) |
|
||||||
|
((avg_b / cnt) << 0);
|
||||||
|
for (y = 0; y < block_size; ++y) {
|
||||||
|
for (x = 0; x < block_size; ++x) {
|
||||||
|
pdst[x + y * dst->argb_stride] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Key frame related utilities.
|
// Key frame related utilities.
|
||||||
|
|
||||||
|
@ -91,6 +91,12 @@ void WebPUtilReduceTransparency(const struct WebPPicture* const src,
|
|||||||
const WebPFrameRect* const dst_rect,
|
const WebPFrameRect* const dst_rect,
|
||||||
struct WebPPicture* const dst);
|
struct WebPPicture* const dst);
|
||||||
|
|
||||||
|
// Replace similar blocks of pixels by a 'see-through' transparent block
|
||||||
|
// with uniform average color.
|
||||||
|
void WebPUtilFlattenSimilarBlocks(const WebPPicture* const src,
|
||||||
|
const WebPFrameRect* const rect,
|
||||||
|
WebPPicture* const dst);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Key frame related.
|
// Key frame related.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user