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