mirror of
https://github.com/webmproject/libwebp.git
synced 2024-11-20 04:18:26 +01:00
Refactor palette sorting computation.
This will ease the integration of new methods. Change-Id: Icec3eddaa4ab9030d28ccfe579eb6dc13ded2f02
This commit is contained in:
parent
af7fbfd2d9
commit
1432ebbadb
@ -267,7 +267,7 @@ typedef struct {
|
|||||||
|
|
||||||
// +2 because we add a palette sorting configuration for kPalette and
|
// +2 because we add a palette sorting configuration for kPalette and
|
||||||
// kPaletteAndSpatial.
|
// kPaletteAndSpatial.
|
||||||
#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2)
|
#define CRUNCH_CONFIGS_MAX (kNumEntropyIx + 2 * kPaletteSortingNum)
|
||||||
|
|
||||||
static int EncoderAnalyze(VP8LEncoder* const enc,
|
static int EncoderAnalyze(VP8LEncoder* const enc,
|
||||||
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
|
CrunchConfig crunch_configs[CRUNCH_CONFIGS_MAX],
|
||||||
@ -324,22 +324,30 @@ static int EncoderAnalyze(VP8LEncoder* const enc,
|
|||||||
// a palette.
|
// a palette.
|
||||||
if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
|
if ((i != kPalette && i != kPaletteAndSpatial) || use_palette) {
|
||||||
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
|
assert(*crunch_configs_size < CRUNCH_CONFIGS_MAX);
|
||||||
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
|
||||||
if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
|
if (use_palette && (i == kPalette || i == kPaletteAndSpatial)) {
|
||||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
for (int sorting_method = 0; sorting_method < kPaletteSortingNum;
|
||||||
kMinimizeDelta;
|
++sorting_method) {
|
||||||
++*crunch_configs_size;
|
const PaletteSorting typed_sorting_method =
|
||||||
// Also add modified Zeng's method.
|
(PaletteSorting)sorting_method;
|
||||||
|
// TODO(vrabaud) kSortedDefault should be tested. It is omitted
|
||||||
|
// for now for backward compatibility.
|
||||||
|
if (typed_sorting_method == kUnusedPalette ||
|
||||||
|
typed_sorting_method == kSortedDefault) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
||||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
||||||
kModifiedZeng;
|
typed_sorting_method;
|
||||||
|
++*crunch_configs_size;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
crunch_configs[(*crunch_configs_size)].entropy_idx_ = i;
|
||||||
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
crunch_configs[(*crunch_configs_size)].palette_sorting_type_ =
|
||||||
kUnusedPalette;
|
kUnusedPalette;
|
||||||
}
|
|
||||||
++*crunch_configs_size;
|
++*crunch_configs_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Only choose the guessed best transform.
|
// Only choose the guessed best transform.
|
||||||
*crunch_configs_size = 1;
|
*crunch_configs_size = 1;
|
||||||
@ -1544,21 +1552,12 @@ static int EncodeStreamHook(void* input, void* data2) {
|
|||||||
|
|
||||||
// Encode palette
|
// Encode palette
|
||||||
if (enc->use_palette_) {
|
if (enc->use_palette_) {
|
||||||
if (crunch_configs[idx].palette_sorting_type_ == kSortedDefault) {
|
if (!PaletteSort(crunch_configs[idx].palette_sorting_type_, enc->pic_,
|
||||||
// Nothing to do, we have already sorted the palette.
|
enc->palette_sorted_, enc->palette_size_,
|
||||||
memcpy(enc->palette_, enc->palette_sorted_,
|
enc->palette_)) {
|
||||||
enc->palette_size_ * sizeof(*enc->palette_));
|
|
||||||
} else if (crunch_configs[idx].palette_sorting_type_ == kMinimizeDelta) {
|
|
||||||
PaletteSortMinimizeDeltas(enc->palette_sorted_, enc->palette_size_,
|
|
||||||
enc->palette_);
|
|
||||||
} else {
|
|
||||||
assert(crunch_configs[idx].palette_sorting_type_ == kModifiedZeng);
|
|
||||||
if (!PaletteSortModifiedZeng(enc->pic_, enc->palette_sorted_,
|
|
||||||
enc->palette_size_, enc->palette_)) {
|
|
||||||
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
percent_range = remaining_percent / 4;
|
percent_range = remaining_percent / 4;
|
||||||
if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
|
if (!EncodePalette(bw, low_effort, enc, percent_range, &percent)) {
|
||||||
goto Error;
|
goto Error;
|
||||||
|
@ -182,7 +182,7 @@ static int PaletteHasNonMonotonousDeltas(const uint32_t* const palette,
|
|||||||
return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
|
return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
|
static void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
|
||||||
int num_colors, uint32_t* const palette) {
|
int num_colors, uint32_t* const palette) {
|
||||||
uint32_t predict = 0x00000000;
|
uint32_t predict = 0x00000000;
|
||||||
int i, k;
|
int i, k;
|
||||||
@ -293,9 +293,10 @@ struct Sum {
|
|||||||
uint32_t sum;
|
uint32_t sum;
|
||||||
};
|
};
|
||||||
|
|
||||||
int PaletteSortModifiedZeng(const WebPPicture* const pic,
|
static int PaletteSortModifiedZeng(const WebPPicture* const pic,
|
||||||
const uint32_t* const palette_in,
|
const uint32_t* const palette_in,
|
||||||
uint32_t num_colors, uint32_t* const palette) {
|
uint32_t num_colors,
|
||||||
|
uint32_t* const palette) {
|
||||||
uint32_t i, j, ind;
|
uint32_t i, j, ind;
|
||||||
uint8_t remapping[MAX_PALETTE_SIZE];
|
uint8_t remapping[MAX_PALETTE_SIZE];
|
||||||
uint32_t* cooccurrence;
|
uint32_t* cooccurrence;
|
||||||
@ -375,3 +376,27 @@ int PaletteSortModifiedZeng(const WebPPicture* const pic,
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
int PaletteSort(PaletteSorting method, const struct WebPPicture* const pic,
|
||||||
|
const uint32_t* const palette_sorted, uint32_t num_colors,
|
||||||
|
uint32_t* const palette) {
|
||||||
|
switch (method) {
|
||||||
|
case kSortedDefault:
|
||||||
|
// Nothing to do, we have already sorted the palette.
|
||||||
|
memcpy(palette, palette_sorted, num_colors * sizeof(*palette));
|
||||||
|
return 1;
|
||||||
|
case kMinimizeDelta:
|
||||||
|
PaletteSortMinimizeDeltas(palette_sorted, num_colors, palette);
|
||||||
|
return 1;
|
||||||
|
case kModifiedZeng:
|
||||||
|
return PaletteSortModifiedZeng(pic, palette_sorted, num_colors, palette);
|
||||||
|
case kUnusedPalette:
|
||||||
|
case kPaletteSortingNum:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -21,9 +21,15 @@ struct WebPPicture;
|
|||||||
// The different ways a palette can be sorted.
|
// The different ways a palette can be sorted.
|
||||||
typedef enum PaletteSorting {
|
typedef enum PaletteSorting {
|
||||||
kSortedDefault = 0,
|
kSortedDefault = 0,
|
||||||
|
// Sorts by minimizing L1 deltas between consecutive colors, giving more
|
||||||
|
// weight to RGB colors.
|
||||||
kMinimizeDelta = 1,
|
kMinimizeDelta = 1,
|
||||||
|
// Implements the modified Zeng method from "A Survey on Palette Reordering
|
||||||
|
// Methods for Improving the Compression of Color-Indexed Images" by Armando
|
||||||
|
// J. Pinho and Antonio J. R. Neves.
|
||||||
kModifiedZeng = 2,
|
kModifiedZeng = 2,
|
||||||
kUnusedPalette = 3
|
kUnusedPalette = 3,
|
||||||
|
kPaletteSortingNum = 4
|
||||||
} PaletteSorting;
|
} PaletteSorting;
|
||||||
|
|
||||||
// Returns the index of 'color' in the sorted palette 'sorted' of size
|
// Returns the index of 'color' in the sorted palette 'sorted' of size
|
||||||
@ -44,19 +50,11 @@ void PrepareMapToPalette(const uint32_t palette[], uint32_t num_colors,
|
|||||||
int GetColorPalette(const struct WebPPicture* const pic,
|
int GetColorPalette(const struct WebPPicture* const pic,
|
||||||
uint32_t* const palette);
|
uint32_t* const palette);
|
||||||
|
|
||||||
// Sorts the color sorted palette in 'palette_sorted'/'num_colors' by
|
// Sorts the palette according to the criterion defined by 'method'.
|
||||||
// minimizing deltas between consecutive colors and stores it in 'palette'.
|
// 'palette_sorted' is the input palette sorted lexicographically, as done in
|
||||||
void PaletteSortMinimizeDeltas(const uint32_t* const palette_sorted,
|
// PrepareMapToPalette. Returns 0 on memory allocation error.
|
||||||
int num_colors, uint32_t* const palette);
|
int PaletteSort(PaletteSorting method, const struct WebPPicture* pic,
|
||||||
|
const uint32_t* palette_sorted, uint32_t num_colors,
|
||||||
// Implements the modified Zeng method from "A Survey on Palette Reordering
|
uint32_t* palette);
|
||||||
// Methods for Improving the Compression of Color-Indexed Images" by Armando J.
|
|
||||||
// Pinho and Antonio J. R. Neves. The palette defined by 'palette_in' and
|
|
||||||
// 'num_colors' is sorted using information from 'pic' and output in
|
|
||||||
// 'palette'.
|
|
||||||
// Returns 0 on memory allocation error.
|
|
||||||
int PaletteSortModifiedZeng(const struct WebPPicture* const pic,
|
|
||||||
const uint32_t* const palette_in,
|
|
||||||
uint32_t num_colors, uint32_t* const palette);
|
|
||||||
|
|
||||||
#endif // WEBP_UTILS_PALETTE_H_
|
#endif // WEBP_UTILS_PALETTE_H_
|
||||||
|
Loading…
Reference in New Issue
Block a user