/src/libjxl/lib/jxl/modular/transform/palette.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #ifndef LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_ |
7 | | #define LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_ |
8 | | |
9 | | #include <algorithm> |
10 | | #include <array> |
11 | | #include <cstddef> |
12 | | #include <cstdint> |
13 | | |
14 | | #include "lib/jxl/base/compiler_specific.h" |
15 | | #include "lib/jxl/base/data_parallel.h" |
16 | | #include "lib/jxl/base/status.h" |
17 | | #include "lib/jxl/modular/encoding/context_predict.h" |
18 | | #include "lib/jxl/modular/modular_image.h" |
19 | | #include "lib/jxl/modular/options.h" |
20 | | |
21 | | namespace jxl { |
22 | | |
23 | | namespace palette_internal { |
24 | | |
25 | | static constexpr int kMaxPaletteLookupTableSize = 1 << 16; |
26 | | |
27 | | static constexpr int kRgbChannels = 3; |
28 | | |
29 | | // 5x5x5 color cube for the larger cube. |
30 | | static constexpr int kLargeCube = 5; |
31 | | |
32 | | // Smaller interleaved color cube to fill the holes of the larger cube. |
33 | | static constexpr int kSmallCube = 4; |
34 | | static constexpr int kSmallCubeBits = 2; |
35 | | // kSmallCube ** 3 |
36 | | static constexpr int kLargeCubeOffset = kSmallCube * kSmallCube * kSmallCube; |
37 | | static constexpr int kImplicitPaletteSize = |
38 | | kLargeCubeOffset + kLargeCube * kLargeCube * kLargeCube; |
39 | | |
40 | | template <int denom> |
41 | 53.1k | static inline pixel_type Scale(uint64_t value, uint64_t bit_depth) { |
42 | | // return (value * ((static_cast<pixel_type_w>(1) << bit_depth) - 1)) / denom; |
43 | | // We only call this function with kSmallCube or kLargeCube - 1 as denom, |
44 | | // allowing us to avoid a division here. |
45 | 53.1k | static_assert(denom == 4, "Denominator is defined as 4"); |
46 | 53.1k | return (value * ((static_cast<uint64_t>(1) << bit_depth) - 1)) >> 2; |
47 | 53.1k | } Unexecuted instantiation: enc_palette.cc:int jxl::palette_internal::Scale<4>(unsigned long, unsigned long) Unexecuted instantiation: transform.cc:int jxl::palette_internal::Scale<4>(unsigned long, unsigned long) palette.cc:int jxl::palette_internal::Scale<4>(unsigned long, unsigned long) Line | Count | Source | 41 | 53.1k | static inline pixel_type Scale(uint64_t value, uint64_t bit_depth) { | 42 | | // return (value * ((static_cast<pixel_type_w>(1) << bit_depth) - 1)) / denom; | 43 | | // We only call this function with kSmallCube or kLargeCube - 1 as denom, | 44 | | // allowing us to avoid a division here. | 45 | 53.1k | static_assert(denom == 4, "Denominator is defined as 4"); | 46 | 53.1k | return (value * ((static_cast<uint64_t>(1) << bit_depth) - 1)) >> 2; | 47 | 53.1k | } |
|
48 | | |
49 | | // The purpose of this function is solely to extend the interpretation of |
50 | | // palette indices to implicit values. If index < nb_deltas, indicating that the |
51 | | // result is a delta palette entry, it is the responsibility of the caller to |
52 | | // treat it as such. |
53 | | static JXL_MAYBE_UNUSED pixel_type |
54 | | GetPaletteValue(const pixel_type *const palette, int index, const size_t c, |
55 | 2.23M | const int palette_size, const int onerow, const int bit_depth) { |
56 | 2.23M | if (index < 0) { |
57 | 716k | static constexpr std::array<std::array<pixel_type, 3>, 72> kDeltaPalette = { |
58 | 716k | { |
59 | 716k | {{0, 0, 0}}, {{4, 4, 4}}, {{11, 0, 0}}, |
60 | 716k | {{0, 0, -13}}, {{0, -12, 0}}, {{-10, -10, -10}}, |
61 | 716k | {{-18, -18, -18}}, {{-27, -27, -27}}, {{-18, -18, 0}}, |
62 | 716k | {{0, 0, -32}}, {{-32, 0, 0}}, {{-37, -37, -37}}, |
63 | 716k | {{0, -32, -32}}, {{24, 24, 45}}, {{50, 50, 50}}, |
64 | 716k | {{-45, -24, -24}}, {{-24, -45, -45}}, {{0, -24, -24}}, |
65 | 716k | {{-34, -34, 0}}, {{-24, 0, -24}}, {{-45, -45, -24}}, |
66 | 716k | {{64, 64, 64}}, {{-32, 0, -32}}, {{0, -32, 0}}, |
67 | 716k | {{-32, 0, 32}}, {{-24, -45, -24}}, {{45, 24, 45}}, |
68 | 716k | {{24, -24, -45}}, {{-45, -24, 24}}, {{80, 80, 80}}, |
69 | 716k | {{64, 0, 0}}, {{0, 0, -64}}, {{0, -64, -64}}, |
70 | 716k | {{-24, -24, 45}}, {{96, 96, 96}}, {{64, 64, 0}}, |
71 | 716k | {{45, -24, -24}}, {{34, -34, 0}}, {{112, 112, 112}}, |
72 | 716k | {{24, -45, -45}}, {{45, 45, -24}}, {{0, -32, 32}}, |
73 | 716k | {{24, -24, 45}}, {{0, 96, 96}}, {{45, -24, 24}}, |
74 | 716k | {{24, -45, -24}}, {{-24, -45, 24}}, {{0, -64, 0}}, |
75 | 716k | {{96, 0, 0}}, {{128, 128, 128}}, {{64, 0, 64}}, |
76 | 716k | {{144, 144, 144}}, {{96, 96, 0}}, {{-36, -36, 36}}, |
77 | 716k | {{45, -24, -45}}, {{45, -45, -24}}, {{0, 0, -96}}, |
78 | 716k | {{0, 128, 128}}, {{0, 96, 0}}, {{45, 24, -45}}, |
79 | 716k | {{-128, 0, 0}}, {{24, -45, 24}}, {{-45, 24, -45}}, |
80 | 716k | {{64, 0, -64}}, {{64, -64, -64}}, {{96, 0, 96}}, |
81 | 716k | {{45, -45, 24}}, {{24, 45, -45}}, {{64, 64, -64}}, |
82 | 716k | {{128, 128, 0}}, {{0, 0, -128}}, {{-24, 45, -45}}, |
83 | 716k | }}; |
84 | 716k | if (c >= kRgbChannels) { |
85 | 74.1k | return 0; |
86 | 74.1k | } |
87 | | // Do not open the brackets, otherwise INT32_MIN negation could overflow. |
88 | 641k | index = -(index + 1); |
89 | 641k | index %= 1 + 2 * (kDeltaPalette.size() - 1); |
90 | 641k | static constexpr int kMultiplier[] = {-1, 1}; |
91 | 641k | pixel_type result = |
92 | 641k | kDeltaPalette[((index + 1) >> 1)][c] * kMultiplier[index & 1]; |
93 | 641k | if (bit_depth > 8) { |
94 | 275k | result *= static_cast<pixel_type>(1) << (bit_depth - 8); |
95 | 275k | } |
96 | 641k | return result; |
97 | 1.52M | } else if (palette_size <= index && index < palette_size + kLargeCubeOffset) { |
98 | 41.3k | if (c >= kRgbChannels) return 0; |
99 | 39.1k | index -= palette_size; |
100 | 39.1k | index >>= c * kSmallCubeBits; |
101 | 39.1k | return Scale<kSmallCube>(index % kSmallCube, bit_depth) + |
102 | 39.1k | (1 << (std::max(0, bit_depth - 3))); |
103 | 1.48M | } else if (palette_size + kLargeCubeOffset <= index) { |
104 | 17.5k | if (c >= kRgbChannels) return 0; |
105 | 14.0k | index -= palette_size + kLargeCubeOffset; |
106 | | // TODO(eustas): should we take care of ambiguity created by |
107 | | // index >= kLargeCube ** 3 ? |
108 | 14.0k | switch (c) { |
109 | 6.16k | case 0: |
110 | 6.16k | default: |
111 | 6.16k | break; |
112 | 6.16k | case 1: |
113 | 3.93k | index /= kLargeCube; |
114 | 3.93k | break; |
115 | 3.90k | case 2: |
116 | 3.90k | index /= kLargeCube * kLargeCube; |
117 | 3.90k | break; |
118 | 14.0k | } |
119 | 14.0k | return Scale<kLargeCube - 1>(index % kLargeCube, bit_depth); |
120 | 14.0k | } |
121 | 1.46M | return palette[c * onerow + static_cast<size_t>(index)]; |
122 | 2.23M | } Unexecuted instantiation: enc_palette.cc:jxl::palette_internal::GetPaletteValue(int const*, int, unsigned long, int, int, int) Unexecuted instantiation: transform.cc:jxl::palette_internal::GetPaletteValue(int const*, int, unsigned long, int, int, int) palette.cc:jxl::palette_internal::GetPaletteValue(int const*, int, unsigned long, int, int, int) Line | Count | Source | 55 | 2.23M | const int palette_size, const int onerow, const int bit_depth) { | 56 | 2.23M | if (index < 0) { | 57 | 716k | static constexpr std::array<std::array<pixel_type, 3>, 72> kDeltaPalette = { | 58 | 716k | { | 59 | 716k | {{0, 0, 0}}, {{4, 4, 4}}, {{11, 0, 0}}, | 60 | 716k | {{0, 0, -13}}, {{0, -12, 0}}, {{-10, -10, -10}}, | 61 | 716k | {{-18, -18, -18}}, {{-27, -27, -27}}, {{-18, -18, 0}}, | 62 | 716k | {{0, 0, -32}}, {{-32, 0, 0}}, {{-37, -37, -37}}, | 63 | 716k | {{0, -32, -32}}, {{24, 24, 45}}, {{50, 50, 50}}, | 64 | 716k | {{-45, -24, -24}}, {{-24, -45, -45}}, {{0, -24, -24}}, | 65 | 716k | {{-34, -34, 0}}, {{-24, 0, -24}}, {{-45, -45, -24}}, | 66 | 716k | {{64, 64, 64}}, {{-32, 0, -32}}, {{0, -32, 0}}, | 67 | 716k | {{-32, 0, 32}}, {{-24, -45, -24}}, {{45, 24, 45}}, | 68 | 716k | {{24, -24, -45}}, {{-45, -24, 24}}, {{80, 80, 80}}, | 69 | 716k | {{64, 0, 0}}, {{0, 0, -64}}, {{0, -64, -64}}, | 70 | 716k | {{-24, -24, 45}}, {{96, 96, 96}}, {{64, 64, 0}}, | 71 | 716k | {{45, -24, -24}}, {{34, -34, 0}}, {{112, 112, 112}}, | 72 | 716k | {{24, -45, -45}}, {{45, 45, -24}}, {{0, -32, 32}}, | 73 | 716k | {{24, -24, 45}}, {{0, 96, 96}}, {{45, -24, 24}}, | 74 | 716k | {{24, -45, -24}}, {{-24, -45, 24}}, {{0, -64, 0}}, | 75 | 716k | {{96, 0, 0}}, {{128, 128, 128}}, {{64, 0, 64}}, | 76 | 716k | {{144, 144, 144}}, {{96, 96, 0}}, {{-36, -36, 36}}, | 77 | 716k | {{45, -24, -45}}, {{45, -45, -24}}, {{0, 0, -96}}, | 78 | 716k | {{0, 128, 128}}, {{0, 96, 0}}, {{45, 24, -45}}, | 79 | 716k | {{-128, 0, 0}}, {{24, -45, 24}}, {{-45, 24, -45}}, | 80 | 716k | {{64, 0, -64}}, {{64, -64, -64}}, {{96, 0, 96}}, | 81 | 716k | {{45, -45, 24}}, {{24, 45, -45}}, {{64, 64, -64}}, | 82 | 716k | {{128, 128, 0}}, {{0, 0, -128}}, {{-24, 45, -45}}, | 83 | 716k | }}; | 84 | 716k | if (c >= kRgbChannels) { | 85 | 74.1k | return 0; | 86 | 74.1k | } | 87 | | // Do not open the brackets, otherwise INT32_MIN negation could overflow. | 88 | 641k | index = -(index + 1); | 89 | 641k | index %= 1 + 2 * (kDeltaPalette.size() - 1); | 90 | 641k | static constexpr int kMultiplier[] = {-1, 1}; | 91 | 641k | pixel_type result = | 92 | 641k | kDeltaPalette[((index + 1) >> 1)][c] * kMultiplier[index & 1]; | 93 | 641k | if (bit_depth > 8) { | 94 | 275k | result *= static_cast<pixel_type>(1) << (bit_depth - 8); | 95 | 275k | } | 96 | 641k | return result; | 97 | 1.52M | } else if (palette_size <= index && index < palette_size + kLargeCubeOffset) { | 98 | 41.3k | if (c >= kRgbChannels) return 0; | 99 | 39.1k | index -= palette_size; | 100 | 39.1k | index >>= c * kSmallCubeBits; | 101 | 39.1k | return Scale<kSmallCube>(index % kSmallCube, bit_depth) + | 102 | 39.1k | (1 << (std::max(0, bit_depth - 3))); | 103 | 1.48M | } else if (palette_size + kLargeCubeOffset <= index) { | 104 | 17.5k | if (c >= kRgbChannels) return 0; | 105 | 14.0k | index -= palette_size + kLargeCubeOffset; | 106 | | // TODO(eustas): should we take care of ambiguity created by | 107 | | // index >= kLargeCube ** 3 ? | 108 | 14.0k | switch (c) { | 109 | 6.16k | case 0: | 110 | 6.16k | default: | 111 | 6.16k | break; | 112 | 6.16k | case 1: | 113 | 3.93k | index /= kLargeCube; | 114 | 3.93k | break; | 115 | 3.90k | case 2: | 116 | 3.90k | index /= kLargeCube * kLargeCube; | 117 | 3.90k | break; | 118 | 14.0k | } | 119 | 14.0k | return Scale<kLargeCube - 1>(index % kLargeCube, bit_depth); | 120 | 14.0k | } | 121 | 1.46M | return palette[c * onerow + static_cast<size_t>(index)]; | 122 | 2.23M | } |
|
123 | | |
124 | | } // namespace palette_internal |
125 | | |
126 | | Status InvPalette(Image &input, uint32_t begin_c, uint32_t nb_colors, |
127 | | uint32_t nb_deltas, Predictor predictor, |
128 | | const weighted::Header &wp_header, ThreadPool *pool); |
129 | | |
130 | | Status MetaPalette(Image &input, uint32_t begin_c, uint32_t end_c, |
131 | | uint32_t nb_colors, uint32_t nb_deltas, bool lossy); |
132 | | |
133 | | } // namespace jxl |
134 | | |
135 | | #endif // LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_ |