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_TRANSFORM_H_
7 #define LIB_JXL_MODULAR_TRANSFORM_TRANSFORM_H_
8
9 #include <cstdint>
10 #include <string>
11 #include <vector>
12
13 #include "lib/jxl/base/data_parallel.h"
14 #include "lib/jxl/fields.h"
15 #include "lib/jxl/modular/encoding/context_predict.h"
16 #include "lib/jxl/modular/options.h"
17
18 namespace jxl {
19
20 enum class TransformId : uint32_t {
21 // G, R-G, B-G and variants (including YCoCg).
22 kRCT = 0,
23
24 // Color palette. Parameters are: [begin_c] [end_c] [nb_colors]
25 kPalette = 1,
26
27 // Squeezing (Haar-style)
28 kSqueeze = 2,
29
30 // Invalid for now.
31 kInvalid = 3,
32 };
33
34 struct SqueezeParams : public Fields {
NameSqueezeParams35 const char *Name() const override { return "SqueezeParams"; }
36 bool horizontal;
37 bool in_place;
38 uint32_t begin_c;
39 uint32_t num_c;
40 SqueezeParams();
VisitFieldsSqueezeParams41 Status VisitFields(Visitor *JXL_RESTRICT visitor) override {
42 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &horizontal));
43 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &in_place));
44 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(3), BitsOffset(6, 8),
45 BitsOffset(10, 72),
46 BitsOffset(13, 1096), 0, &begin_c));
47 JXL_QUIET_RETURN_IF_ERROR(
48 visitor->U32(Val(1), Val(2), Val(3), BitsOffset(4, 4), 2, &num_c));
49 return true;
50 }
51 };
52
53 class Transform : public Fields {
54 public:
55 TransformId id;
56 // for Palette and RCT.
57 uint32_t begin_c;
58 // for RCT. 42 possible values starting from 0.
59 uint32_t rct_type;
60 // Only for Palette and NearLossless.
61 uint32_t num_c;
62 // Only for Palette.
63 uint32_t nb_colors;
64 uint32_t nb_deltas;
65 // for Squeeze. Default squeeze if empty.
66 std::vector<SqueezeParams> squeezes;
67 // for NearLossless, not serialized.
68 int max_delta_error;
69 // Serialized for Palette.
70 Predictor predictor;
71 // for Palette, not serialized.
72 bool ordered_palette = true;
73 bool lossy_palette = false;
74
75 explicit Transform(TransformId id);
76 // default constructor for bundles.
Transform()77 Transform() : Transform(TransformId::kInvalid) {}
78
VisitFields(Visitor * JXL_RESTRICT visitor)79 Status VisitFields(Visitor *JXL_RESTRICT visitor) override {
80 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
81 Val((uint32_t)TransformId::kRCT), Val((uint32_t)TransformId::kPalette),
82 Val((uint32_t)TransformId::kSqueeze),
83 Val((uint32_t)TransformId::kInvalid), (uint32_t)TransformId::kRCT,
84 reinterpret_cast<uint32_t *>(&id)));
85 if (id == TransformId::kInvalid) {
86 return JXL_FAILURE("Invalid transform ID");
87 }
88 if (visitor->Conditional(id == TransformId::kRCT ||
89 id == TransformId::kPalette)) {
90 JXL_QUIET_RETURN_IF_ERROR(
91 visitor->U32(Bits(3), BitsOffset(6, 8), BitsOffset(10, 72),
92 BitsOffset(13, 1096), 0, &begin_c));
93 }
94 if (visitor->Conditional(id == TransformId::kRCT)) {
95 // 0-41, default YCoCg.
96 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(6), Bits(2), BitsOffset(4, 2),
97 BitsOffset(6, 10), 6, &rct_type));
98 if (rct_type >= 42) {
99 return JXL_FAILURE("Invalid transform RCT type");
100 }
101 }
102 if (visitor->Conditional(id == TransformId::kPalette)) {
103 JXL_QUIET_RETURN_IF_ERROR(
104 visitor->U32(Val(1), Val(3), Val(4), BitsOffset(13, 1), 3, &num_c));
105 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(
106 BitsOffset(8, 0), BitsOffset(10, 256), BitsOffset(12, 1280),
107 BitsOffset(16, 5376), 256, &nb_colors));
108 JXL_QUIET_RETURN_IF_ERROR(
109 visitor->U32(Val(0), BitsOffset(8, 1), BitsOffset(10, 257),
110 BitsOffset(16, 1281), 0, &nb_deltas));
111 JXL_QUIET_RETURN_IF_ERROR(
112 visitor->Bits(4, (uint32_t)Predictor::Zero,
113 reinterpret_cast<uint32_t *>(&predictor)));
114 if (predictor >= Predictor::Best) {
115 return JXL_FAILURE("Invalid predictor");
116 }
117 }
118
119 if (visitor->Conditional(id == TransformId::kSqueeze)) {
120 uint32_t num_squeezes = static_cast<uint32_t>(squeezes.size());
121 JXL_QUIET_RETURN_IF_ERROR(
122 visitor->U32(Val(0), BitsOffset(4, 1), BitsOffset(6, 9),
123 BitsOffset(8, 41), 0, &num_squeezes));
124 if (visitor->IsReading()) squeezes.resize(num_squeezes);
125 for (size_t i = 0; i < num_squeezes; i++) {
126 JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&squeezes[i]));
127 }
128 }
129 return true;
130 }
131
Name()132 const char *Name() const override { return "Transform"; }
133
134 Status Inverse(Image &input, const weighted::Header &wp_header,
135 ThreadPool *pool = nullptr);
136 Status MetaApply(Image &input);
137 };
138
139 Status CheckEqualChannels(const Image &image, uint32_t c1, uint32_t c2);
140
PixelAdd(pixel_type a,pixel_type b)141 static inline pixel_type PixelAdd(pixel_type a, pixel_type b) {
142 return static_cast<pixel_type>(static_cast<uint32_t>(a) +
143 static_cast<uint32_t>(b));
144 }
145
146 } // namespace jxl
147
148 #endif // LIB_JXL_MODULAR_TRANSFORM_TRANSFORM_H_
149