summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/modular/transform/transform.cc
blob: a609cfb3fb525a0ac41ed4a6ea1c4ec99394532d (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
// 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.

#include "lib/jxl/modular/transform/transform.h"

#include <cinttypes>

#include "lib/jxl/base/printf_macros.h"
#include "lib/jxl/fields.h"
#include "lib/jxl/modular/modular_image.h"
#include "lib/jxl/modular/transform/palette.h"
#include "lib/jxl/modular/transform/rct.h"
#include "lib/jxl/modular/transform/squeeze.h"

namespace jxl {

SqueezeParams::SqueezeParams() { Bundle::Init(this); }
Transform::Transform(TransformId id) {
  Bundle::Init(this);
  this->id = id;
}

Status Transform::Inverse(Image &input, const weighted::Header &wp_header,
                          ThreadPool *pool) const {
  JXL_DEBUG_V(6, "Input channels (%" PRIuS ", %" PRIuS " meta): ",
              input.channel.size(), input.nb_meta_channels);
  switch (id) {
    case TransformId::kRCT:
      return InvRCT(input, begin_c, rct_type, pool);
    case TransformId::kSqueeze:
      return InvSqueeze(input, squeezes, pool);
    case TransformId::kPalette:
      return InvPalette(input, begin_c, nb_colors, nb_deltas, predictor,
                        wp_header, pool);
    default:
      return JXL_FAILURE("Unknown transformation (ID=%u)",
                         static_cast<unsigned int>(id));
  }
}

Status Transform::MetaApply(Image &input) {
  JXL_DEBUG_V(6, "MetaApply input: %s", input.DebugString().c_str());
  switch (id) {
    case TransformId::kRCT:
      JXL_DEBUG_V(2, "Transform: kRCT, rct_type=%" PRIu32, rct_type);
      return CheckEqualChannels(input, begin_c, begin_c + 2);
    case TransformId::kSqueeze:
      JXL_DEBUG_V(2, "Transform: kSqueeze:");
#if JXL_DEBUG_V_LEVEL >= 2
      {
        auto squeezes_copy = squeezes;
        if (squeezes_copy.empty()) {
          DefaultSqueezeParameters(&squeezes_copy, input);
        }
        for (const auto &params : squeezes_copy) {
          JXL_DEBUG_V(
              2,
              "  squeeze params: horizontal=%d, in_place=%d, begin_c=%" PRIu32
              ", num_c=%" PRIu32,
              params.horizontal, params.in_place, params.begin_c, params.num_c);
        }
      }
#endif
      return MetaSqueeze(input, &squeezes);
    case TransformId::kPalette:
      JXL_DEBUG_V(2,
                  "Transform: kPalette, begin_c=%" PRIu32 ", num_c=%" PRIu32
                  ", nb_colors=%" PRIu32 ", nb_deltas=%" PRIu32,
                  begin_c, num_c, nb_colors, nb_deltas);
      return MetaPalette(input, begin_c, begin_c + num_c - 1, nb_colors,
                         nb_deltas, lossy_palette);
    default:
      return JXL_FAILURE("Unknown transformation (ID=%u)",
                         static_cast<unsigned int>(id));
  }
}

Status CheckEqualChannels(const Image &image, uint32_t c1, uint32_t c2) {
  if (c1 > image.channel.size() || c2 >= image.channel.size() || c2 < c1) {
    return JXL_FAILURE("Invalid channel range: %u..%u (there are only %" PRIuS
                       " channels)",
                       c1, c2, image.channel.size());
  }
  if (c1 < image.nb_meta_channels && c2 >= image.nb_meta_channels) {
    return JXL_FAILURE("Invalid: transforming mix of meta and nonmeta");
  }
  const auto &ch1 = image.channel[c1];
  for (size_t c = c1 + 1; c <= c2; c++) {
    const auto &ch2 = image.channel[c];
    if (ch1.w != ch2.w || ch1.h != ch2.h || ch1.hshift != ch2.hshift ||
        ch1.vshift != ch2.vshift) {
      return false;
    }
  }
  return true;
}

}  // namespace jxl