Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/modular/transform/palette.h
Line
Count
Source
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
37.9M
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
37.9M
  static_assert(denom == 4, "Denominator is defined as 4");
46
37.9M
  return (value * ((static_cast<uint64_t>(1) << bit_depth) - 1)) >> 2;
47
37.9M
}
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
37.9M
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
37.9M
  static_assert(denom == 4, "Denominator is defined as 4");
46
37.9M
  return (value * ((static_cast<uint64_t>(1) << bit_depth) - 1)) >> 2;
47
37.9M
}
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
169M
                const int palette_size, const int onerow, const int bit_depth) {
56
169M
  if (index < 0) {
57
26.3M
    static constexpr std::array<std::array<pixel_type, 3>, 72> kDeltaPalette = {
58
26.3M
        {
59
26.3M
            {{0, 0, 0}},       {{4, 4, 4}},       {{11, 0, 0}},
60
26.3M
            {{0, 0, -13}},     {{0, -12, 0}},     {{-10, -10, -10}},
61
26.3M
            {{-18, -18, -18}}, {{-27, -27, -27}}, {{-18, -18, 0}},
62
26.3M
            {{0, 0, -32}},     {{-32, 0, 0}},     {{-37, -37, -37}},
63
26.3M
            {{0, -32, -32}},   {{24, 24, 45}},    {{50, 50, 50}},
64
26.3M
            {{-45, -24, -24}}, {{-24, -45, -45}}, {{0, -24, -24}},
65
26.3M
            {{-34, -34, 0}},   {{-24, 0, -24}},   {{-45, -45, -24}},
66
26.3M
            {{64, 64, 64}},    {{-32, 0, -32}},   {{0, -32, 0}},
67
26.3M
            {{-32, 0, 32}},    {{-24, -45, -24}}, {{45, 24, 45}},
68
26.3M
            {{24, -24, -45}},  {{-45, -24, 24}},  {{80, 80, 80}},
69
26.3M
            {{64, 0, 0}},      {{0, 0, -64}},     {{0, -64, -64}},
70
26.3M
            {{-24, -24, 45}},  {{96, 96, 96}},    {{64, 64, 0}},
71
26.3M
            {{45, -24, -24}},  {{34, -34, 0}},    {{112, 112, 112}},
72
26.3M
            {{24, -45, -45}},  {{45, 45, -24}},   {{0, -32, 32}},
73
26.3M
            {{24, -24, 45}},   {{0, 96, 96}},     {{45, -24, 24}},
74
26.3M
            {{24, -45, -24}},  {{-24, -45, 24}},  {{0, -64, 0}},
75
26.3M
            {{96, 0, 0}},      {{128, 128, 128}}, {{64, 0, 64}},
76
26.3M
            {{144, 144, 144}}, {{96, 96, 0}},     {{-36, -36, 36}},
77
26.3M
            {{45, -24, -45}},  {{45, -45, -24}},  {{0, 0, -96}},
78
26.3M
            {{0, 128, 128}},   {{0, 96, 0}},      {{45, 24, -45}},
79
26.3M
            {{-128, 0, 0}},    {{24, -45, 24}},   {{-45, 24, -45}},
80
26.3M
            {{64, 0, -64}},    {{64, -64, -64}},  {{96, 0, 96}},
81
26.3M
            {{45, -45, 24}},   {{24, 45, -45}},   {{64, 64, -64}},
82
26.3M
            {{128, 128, 0}},   {{0, 0, -128}},    {{-24, 45, -45}},
83
26.3M
        }};
84
26.3M
    if (c >= kRgbChannels) {
85
1.14M
      return 0;
86
1.14M
    }
87
    // Do not open the brackets, otherwise INT32_MIN negation could overflow.
88
25.2M
    index = -(index + 1);
89
25.2M
    index %= 1 + 2 * (kDeltaPalette.size() - 1);
90
25.2M
    static constexpr int kMultiplier[] = {-1, 1};
91
25.2M
    pixel_type result =
92
25.2M
        kDeltaPalette[((index + 1) >> 1)][c] * kMultiplier[index & 1];
93
25.2M
    if (bit_depth > 8) {
94
20.6M
      result *= static_cast<pixel_type>(1) << (bit_depth - 8);
95
20.6M
    }
96
25.2M
    return result;
97
143M
  } else if (palette_size <= index && index < palette_size + kLargeCubeOffset) {
98
45.4M
    if (c >= kRgbChannels) return 0;
99
35.4M
    index -= palette_size;
100
35.4M
    index >>= c * kSmallCubeBits;
101
35.4M
    return Scale<kSmallCube>(index % kSmallCube, bit_depth) +
102
35.4M
           (1 << (std::max(0, bit_depth - 3)));
103
97.8M
  } else if (palette_size + kLargeCubeOffset <= index) {
104
2.76M
    if (c >= kRgbChannels) return 0;
105
2.48M
    index -= palette_size + kLargeCubeOffset;
106
    // TODO(eustas): should we take care of ambiguity created by
107
    //               index >= kLargeCube ** 3 ?
108
2.48M
    switch (c) {
109
1.78M
      case 0:
110
1.78M
      default:
111
1.78M
        break;
112
1.78M
      case 1:
113
348k
        index /= kLargeCube;
114
348k
        break;
115
346k
      case 2:
116
346k
        index /= kLargeCube * kLargeCube;
117
346k
        break;
118
2.48M
    }
119
2.48M
    return Scale<kLargeCube - 1>(index % kLargeCube, bit_depth);
120
2.48M
  }
121
95.1M
  return palette[c * onerow + static_cast<size_t>(index)];
122
169M
}
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
169M
                const int palette_size, const int onerow, const int bit_depth) {
56
169M
  if (index < 0) {
57
26.3M
    static constexpr std::array<std::array<pixel_type, 3>, 72> kDeltaPalette = {
58
26.3M
        {
59
26.3M
            {{0, 0, 0}},       {{4, 4, 4}},       {{11, 0, 0}},
60
26.3M
            {{0, 0, -13}},     {{0, -12, 0}},     {{-10, -10, -10}},
61
26.3M
            {{-18, -18, -18}}, {{-27, -27, -27}}, {{-18, -18, 0}},
62
26.3M
            {{0, 0, -32}},     {{-32, 0, 0}},     {{-37, -37, -37}},
63
26.3M
            {{0, -32, -32}},   {{24, 24, 45}},    {{50, 50, 50}},
64
26.3M
            {{-45, -24, -24}}, {{-24, -45, -45}}, {{0, -24, -24}},
65
26.3M
            {{-34, -34, 0}},   {{-24, 0, -24}},   {{-45, -45, -24}},
66
26.3M
            {{64, 64, 64}},    {{-32, 0, -32}},   {{0, -32, 0}},
67
26.3M
            {{-32, 0, 32}},    {{-24, -45, -24}}, {{45, 24, 45}},
68
26.3M
            {{24, -24, -45}},  {{-45, -24, 24}},  {{80, 80, 80}},
69
26.3M
            {{64, 0, 0}},      {{0, 0, -64}},     {{0, -64, -64}},
70
26.3M
            {{-24, -24, 45}},  {{96, 96, 96}},    {{64, 64, 0}},
71
26.3M
            {{45, -24, -24}},  {{34, -34, 0}},    {{112, 112, 112}},
72
26.3M
            {{24, -45, -45}},  {{45, 45, -24}},   {{0, -32, 32}},
73
26.3M
            {{24, -24, 45}},   {{0, 96, 96}},     {{45, -24, 24}},
74
26.3M
            {{24, -45, -24}},  {{-24, -45, 24}},  {{0, -64, 0}},
75
26.3M
            {{96, 0, 0}},      {{128, 128, 128}}, {{64, 0, 64}},
76
26.3M
            {{144, 144, 144}}, {{96, 96, 0}},     {{-36, -36, 36}},
77
26.3M
            {{45, -24, -45}},  {{45, -45, -24}},  {{0, 0, -96}},
78
26.3M
            {{0, 128, 128}},   {{0, 96, 0}},      {{45, 24, -45}},
79
26.3M
            {{-128, 0, 0}},    {{24, -45, 24}},   {{-45, 24, -45}},
80
26.3M
            {{64, 0, -64}},    {{64, -64, -64}},  {{96, 0, 96}},
81
26.3M
            {{45, -45, 24}},   {{24, 45, -45}},   {{64, 64, -64}},
82
26.3M
            {{128, 128, 0}},   {{0, 0, -128}},    {{-24, 45, -45}},
83
26.3M
        }};
84
26.3M
    if (c >= kRgbChannels) {
85
1.14M
      return 0;
86
1.14M
    }
87
    // Do not open the brackets, otherwise INT32_MIN negation could overflow.
88
25.2M
    index = -(index + 1);
89
25.2M
    index %= 1 + 2 * (kDeltaPalette.size() - 1);
90
25.2M
    static constexpr int kMultiplier[] = {-1, 1};
91
25.2M
    pixel_type result =
92
25.2M
        kDeltaPalette[((index + 1) >> 1)][c] * kMultiplier[index & 1];
93
25.2M
    if (bit_depth > 8) {
94
20.6M
      result *= static_cast<pixel_type>(1) << (bit_depth - 8);
95
20.6M
    }
96
25.2M
    return result;
97
143M
  } else if (palette_size <= index && index < palette_size + kLargeCubeOffset) {
98
45.4M
    if (c >= kRgbChannels) return 0;
99
35.4M
    index -= palette_size;
100
35.4M
    index >>= c * kSmallCubeBits;
101
35.4M
    return Scale<kSmallCube>(index % kSmallCube, bit_depth) +
102
35.4M
           (1 << (std::max(0, bit_depth - 3)));
103
97.8M
  } else if (palette_size + kLargeCubeOffset <= index) {
104
2.76M
    if (c >= kRgbChannels) return 0;
105
2.48M
    index -= palette_size + kLargeCubeOffset;
106
    // TODO(eustas): should we take care of ambiguity created by
107
    //               index >= kLargeCube ** 3 ?
108
2.48M
    switch (c) {
109
1.78M
      case 0:
110
1.78M
      default:
111
1.78M
        break;
112
1.78M
      case 1:
113
348k
        index /= kLargeCube;
114
348k
        break;
115
346k
      case 2:
116
346k
        index /= kLargeCube * kLargeCube;
117
346k
        break;
118
2.48M
    }
119
2.48M
    return Scale<kLargeCube - 1>(index % kLargeCube, bit_depth);
120
2.48M
  }
121
95.1M
  return palette[c * onerow + static_cast<size_t>(index)];
122
169M
}
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_