blob: c883c0185f6bdc82f699604b39153c7f85df51cd [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// -----------------------------------------------------------------------------
//
// Common code dealing with symbols.
//
// Author: Vincent Rabaud (vrabaud@google.com)
#ifndef WP2_COMMON_SYMBOLS_H_
#define WP2_COMMON_SYMBOLS_H_
#include <cassert>
#include <cstdint>
#include <limits>
#include "src/common/constants.h"
#include "src/common/lossy/block_size.h"
#include "src/dsp/math.h"
#include "src/utils/ans.h"
#include "src/utils/ans_enc.h"
#include "src/utils/utils.h"
#include "src/utils/vector.h"
#include "src/wp2/base.h"
#include "src/wp2/format_constants.h"
//------------------------------------------------------------------------------
namespace WP2 {
// Maximum number of symbol types to use.
static constexpr uint32_t kSymbolNumMax = 41;
// Number of residual clusters, not including sectors.
// Y/UV/A * Method0/Method1 * transform.
static constexpr uint32_t kResidualClusters = 3 * kNumResidualStats * TRF_LAST;
// Class containing info about the size (in bits) of the different symbols
// (colors, cache index and LZ77 distance/length).
// WARNING! This is a *big* object. Don't use on the stack!
class SymbolsInfo {
public:
// Bound to use when a symbol is unused.
static constexpr int32_t kInvalidBound = std::numeric_limits<int32_t>::max();
enum class StorageMethod {
// Automatically choose between dictionary, range, prefix coding.
kAuto,
// Adaptive bit using counts of 0/1 so far for probabilities.
kAdaptiveBit,
// Adaptive symbol (that can be of size 2, but uses the adaptive symbol
// method).
kAdaptiveSym,
// Adaptive symbol, with automatically chosen adaptation speed (signaled
// in the header). Only allowed for symbols that occur at most once per
// block and whose values fit in a uint8_t, because we keep all symbols
// in memory which might quickly add up.
kAdaptiveWithAutoSpeed,
kUnused
};
SymbolsInfo() = default;
SymbolsInfo(const SymbolsInfo& other) = delete;
SymbolsInfo& operator=(const SymbolsInfo& info) = delete;
// TODO(maryla): CopyFrom is fairly expensive (this is a big object) and I
// think we currently use it in some places where we don't
// actually need a copy.
WP2Status CopyFrom(const SymbolsInfo& other);
// 'use_splits' is true if block geometry is encoded through splits, false if
// encoded through block sizes.
WP2Status InitLossy(uint32_t num_segments, PartitionSet partition_set,
bool has_alpha, bool use_aom_coeffs, bool use_splits);
// Whether a symbol is used at all.
inline bool IsUnused(uint32_t sym) const {
return (Method(sym) == StorageMethod::kUnused);
}
// Invalidate the use of a given symbol.
void SetUnused(uint32_t sym, uint32_t num_clusters = 0);
void SetInfo(uint32_t sym, int32_t min, int32_t max, uint32_t num_clusters,
StorageMethod method, bool probably_geometric = false);
// Sets symbol range for all clusters. Indicates that symbol values are in
// [min; max]. For now, only min=0 or min=-max is supported.
// Overwrites any values previously set through
// SetMinMax(sym,min,max) or SetMinMax(cluster,min,max).
// The convention min==max==kInvalidBound means the symbol will never be used.
void SetMinMax(uint32_t sym, int32_t min, int32_t max);
// Sets symbol range for a specific cluster. Overrides any value previously
// set through SetMinMax(sym,min,max) for that cluster.
WP2Status SetMinMax(uint32_t sym, uint32_t cluster, int32_t min, int32_t max);
void SetClusters(uint32_t sym, uint32_t num_clusters);
WP2Status SetStartingProba(uint32_t sym, uint32_t cluster, uint32_t p0,
uint32_t p1);
uint32_t StartingProbaP0(uint32_t sym, uint32_t cluster) const {
assert(Method(sym) == StorageMethod::kAdaptiveBit &&
Range(sym, cluster) == 2);
return GetClusterInfo(sym, cluster).p0;
}
uint32_t StartingProbaP1(uint32_t sym, uint32_t cluster) const {
assert(Method(sym) == StorageMethod::kAdaptiveBit &&
Range(sym, cluster) == 2);
return GetClusterInfo(sym, cluster).p1;
}
void GetInitialCDF(uint32_t sym, uint32_t cluster, const uint16_t** cdf,
uint16_t* max_proba) const;
WP2Status SetInitialCDF(uint32_t sym, uint32_t cluster, const uint16_t* cdf,
uint16_t max_proba);
// Range of the symbol of bounds [min,max]: max-min+1.
inline uint32_t Range(uint32_t sym, uint32_t cluster) const {
const ClusterInfo& info_cluster = GetClusterInfo(sym, cluster);
if (info_cluster.min != kInvalidBound &&
info_cluster.max != kInvalidBound) {
return info_cluster.max - info_cluster.min + 1;
}
const SymbolInfo& info_sym = GetSymbolInfo(sym);
if (info_sym.min != kInvalidBound && info_sym.max != kInvalidBound) {
return info_sym.max - info_sym.min + 1;
}
return 0u;
}
inline int32_t Min(uint32_t sym, uint32_t cluster) const {
const ClusterInfo& info_cluster = GetClusterInfo(sym, cluster);
if (info_cluster.min != kInvalidBound &&
info_cluster.max != kInvalidBound) {
return info_cluster.min;
}
return GetSymbolInfo(sym).min;
}
inline int32_t Max(uint32_t sym, uint32_t cluster) const {
const ClusterInfo& info_cluster = GetClusterInfo(sym, cluster);
if (info_cluster.min != kInvalidBound &&
info_cluster.max != kInvalidBound) {
return info_cluster.max;
}
return GetSymbolInfo(sym).max;
}
inline StorageMethod Method(uint32_t sym) const {
return GetSymbolInfo(sym).storage_method;
}
inline bool IsAdaptiveMethod(uint32_t sym) const {
const StorageMethod method = Method(sym);
return (method == StorageMethod::kAdaptiveSym ||
method == StorageMethod::kAdaptiveWithAutoSpeed);
}
// Whether values for this symbol are likely to follow a geometric
// distribution. This information can be used when estimating the cost
// of storing this symbol.
inline bool ProbablyGeometric(const uint32_t sym) const {
return GetSymbolInfo(sym).probably_geometric;
}
inline uint32_t NumClusters(const uint32_t sym) const {
return GetSymbolInfo(sym).num_clusters;
}
// Gets the sum of the max ranges of all the symbols.
// TODO(maryla): not sure this is needed, it seems it's usually called for
// symbols that have 1 cluster, in which case it's equivalent to RangeSum().
uint32_t MaxRangeSum() const;
// Gets the sum of the ranges of all the symbols/clusters.
uint32_t RangeSum() const;
// Gets the maximum range among all the symbols and clusters.
uint32_t GetMaxRange() const;
// Gets the maximum range for a given symbol among all clusters.
uint32_t GetMaxRange(uint32_t sym) const;
// maximum number of symbols potentially used
uint32_t Size() const { return num_symbols_; }
protected:
struct ClusterInfo {
// Overrides SymbolInfo.min if min <= max.
int min = kInvalidBound;
int max = kInvalidBound;
// Starting probabilities for StorageMethod::kAdaptiveBit.
uint32_t p0 = 1, p1 = 1;
// Pointer to a reference cdf to use.
const uint16_t* cdf = nullptr;
// Max proba in the CDF.
uint16_t max_proba;
};
struct SymbolInfo {
StorageMethod storage_method = StorageMethod::kAuto;
int min = kInvalidBound;
int max = kInvalidBound;
// Index of start of per-cluster info in cluster_info_.
int cluster_info_index = kNoPerClusterInfo;
uint32_t num_clusters = 0;
// Whether values are likely to follow a geometric distribution.
bool probably_geometric = false;
static constexpr int kNoPerClusterInfo = -1;
bool MinMaxIsValid(int new_min, int new_max) const;
};
inline SymbolInfo* GetSymbolInfo(uint32_t sym) { return &symbols_info_[sym]; }
inline const SymbolInfo& GetSymbolInfo(uint32_t sym) const {
return symbols_info_[sym];
}
// Returns the ClusterInfo for the given cluster/sym, initializing the
// per-cluster info storage if needed.
ClusterInfo* GetOrMakeClusterInfo(uint32_t sym, uint32_t cluster);
const ClusterInfo& GetClusterInfo(uint32_t sym, uint32_t cluster) const;
static const ClusterInfo kDefaultClusterInfo;
protected:
uint32_t num_symbols_ = 0;
SymbolInfo symbols_info_[kSymbolNumMax];
Vector<ClusterInfo> cluster_info_;
uint32_t next_cluster_info_index_ = 0;
};
//------------------------------------------------------------------------------
// Split the symbol 'v' into a 'prefix' (corresponding to the first
// 'prefix_size' bits), the number of extra bits, and the value contained in
// those extra bits. This prefix coding is used in deflate (cf rfc1951) and is
// close to an exponential Golomb.
struct PrefixCode {
PrefixCode(uint32_t v, uint32_t prefix_size) {
if (v < (2u << prefix_size)) {
prefix = v;
extra_bits_num = 0;
extra_bits_value = 0;
return;
}
const uint32_t highest_bit_index = WP2Log2Floor(v);
extra_bits_num = highest_bit_index - prefix_size;
const uint32_t other_highest_bits =
(v - (1 << highest_bit_index)) >> extra_bits_num;
// Store highest bit position and the next highest bits into an int.
prefix = ((extra_bits_num + 1) << prefix_size) + other_highest_bits;
extra_bits_value = v & ((1 << extra_bits_num) - 1);
}
// Given a 'prefix', returns the number of extra bits required to complete
// it.
static uint32_t NumExtraBits(uint32_t prefix, uint32_t prefix_size) {
if (prefix < (2u << prefix_size)) return 0;
return (prefix >> prefix_size) - 1;
}
// Given a 'prefix' and 'extra_bits_value', combine the two to reconstruct
// the final value.
static uint32_t Merge(uint32_t prefix, uint32_t prefix_size,
uint32_t extra_bits_value) {
if (prefix < (2u << prefix_size)) return prefix;
const uint32_t extra_bits_num = (prefix >> prefix_size) - 1;
uint32_t offset = 1 << prefix_size;
offset += prefix & ((1 << prefix_size) - 1);
offset <<= extra_bits_num;
return offset + extra_bits_value;
}
uint32_t prefix;
uint32_t extra_bits_num;
uint32_t extra_bits_value;
};
// Read/write a value in [min, max] using prefix coding.
// 'prefix_size' must be 1 or 2 (number of leading bits coded separately).
void WritePrefixCode(int32_t value, int32_t min, int32_t max,
uint32_t prefix_size, ANSEncBase* enc, WP2_OPT_LABEL);
int32_t ReadPrefixCode(int32_t min, int32_t max, uint32_t prefix_size,
ANSDec* dec, WP2_OPT_LABEL);
//------------------------------------------------------------------------------
// Class common to decoder to read/write statistics in an image.
// It is made common to have a similar behavior when analyzing tiles.
template <class EXTRA>
class SymbolIO {
public:
virtual ~SymbolIO() = default;
// Allocates data after ranges/cluster sizes have been specified.
virtual WP2Status Allocate() {
const uint32_t size = symbols_info_.RangeSum();
uint32_t size_contexts = 0;
for (uint32_t sym = 0; sym < symbols_info_.Size(); ++sym) {
size_contexts += symbols_info_.NumClusters(sym);
}
WP2_CHECK_ALLOC_OK(mappings_buffer_.resize(size));
WP2_CHECK_ALLOC_OK(all_stats_.resize(size_contexts));
// Prepare the mappings to point to the right spot in the buffer.
auto* mapping_buffer = mappings_buffer_.data();
for (uint32_t sym = 0, ind = 0; sym < symbols_info_.Size(); ++sym) {
stats_start_[sym] = &all_stats_[ind];
for (uint32_t c = 0; c < symbols_info_.NumClusters(sym); ++c) {
all_stats_[ind].type = Stat::Type::kUnknown;
all_stats_[ind].use_mapping = false;
all_stats_[ind].range = 0;
all_stats_[ind].mappings = mapping_buffer;
mapping_buffer += symbols_info_.Range(sym, c);
++ind;
}
}
return WP2_STATUS_OK;
}
// Fills the array 'is_maybe_used' with true when the symbol might be used,
// false if we are sure it is not used.
virtual void GetPotentialUsage(uint32_t sym, uint32_t cluster,
bool is_maybe_used[], uint32_t size) const = 0;
protected:
// The stats of a symbol.
struct Stat {
static const uint16_t kInvalidMapping;
enum class Type {
// We have no information on this symbol.
kUnknown,
// Symbol always has the same value or is unused.
kTrivial,
// Symbol is stored as a range (all values assumed to have equal
// probability).
kRange,
// Symbol is stored as a dictionary.
kDict,
// Symbol is stored with a prefix code.
kPrefixCode,
// Symbol is stored as an adaptive bit.
kAdaptiveBit,
// Symbol is stored as an adaptive symbol.
kAdaptiveSymbol,
};
Type type;
// Whether to use 'mappings' to map raw stored values to symbol values.
bool use_mapping;
uint16_t* mappings;
// If set to true, it assumes values are stored as abs(value) + sign with
// abs(value) stored as range/dict/prefix code/... Otherwise, value - min is
// the one stored as range/dict/prefix code/...
bool is_symmetric;
// For type kRange, the symbol is stored as a value in [0;range[
uint16_t range;
union Param {
// For type kPrefixCode.
struct {
// Range of the prefix.
uint16_t range;
// Size in bits of the prefix code.
uint8_t prefix_size;
} prefix_code;
// For type kTrivial, there is only one value. If the range contains
// negative and positive values, the sign is stored apart.
uint16_t trivial_value;
// For type kAdaptive where range is 2.
// Index of this adaptive bit a_bits_.
uint32_t a_bit_index;
// For type kAdaptive where range is != 2.
// Index of the adaptive symbol in a_symbols_.
uint32_t a_symbol_index;
};
Param param;
EXTRA extra;
};
// Sets basic information about symbols.
WP2Status Init(const SymbolsInfo& symbols_info) {
WP2_CHECK_STATUS(symbols_info_.CopyFrom(symbols_info));
return WP2_STATUS_OK;
}
// Gets the statistics for symbol 'sym' in cluster 'cluster'.
inline Stat* GetStats(uint32_t sym, uint32_t cluster) {
assert(sym < symbols_info_.Size() &&
cluster < symbols_info_.NumClusters(sym));
return &stats_start_[sym][cluster];
}
inline const Stat* GetStats(uint32_t sym, uint32_t cluster) const {
assert(sym < symbols_info_.Size() &&
cluster < symbols_info_.NumClusters(sym));
return &stats_start_[sym][cluster];
}
// Helper function to set the stats of symbol 'sym' at 'cluster' to be proper
// prefix code.
void SetPrefixCodeStat(uint32_t sym, uint32_t cluster, uint32_t prefix_size) {
Stat* const stat = GetStats(sym, cluster);
stat->type = Stat::Type::kPrefixCode;
stat->range = symbols_info_.Range(sym, cluster);
const PrefixCode prefix_code = PrefixCode(stat->range - 1, prefix_size);
stat->param.prefix_code.range = prefix_code.prefix + 1;
stat->param.prefix_code.prefix_size = prefix_size;
}
// Sets up the given symbol as an adaptive bit.
WP2Status AddAdaptiveBit(uint32_t sym, uint32_t cluster, uint32_t p0 = 1,
uint32_t p1 = 1) {
Stat* const stat = GetStats(sym, cluster);
stat->type = Stat::Type::kAdaptiveBit;
stat->is_symmetric = false;
stat->use_mapping = false;
stat->range = 2;
stat->param.a_bit_index = a_bits_.size();
WP2_CHECK_ALLOC_OK(a_bits_.push_back(ANSBinSymbol(p0, p1)));
return WP2_STATUS_OK;
}
// Sets up the given symbol as an adaptive symbol.
WP2Status AddAdaptiveSymbol(uint32_t sym, uint32_t cluster,
ANSAdaptiveSymbol::Method method,
uint32_t speed) {
Stat* const stat = GetStats(sym, cluster);
stat->type = Stat::Type::kAdaptiveSymbol;
stat->is_symmetric = false;
stat->use_mapping = false;
const uint32_t range = symbols_info_.Range(sym, cluster);
stat->range = range;
stat->param.a_symbol_index = a_symbols_.size();
const uint16_t* cdf;
uint16_t max_proba;
symbols_info_.GetInitialCDF(sym, cluster, &cdf, &max_proba);
WP2_CHECK_STATUS(a_symbols_.Add(range, cdf, max_proba));
auto& asym = a_symbols_[stat->param.a_symbol_index];
asym.SetAdaptationSpeed(method, speed);
return WP2_STATUS_OK;
}
SymbolsInfo symbols_info_;
ANSAdaptiveBits a_bits_;
ANSAdaptiveSymbols a_symbols_;
// For each symbol 'sym', the statistics for all clusters start at
// stats_start_[sym].
Stat* stats_start_[kSymbolNumMax];
VectorNoCtor<Stat> all_stats_;
Vector_u16 mappings_buffer_;
};
template <class T>
const uint16_t SymbolIO<T>::Stat::kInvalidMapping =
std::numeric_limits<uint16_t>::max();
} // namespace WP2
//------------------------------------------------------------------------------
// Info about the symbols.
namespace WP2 {
enum Symbol {
kSymbolModeY = 0, // prediction modes for Y
kSymbolModeUV, // prediction modes for U/V
kSymbolModeA, // prediction mode for A
kSymbolSegmentId,
kSymbolRndMtx0,
// Symbol for the block transform (same in X and Y).
kSymbolTransform,
// Symbol for whether the block contains several transforms or not.
kSymbolSplitTransform,
// Symbol for BlockAlphaMode for each block.
kSymbolBlockAlphaMode,
// Symbol for whether the block uses 420 (downscaled UV).
kSymbolYuv420,
// Symbol for whether the block uses random matrices.
kSymbolUseRandomMatrix,
// Symbol for whether at least one coeff is not zero.
kSymbolHasCoeffs,
// Symbol for the residual encoding method for Y, U and V.
kSymbolEncodingMethod,
// Symbol for the residual encoding method for A.
kSymbolEncodingMethodA,
// Slope ('a' in 'chroma = a * luma + b') for chroma-from-luma prediction.
kSymbolCflSlope,
// Block size or block split. One cluster per bounding BlockSize.
kSymbolBlockSize,
// ------------------
// Residual encoding
// ------------------
// Number of zero residuals before the enc of blocK
kSymbolResNumZeros,
// Symbols for small residuals.
kSymbolBits0,
// Symbols for the prefix of big residuals.
kSymbolBits1,
// Symbols for DC residuals.
kSymbolDC,
// Symbol for the prefix of DC coefficients.
kSymbolDCDict,
// Whether we use 1 or 2 boundaries for the coefficients.
kSymbolResidualUseBounds,
// Whether the first used boundary is X.
kSymbolResidualBound1IsX,
// Whether we store the second boundary for the coefficients.
kSymbolResidualUseBound2,
// Whether the residual value is 0.
kSymbolResidualIsZero,
// Whether the residual value is 1.
kSymbolResidualIsOne,
// Whether the residual value is 2.
kSymbolResidualIsTwo,
// Whether all residuals after this one are 0.
kSymbolResidualEndOfBlock,
// Whether all residuals after this one are 1 or -1.
kSymbolResidualHasOnlyOnesLeft,
// ---------------------
// AOM residual encoding
// ---------------------
kAOMEOBPT4,
kAOMEOBPT8,
kAOMEOBPT16,
kAOMEOBPT32,
kAOMEOBPT64,
kAOMEOBPT128,
kAOMEOBPT256,
kAOMEOBPT512,
kAOMEOBPT1024,
kAOMEOBExtra,
kAOMCoeffBaseEOB,
kAOMCoeffBase,
kAOMCoeffBaseRange,
kSymbolNum
};
static_assert(kSymbolNum <= kSymbolNumMax, "kSymbolNumMax too small");
constexpr Symbol kSymbolsForCoeffs[] = {
kSymbolResidualIsZero, kSymbolResidualIsOne, kSymbolResidualIsTwo,
kSymbolResidualEndOfBlock, kSymbolResidualHasOnlyOnesLeft};
constexpr Symbol kSymbolsForCoeffsPerTf[] = {
kSymbolDC, kSymbolResidualUseBounds, kSymbolResidualBound1IsX,
kSymbolResidualUseBound2};
constexpr Symbol kSymbolsForAOMCoeffs[] = {
kAOMEOBPT4, kAOMEOBPT8, kAOMEOBPT16, kAOMEOBPT32,
kAOMEOBPT64, kAOMEOBPT128, kAOMEOBPT256, kAOMEOBPT512,
kAOMEOBPT1024, kAOMEOBExtra, kAOMCoeffBaseEOB, kAOMCoeffBase,
kAOMCoeffBaseRange};
enum SymbolCount {
kSymbolCountZero = 0,
kSymbolCountOne,
kSymbolCountMoreThanOne,
kSymbolCountLast
};
enum AlphaMode { kAlphaModeLossless = 0, kAlphaModeLossy, kAlphaModeNum };
enum BlockAlphaMode {
kBlockAlphaFullTransp, // All pixels have an alpha of 0.
kBlockAlphaFullOpaque, // All pixels have an alpha of kAlphaMax.
kBlockAlphaLossy, // Block alpha is encoded lossily.
kBlockAlphaLossless, // Block alpha is encoded losslessly.
};
enum class ChromaSubsampling {
k420,
k444,
kAdaptive, // Can differ from one block to the next.
kSingleBlock, // Do not signal anything before decoding the only block.
};
} // namespace WP2
namespace WP2L {
enum Symbol {
kSymbolType = 0, // one of the SymbolType
kSymbolA,
kSymbolR,
kSymbolG,
kSymbolB,
kSymbolColorCache,
kSymbolSegmentCache,
kSymbolDist,
kSymbolLen,
kSymbolSubMode,
kSymbolNum
};
static const char* const kSymbolNames[] = {
"type", "a", "r", "g", "b", "color_cache",
"segment_cache", "dist", "len", "sub_mode"};
STATIC_ASSERT_ARRAY_SIZE(kSymbolNames, kSymbolNum);
// Group 4 symbols.
enum SymbolGroup4 {
kSymbolG4Type,
kSymbolG4HorizontalDist,
kSymbolG4VerticalDist,
// Boolean to signal if the next color is different from the expected one
// (as deduced from previous row).
kSymbolG4ColorChange,
// Index of the new color if kSymbolG4ColorChange was true.
kSymbolG4NewColor,
kSymbolG4Num
};
static const char* const kSymbolGroup4Names[] = {"type", "hdist", "vdist",
"color_change", "new_color"};
STATIC_ASSERT_ARRAY_SIZE(kSymbolGroup4Names, kSymbolG4Num);
// Initializes a SymbolsInfo to be used with Group 4 algorithm.
void InitGroup4(uint32_t width, uint32_t num_colors, WP2::SymbolsInfo* info);
static_assert(kSymbolNum <= WP2::kSymbolNumMax, "kSymbolNumMax too small");
enum SymbolType {
kSymbolTypeLiteral, // literal value
kSymbolTypeCopy, // copy from (distance, length)
kSymbolTypeColorCacheIdx, // index in the color cache
kSymbolTypeSegmentCacheIdx, // index in the segment cache
kSymbolTypeNum,
kSymbolTypeDiscarded // discarded symbol due to segment cache
};
// Returns whether a symbol will be potentially used, depending on type.
bool IsSymbolUsed(Symbol sym, const bool is_maybe_used[kSymbolTypeNum]);
// Class containing info about the size (in bits) of the different symbols
// (colors, cache index and LZ77 distance/length).
class LosslessSymbolsInfo : public WP2::SymbolsInfo {
public:
LosslessSymbolsInfo();
// By default, there is only one cluster per symbol and the cache bits are set
// to 0.
void Init(uint32_t num_pixels, bool has_alpha, WP2SampleFormat format);
// Set the symbols A,R,B as useless as all the information will be stored in
// G channel.
void InitAsLabelImage(uint32_t num_pixels, uint32_t num_labels);
// Set the symbol A as useless and R,G,B as ranging with the cross color image
// bounds kRedToBlueMax, kGreenToBlueMax, kGreenToRedMax
void InitAsCrossColorImage(uint32_t num_pixels);
// Initialize to store predictors.
void InitAsPredictorImage(uint32_t num_pixels);
// Initialize kSymbolSubMode.
WP2Status InitSubMode();
virtual ~LosslessSymbolsInfo() = default;
WP2Status CopyFrom(const LosslessSymbolsInfo& other);
// Changes the number of clusters for all symbols.
void SetNumClusters(uint32_t num_clusters);
// Sets the range of the color cache and segment cache (if used).
void SetCacheRange(uint32_t cache_range, bool has_segment_cache);
WP2SampleFormat SampleFormat() const { return sample_format_; }
// Returns whether alpha is used and whether it is a label image (ARB unused).
static bool HasAlpha(const SymbolsInfo& info);
static bool IsLabelImage(const SymbolsInfo& info);
private:
void InitNonARGB(uint32_t num_pixels);
WP2SampleFormat sample_format_;
uint32_t num_pixels_;
};
} // namespace WP2L
//------------------------------------------------------------------------------
#endif // WP2_COMMON_SYMBOLS_H_