ifdef code not used by Chrome/Android.
Change-Id: Id086f6fd602b1fe3dc9034764b6a920a696ff1d2
This commit is contained in:
parent
3993af127e
commit
a80fcc4ae1
@ -10,6 +10,7 @@ option(WEBP_BUILD_GIF2WEBP "Build the gif2webp conversion tool." OFF)
|
|||||||
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." OFF)
|
option(WEBP_BUILD_IMG2WEBP "Build the img2webp animation tool." OFF)
|
||||||
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." OFF)
|
option(WEBP_BUILD_WEBPINFO "Build the webpinfo command line tool." OFF)
|
||||||
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
option(WEBP_BUILD_WEBP_JS "Emscripten build of webp.js." OFF)
|
||||||
|
option(WEBP_ENABLE_NEAR_LOSSLESS "Enable near-lossless encoding" ON)
|
||||||
option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
|
option(WEBP_EXPERIMENTAL_FEATURES "Build with experimental features." OFF)
|
||||||
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF)
|
option(WEBP_ENABLE_SWAP_16BIT_CSP "Enable byte swap for 16 bit colorspaces." OFF)
|
||||||
|
|
||||||
|
@ -140,6 +140,9 @@
|
|||||||
/* Set to 1 if TIFF library is installed */
|
/* Set to 1 if TIFF library is installed */
|
||||||
#cmakedefine WEBP_HAVE_TIFF 1
|
#cmakedefine WEBP_HAVE_TIFF 1
|
||||||
|
|
||||||
|
/* Enable near lossless encoding */
|
||||||
|
#cmakedefine WEBP_NEAR_LOSSLESS 1
|
||||||
|
|
||||||
/* Undefine this to disable thread support. */
|
/* Undefine this to disable thread support. */
|
||||||
#cmakedefine WEBP_USE_THREAD 1
|
#cmakedefine WEBP_USE_THREAD 1
|
||||||
|
|
||||||
|
15
configure.ac
15
configure.ac
@ -689,6 +689,21 @@ fi
|
|||||||
AC_MSG_RESULT(${enable_experimental-no})
|
AC_MSG_RESULT(${enable_experimental-no})
|
||||||
AC_SUBST(USE_EXPERIMENTAL_CODE)
|
AC_SUBST(USE_EXPERIMENTAL_CODE)
|
||||||
|
|
||||||
|
dnl === If --disable-near-lossless is defined, add -DWEBP_NEAR_LOSSLESS=0
|
||||||
|
|
||||||
|
AC_DEFINE(WEBP_NEAR_LOSSLESS, [1], [Enable near lossless encoding])
|
||||||
|
AC_MSG_CHECKING(if --disable-near-lossless option is specified)
|
||||||
|
AC_ARG_ENABLE([near_lossless],
|
||||||
|
AS_HELP_STRING([--disable-near-lossless],
|
||||||
|
[Disable near lossless encoding]),
|
||||||
|
[], [enable_near_lossless=yes])
|
||||||
|
if test "$enable_near_lossless" = "no"; then
|
||||||
|
AC_DEFINE(WEBP_NEAR_LOSSLESS, [0], [Enable near lossless encoding])
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
fi
|
||||||
|
|
||||||
dnl === Check whether libwebpmux should be built
|
dnl === Check whether libwebpmux should be built
|
||||||
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
AC_MSG_CHECKING(whether libwebpmux is to be built)
|
||||||
AC_ARG_ENABLE([libwebpmux],
|
AC_ARG_ENABLE([libwebpmux],
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "./vp8li_enc.h"
|
#include "./vp8li_enc.h"
|
||||||
|
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
|
||||||
#define MIN_DIM_FOR_NEAR_LOSSLESS 64
|
#define MIN_DIM_FOR_NEAR_LOSSLESS 64
|
||||||
#define MAX_LIMIT_BITS 5
|
#define MAX_LIMIT_BITS 5
|
||||||
|
|
||||||
@ -140,3 +142,10 @@ int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
|||||||
WebPSafeFree(copy_buffer);
|
WebPSafeFree(copy_buffer);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
#else // (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
|
||||||
|
// Define a stub to suppress compiler warnings.
|
||||||
|
extern void VP8LNearLosslessStub(void);
|
||||||
|
WEBP_TSAN_IGNORE_FUNCTION void VP8LNearLosslessStub(void) {}
|
||||||
|
|
||||||
|
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
@ -26,7 +26,6 @@ static const uint32_t kMaskAlpha = 0xff000000;
|
|||||||
|
|
||||||
// Mostly used to reduce code size + readability
|
// Mostly used to reduce code size + readability
|
||||||
static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
|
static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
|
||||||
static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; }
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Methods to calculate Entropy (Shannon).
|
// Methods to calculate Entropy (Shannon).
|
||||||
@ -90,6 +89,9 @@ static WEBP_INLINE void PredictBatch(int mode, int x_start, int y,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
static WEBP_INLINE int GetMax(int a, int b) { return (a < b) ? b : a; }
|
||||||
|
|
||||||
static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) {
|
static int MaxDiffBetweenPixels(uint32_t p1, uint32_t p2) {
|
||||||
const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24));
|
const int diff_a = abs((int)(p1 >> 24) - (int)(p2 >> 24));
|
||||||
const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff));
|
const int diff_r = abs((int)((p1 >> 16) & 0xff) - (int)((p2 >> 16) & 0xff));
|
||||||
@ -220,6 +222,7 @@ static uint32_t NearLossless(uint32_t value, uint32_t predict,
|
|||||||
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
return ((uint32_t)a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||||
}
|
}
|
||||||
#undef NEAR_LOSSLESS_DIFF
|
#undef NEAR_LOSSLESS_DIFF
|
||||||
|
#endif // (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
|
||||||
// Stores the difference between the pixel and its prediction in "out".
|
// Stores the difference between the pixel and its prediction in "out".
|
||||||
// In case of a lossy encoding, updates the source image to avoid propagating
|
// In case of a lossy encoding, updates the source image to avoid propagating
|
||||||
@ -246,6 +249,7 @@ static WEBP_INLINE void GetResidual(
|
|||||||
} else {
|
} else {
|
||||||
predict = pred_func(current_row[x - 1], upper_row + x);
|
predict = pred_func(current_row[x - 1], upper_row + x);
|
||||||
}
|
}
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 ||
|
if (max_quantization == 1 || mode == 0 || y == 0 || y == height - 1 ||
|
||||||
x == 0 || x == width - 1) {
|
x == 0 || x == width - 1) {
|
||||||
residual = VP8LSubPixels(current_row[x], predict);
|
residual = VP8LSubPixels(current_row[x], predict);
|
||||||
@ -256,6 +260,11 @@ static WEBP_INLINE void GetResidual(
|
|||||||
current_row[x] = VP8LAddPixels(predict, residual);
|
current_row[x] = VP8LAddPixels(predict, residual);
|
||||||
// x is never 0 here so we do not need to update upper_row like below.
|
// x is never 0 here so we do not need to update upper_row like below.
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)max_quantization;
|
||||||
|
(void)used_subtract_green;
|
||||||
|
residual = VP8LSubPixels(current_row[x], predict);
|
||||||
|
#endif
|
||||||
if ((current_row[x] & kMaskAlpha) == 0) {
|
if ((current_row[x] & kMaskAlpha) == 0) {
|
||||||
// If alpha is 0, cleanup RGB. We can choose the RGB values of the
|
// 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
|
// residual for best compression. The prediction of alpha itself can be
|
||||||
@ -298,11 +307,12 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
const int max_x = GetMin(tile_size, width - start_x);
|
const int max_x = GetMin(tile_size, width - start_x);
|
||||||
// Whether there exist columns just outside the tile.
|
// Whether there exist columns just outside the tile.
|
||||||
const int have_left = (start_x > 0);
|
const int have_left = (start_x > 0);
|
||||||
const int have_right = (max_x < width - start_x);
|
|
||||||
// Position and size of the strip covering the tile and adjacent columns if
|
// Position and size of the strip covering the tile and adjacent columns if
|
||||||
// they exist.
|
// they exist.
|
||||||
const int context_start_x = start_x - have_left;
|
const int context_start_x = start_x - have_left;
|
||||||
const int context_width = max_x + have_left + have_right;
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
|
const int context_width = max_x + have_left + (max_x < width - start_x);
|
||||||
|
#endif
|
||||||
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
const int tiles_per_row = VP8LSubSampleSize(width, bits);
|
||||||
// Prediction modes of the left and above neighbor tiles.
|
// Prediction modes of the left and above neighbor tiles.
|
||||||
const int left_mode = (tile_x > 0) ?
|
const int left_mode = (tile_x > 0) ?
|
||||||
@ -314,7 +324,9 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
// when at the right edge.
|
// when at the right edge.
|
||||||
uint32_t* upper_row = argb_scratch;
|
uint32_t* upper_row = argb_scratch;
|
||||||
uint32_t* current_row = upper_row + width + 1;
|
uint32_t* current_row = upper_row + width + 1;
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
|
uint8_t* const max_diffs = (uint8_t*)(current_row + width + 1);
|
||||||
|
#endif
|
||||||
float best_diff = MAX_DIFF_COST;
|
float best_diff = MAX_DIFF_COST;
|
||||||
int best_mode = 0;
|
int best_mode = 0;
|
||||||
int mode;
|
int mode;
|
||||||
@ -354,10 +366,12 @@ static int GetBestPredictorForTile(int width, int height,
|
|||||||
memcpy(current_row + context_start_x,
|
memcpy(current_row + context_start_x,
|
||||||
argb + y * width + context_start_x,
|
argb + y * width + context_start_x,
|
||||||
sizeof(*argb) * (max_x + have_left + (y + 1 < height)));
|
sizeof(*argb) * (max_x + have_left + (y + 1 < height)));
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
if (max_quantization > 1 && y >= 1 && y + 1 < height) {
|
if (max_quantization > 1 && y >= 1 && y + 1 < height) {
|
||||||
MaxDiffsForRow(context_width, width, argb + y * width + context_start_x,
|
MaxDiffsForRow(context_width, width, argb + y * width + context_start_x,
|
||||||
max_diffs + context_start_x, used_subtract_green);
|
max_diffs + context_start_x, used_subtract_green);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GetResidual(width, height, upper_row, current_row, max_diffs, mode,
|
GetResidual(width, height, upper_row, current_row, max_diffs, mode,
|
||||||
start_x, start_x + max_x, y, max_quantization, exact,
|
start_x, start_x + max_x, y, max_quantization, exact,
|
||||||
@ -406,8 +420,10 @@ static void CopyImageWithPrediction(int width, int height,
|
|||||||
// when at the right edge.
|
// when at the right edge.
|
||||||
uint32_t* upper_row = argb_scratch;
|
uint32_t* upper_row = argb_scratch;
|
||||||
uint32_t* current_row = upper_row + width + 1;
|
uint32_t* current_row = upper_row + width + 1;
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1);
|
uint8_t* current_max_diffs = (uint8_t*)(current_row + width + 1);
|
||||||
uint8_t* lower_max_diffs = current_max_diffs + width;
|
uint8_t* lower_max_diffs = current_max_diffs + width;
|
||||||
|
#endif
|
||||||
int y;
|
int y;
|
||||||
|
|
||||||
for (y = 0; y < height; ++y) {
|
for (y = 0; y < height; ++y) {
|
||||||
@ -422,6 +438,7 @@ static void CopyImageWithPrediction(int width, int height,
|
|||||||
PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row,
|
PredictBatch(kPredLowEffort, 0, y, width, current_row, upper_row,
|
||||||
argb + y * width);
|
argb + y * width);
|
||||||
} else {
|
} else {
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
if (max_quantization > 1) {
|
if (max_quantization > 1) {
|
||||||
// Compute max_diffs for the lower row now, because that needs the
|
// Compute max_diffs for the lower row now, because that needs the
|
||||||
// contents of argb for the current row, which we will overwrite with
|
// contents of argb for the current row, which we will overwrite with
|
||||||
@ -434,6 +451,7 @@ static void CopyImageWithPrediction(int width, int height,
|
|||||||
used_subtract_green);
|
used_subtract_green);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
for (x = 0; x < width;) {
|
for (x = 0; x < width;) {
|
||||||
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;
|
||||||
|
@ -1567,10 +1567,14 @@ static int EncodeStreamHook(void* input, void* data2) {
|
|||||||
WebPEncodingError err = VP8_ENC_OK;
|
WebPEncodingError err = VP8_ENC_OK;
|
||||||
const int quality = (int)config->quality;
|
const int quality = (int)config->quality;
|
||||||
const int low_effort = (config->method == 0);
|
const int low_effort = (config->method == 0);
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1) || defined(WEBP_EXPERIMENTAL_FEATURES)
|
||||||
const int width = picture->width;
|
const int width = picture->width;
|
||||||
|
#endif
|
||||||
const int height = picture->height;
|
const int height = picture->height;
|
||||||
const size_t byte_position = VP8LBitWriterNumBytes(bw);
|
const size_t byte_position = VP8LBitWriterNumBytes(bw);
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
int use_near_lossless = 0;
|
int use_near_lossless = 0;
|
||||||
|
#endif
|
||||||
int hdr_size = 0;
|
int hdr_size = 0;
|
||||||
int data_size = 0;
|
int data_size = 0;
|
||||||
int use_delta_palette = 0;
|
int use_delta_palette = 0;
|
||||||
@ -1602,6 +1606,7 @@ static int EncodeStreamHook(void* input, void* data2) {
|
|||||||
VP8LBackwardRefsClear(&enc->refs_[0]);
|
VP8LBackwardRefsClear(&enc->refs_[0]);
|
||||||
VP8LBackwardRefsClear(&enc->refs_[1]);
|
VP8LBackwardRefsClear(&enc->refs_[1]);
|
||||||
|
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
// Apply near-lossless preprocessing.
|
// Apply near-lossless preprocessing.
|
||||||
use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ &&
|
use_near_lossless = (config->near_lossless < 100) && !enc->use_palette_ &&
|
||||||
!enc->use_predict_;
|
!enc->use_predict_;
|
||||||
@ -1617,6 +1622,9 @@ static int EncodeStreamHook(void* input, void* data2) {
|
|||||||
} else {
|
} else {
|
||||||
enc->argb_content_ = kEncoderNone;
|
enc->argb_content_ = kEncoderNone;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
enc->argb_content_ = kEncoderNone;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
if (config->use_delta_palette) {
|
if (config->use_delta_palette) {
|
||||||
|
@ -14,6 +14,15 @@
|
|||||||
#ifndef WEBP_ENC_VP8LI_H_
|
#ifndef WEBP_ENC_VP8LI_H_
|
||||||
#define WEBP_ENC_VP8LI_H_
|
#define WEBP_ENC_VP8LI_H_
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "../webp/config.h"
|
||||||
|
#endif
|
||||||
|
// Either WEBP_NEAR_LOSSLESS is defined as 0 in config.h when compiling to
|
||||||
|
// disable near-lossless, or it is enabled by default.
|
||||||
|
#ifndef WEBP_NEAR_LOSSLESS
|
||||||
|
#define WEBP_NEAR_LOSSLESS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "./backward_references_enc.h"
|
#include "./backward_references_enc.h"
|
||||||
#include "./histogram_enc.h"
|
#include "./histogram_enc.h"
|
||||||
#include "../utils/bit_writer_utils.h"
|
#include "../utils/bit_writer_utils.h"
|
||||||
@ -82,10 +91,12 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
|
|||||||
const WebPPicture* const picture,
|
const WebPPicture* const picture,
|
||||||
VP8LBitWriter* const bw, int use_cache);
|
VP8LBitWriter* const bw, int use_cache);
|
||||||
|
|
||||||
|
#if (WEBP_NEAR_LOSSLESS == 1)
|
||||||
// in near_lossless.c
|
// in near_lossless.c
|
||||||
// Near lossless preprocessing in RGB color-space.
|
// Near lossless preprocessing in RGB color-space.
|
||||||
int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
int VP8ApplyNearLossless(const WebPPicture* const picture, int quality,
|
||||||
uint32_t* const argb_dst);
|
uint32_t* const argb_dst);
|
||||||
|
#endif
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
// Image transforms in predictor.c.
|
// Image transforms in predictor.c.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user