Revert "Refactor GetColorPalette method."

This reverts commit 169004b1d5.

this changes the ABI, so should bump versions and add a note to NEWS
when we're ready to expose it

Change-Id: Ic5bbd0aee2b6fd0f9d438a9effedf22fe0cec4bf
This commit is contained in:
James Zern 2016-05-20 17:04:38 -07:00
parent 0a27aca3f8
commit cf4a651bb8
4 changed files with 104 additions and 85 deletions

View File

@ -126,8 +126,54 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
int low_effort, int low_effort,
uint32_t palette[MAX_PALETTE_SIZE], uint32_t palette[MAX_PALETTE_SIZE],
int* const palette_size) { int* const palette_size) {
const int num_colors = WebPGetColorPalette(pic, palette); int i, x, y, key;
if (num_colors > MAX_PALETTE_SIZE) return 0; int num_colors = 0;
uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
uint32_t colors[MAX_PALETTE_SIZE * 4];
static const uint32_t kHashMul = 0x1e35a7bd;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
if (argb[x] == last_pix) {
continue;
}
last_pix = argb[x];
key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
while (1) {
if (!in_use[key]) {
colors[key] = last_pix;
in_use[key] = 1;
++num_colors;
if (num_colors > MAX_PALETTE_SIZE) {
return 0;
}
break;
} else if (colors[key] == last_pix) {
// The color is already there.
break;
} else {
// Some other color sits there.
// Do linear conflict resolution.
++key;
key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
}
}
}
argb += pic->argb_stride;
}
// TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
num_colors = 0;
for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
if (in_use[i]) {
palette[num_colors] = colors[i];
++num_colors;
}
}
*palette_size = num_colors; *palette_size = num_colors;
qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort); qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) { if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {

View File

@ -646,6 +646,61 @@ static int IsLossyBlendingPossible(const WebPPicture* const src,
return 1; return 1;
} }
#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold.
#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold.
#define MAX_COLOR_COUNT 256 // Power of 2 greater than MAX_COLORS_LOSSLESS.
#define HASH_SIZE (MAX_COLOR_COUNT * 4)
#define HASH_RIGHT_SHIFT 22 // 32 - log2(HASH_SIZE).
// TODO(urvang): Also used in enc/vp8l.c. Move to utils.
// If the number of colors in the 'pic' is at least MAX_COLOR_COUNT, return
// MAX_COLOR_COUNT. Otherwise, return the exact number of colors in the 'pic'.
static int GetColorCount(const WebPPicture* const pic) {
int x, y;
int num_colors = 0;
uint8_t in_use[HASH_SIZE] = { 0 };
uint32_t colors[HASH_SIZE];
static const uint32_t kHashMul = 0x1e35a7bd;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
int key;
if (argb[x] == last_pix) {
continue;
}
last_pix = argb[x];
key = (kHashMul * last_pix) >> HASH_RIGHT_SHIFT;
while (1) {
if (!in_use[key]) {
colors[key] = last_pix;
in_use[key] = 1;
++num_colors;
if (num_colors >= MAX_COLOR_COUNT) {
return MAX_COLOR_COUNT; // Exact count not needed.
}
break;
} else if (colors[key] == last_pix) {
break; // The color is already there.
} else {
// Some other color sits here, so do linear conflict resolution.
++key;
key &= (HASH_SIZE - 1); // Key mask.
}
}
}
argb += pic->argb_stride;
}
return num_colors;
}
#undef MAX_COLOR_COUNT
#undef HASH_SIZE
#undef HASH_RIGHT_SHIFT
// For pixels in 'rect', replace those pixels in 'dst' that are same as 'src' by // For pixels in 'rect', replace those pixels in 'dst' that are same as 'src' by
// transparent pixels. // transparent pixels.
static void IncreaseTransparency(const WebPPicture* const src, static void IncreaseTransparency(const WebPPicture* const src,
@ -802,9 +857,6 @@ enum {
CANDIDATE_COUNT CANDIDATE_COUNT
}; };
#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold.
#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold.
// Generates candidates for a given dispose method given pre-filled sub-frame // Generates candidates for a given dispose method given pre-filled sub-frame
// 'params'. // 'params'.
static WebPEncodingError GenerateCandidates( static WebPEncodingError GenerateCandidates(
@ -839,7 +891,7 @@ static WebPEncodingError GenerateCandidates(
candidate_ll->evaluate_ = is_lossless; candidate_ll->evaluate_ = is_lossless;
candidate_lossy->evaluate_ = !is_lossless; candidate_lossy->evaluate_ = !is_lossless;
} else { // Use a heuristic for trying lossless and/or lossy compression. } else { // Use a heuristic for trying lossless and/or lossy compression.
const int num_colors = WebPGetColorPalette(&params->sub_frame_ll_, NULL); const int num_colors = GetColorCount(&params->sub_frame_ll_);
candidate_ll->evaluate_ = (num_colors < MAX_COLORS_LOSSLESS); candidate_ll->evaluate_ = (num_colors < MAX_COLORS_LOSSLESS);
candidate_lossy->evaluate_ = (num_colors >= MIN_COLORS_LOSSY); candidate_lossy->evaluate_ = (num_colors >= MIN_COLORS_LOSSY);
} }

View File

@ -15,7 +15,6 @@
#include <string.h> // for memcpy() #include <string.h> // for memcpy()
#include "../webp/decode.h" #include "../webp/decode.h"
#include "../webp/encode.h" #include "../webp/encode.h"
#include "../webp/format_constants.h" // for MAX_PALETTE_SIZE
#include "./utils.h" #include "./utils.h"
// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of // If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
@ -238,68 +237,3 @@ void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#define MAX_COLOR_COUNT MAX_PALETTE_SIZE
#define COLOR_HASH_SIZE (MAX_COLOR_COUNT * 4)
#define COLOR_HASH_RIGHT_SHIFT 22 // 32 - log2(COLOR_HASH_SIZE).
int WebPGetColorPalette(const WebPPicture* const pic, uint32_t* const palette) {
int i;
int x, y;
int num_colors = 0;
uint8_t in_use[COLOR_HASH_SIZE] = { 0 };
uint32_t colors[COLOR_HASH_SIZE];
static const uint32_t kHashMul = 0x1e35a7bdU;
const uint32_t* argb = pic->argb;
const int width = pic->width;
const int height = pic->height;
uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
assert(pic != NULL);
assert(pic->use_argb);
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
int key;
if (argb[x] == last_pix) {
continue;
}
last_pix = argb[x];
key = (kHashMul * last_pix) >> COLOR_HASH_RIGHT_SHIFT;
while (1) {
if (!in_use[key]) {
colors[key] = last_pix;
in_use[key] = 1;
++num_colors;
if (num_colors > MAX_COLOR_COUNT) {
return MAX_COLOR_COUNT + 1; // Exact count not needed.
}
break;
} else if (colors[key] == last_pix) {
break; // The color is already there.
} else {
// Some other color sits here, so do linear conflict resolution.
++key;
key &= (COLOR_HASH_SIZE - 1); // Key mask.
}
}
}
argb += pic->argb_stride;
}
if (palette != NULL) { // Fill the colors into palette.
num_colors = 0;
for (i = 0; i < COLOR_HASH_SIZE; ++i) {
if (in_use[i]) {
palette[num_colors] = colors[i];
++num_colors;
}
}
}
return num_colors;
}
#undef MAX_COLOR_COUNT
#undef COLOR_HASH_SIZE
#undef COLOR_HASH_RIGHT_SHIFT
//------------------------------------------------------------------------------

View File

@ -160,19 +160,6 @@ WEBP_EXTERN(void) WebPCopyPlane(const uint8_t* src, int src_stride,
WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src, WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
struct WebPPicture* const dst); struct WebPPicture* const dst);
//------------------------------------------------------------------------------
// Unique colors.
// Returns count of unique colors in 'pic', assuming pic->use_argb is true.
// If the unique color count is more than MAX_COLOR_COUNT, returns
// MAX_COLOR_COUNT+1.
// If 'palette' is not NULL and number of unique colors is less than or equal to
// MAX_COLOR_COUNT, also outputs the actual unique colors into 'palette'.
// Note: 'palette' is assumed to be an array already allocated with at least
// MAX_COLOR_COUNT elements.
WEBP_EXTERN(int) WebPGetColorPalette(const struct WebPPicture* const pic,
uint32_t* const palette);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#ifdef __cplusplus #ifdef __cplusplus