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