summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/modular/transform/palette.h
blob: 2a9e5c71f4ba7af923d886811c572eaaa68cebcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_
#define LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_

#include <atomic>

#include "lib/jxl/base/data_parallel.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/modular/encoding/context_predict.h"
#include "lib/jxl/modular/modular_image.h"
#include "lib/jxl/modular/transform/transform.h"  // CheckEqualChannels

namespace jxl {

namespace palette_internal {

static constexpr int kMaxPaletteLookupTableSize = 1 << 16;

static constexpr int kRgbChannels = 3;

// 5x5x5 color cube for the larger cube.
static constexpr int kLargeCube = 5;

// Smaller interleaved color cube to fill the holes of the larger cube.
static constexpr int kSmallCube = 4;
static constexpr int kSmallCubeBits = 2;
// kSmallCube ** 3
static constexpr int kLargeCubeOffset = kSmallCube * kSmallCube * kSmallCube;
static constexpr int kImplicitPaletteSize =
    kLargeCubeOffset + kLargeCube * kLargeCube * kLargeCube;

static inline pixel_type Scale(uint64_t value, uint64_t bit_depth,
                               uint64_t denom) {
  // return (value * ((static_cast<pixel_type_w>(1) << bit_depth) - 1)) / denom;
  // We only call this function with kSmallCube or kLargeCube - 1 as denom,
  // allowing us to avoid a division here.
  JXL_ASSERT(denom == 4);
  return (value * ((static_cast<uint64_t>(1) << bit_depth) - 1)) >> 2;
}

// The purpose of this function is solely to extend the interpretation of
// palette indices to implicit values. If index < nb_deltas, indicating that the
// result is a delta palette entry, it is the responsibility of the caller to
// treat it as such.
static JXL_MAYBE_UNUSED pixel_type
GetPaletteValue(const pixel_type *const palette, int index, const size_t c,
                const int palette_size, const int onerow, const int bit_depth) {
  if (index < 0) {
    static constexpr std::array<std::array<pixel_type, 3>, 72> kDeltaPalette = {
        {
            {{0, 0, 0}},       {{4, 4, 4}},       {{11, 0, 0}},
            {{0, 0, -13}},     {{0, -12, 0}},     {{-10, -10, -10}},
            {{-18, -18, -18}}, {{-27, -27, -27}}, {{-18, -18, 0}},
            {{0, 0, -32}},     {{-32, 0, 0}},     {{-37, -37, -37}},
            {{0, -32, -32}},   {{24, 24, 45}},    {{50, 50, 50}},
            {{-45, -24, -24}}, {{-24, -45, -45}}, {{0, -24, -24}},
            {{-34, -34, 0}},   {{-24, 0, -24}},   {{-45, -45, -24}},
            {{64, 64, 64}},    {{-32, 0, -32}},   {{0, -32, 0}},
            {{-32, 0, 32}},    {{-24, -45, -24}}, {{45, 24, 45}},
            {{24, -24, -45}},  {{-45, -24, 24}},  {{80, 80, 80}},
            {{64, 0, 0}},      {{0, 0, -64}},     {{0, -64, -64}},
            {{-24, -24, 45}},  {{96, 96, 96}},    {{64, 64, 0}},
            {{45, -24, -24}},  {{34, -34, 0}},    {{112, 112, 112}},
            {{24, -45, -45}},  {{45, 45, -24}},   {{0, -32, 32}},
            {{24, -24, 45}},   {{0, 96, 96}},     {{45, -24, 24}},
            {{24, -45, -24}},  {{-24, -45, 24}},  {{0, -64, 0}},
            {{96, 0, 0}},      {{128, 128, 128}}, {{64, 0, 64}},
            {{144, 144, 144}}, {{96, 96, 0}},     {{-36, -36, 36}},
            {{45, -24, -45}},  {{45, -45, -24}},  {{0, 0, -96}},
            {{0, 128, 128}},   {{0, 96, 0}},      {{45, 24, -45}},
            {{-128, 0, 0}},    {{24, -45, 24}},   {{-45, 24, -45}},
            {{64, 0, -64}},    {{64, -64, -64}},  {{96, 0, 96}},
            {{45, -45, 24}},   {{24, 45, -45}},   {{64, 64, -64}},
            {{128, 128, 0}},   {{0, 0, -128}},    {{-24, 45, -45}},
        }};
    if (c >= kRgbChannels) {
      return 0;
    }
    // Do not open the brackets, otherwise INT32_MIN negation could overflow.
    index = -(index + 1);
    index %= 1 + 2 * (kDeltaPalette.size() - 1);
    static constexpr int kMultiplier[] = {-1, 1};
    pixel_type result =
        kDeltaPalette[((index + 1) >> 1)][c] * kMultiplier[index & 1];
    if (bit_depth > 8) {
      result *= static_cast<pixel_type>(1) << (bit_depth - 8);
    }
    return result;
  } else if (palette_size <= index && index < palette_size + kLargeCubeOffset) {
    if (c >= kRgbChannels) return 0;
    index -= palette_size;
    index >>= c * kSmallCubeBits;
    return Scale(index % kSmallCube, bit_depth, kSmallCube) +
           (1 << (std::max(0, bit_depth - 3)));
  } else if (palette_size + kLargeCubeOffset <= index) {
    if (c >= kRgbChannels) return 0;
    index -= palette_size + kLargeCubeOffset;
    // TODO(eustas): should we take care of ambiguity created by
    //               index >= kLargeCube ** 3 ?
    switch (c) {
      case 0:
      default:
        break;
      case 1:
        index /= kLargeCube;
        break;
      case 2:
        index /= kLargeCube * kLargeCube;
        break;
    }
    return Scale(index % kLargeCube, bit_depth, kLargeCube - 1);
  }
  return palette[c * onerow + static_cast<size_t>(index)];
}

}  // namespace palette_internal

Status InvPalette(Image &input, uint32_t begin_c, uint32_t nb_colors,
                  uint32_t nb_deltas, Predictor predictor,
                  const weighted::Header &wp_header, ThreadPool *pool);

Status MetaPalette(Image &input, uint32_t begin_c, uint32_t end_c,
                   uint32_t nb_colors, uint32_t nb_deltas, bool lossy);

}  // namespace jxl

#endif  // LIB_JXL_MODULAR_TRANSFORM_PALETTE_H_