// 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_TRANSFORM_H_ #define LIB_JXL_MODULAR_TRANSFORM_TRANSFORM_H_ #include #include #include #include "lib/jxl/base/compiler_specific.h" #include "lib/jxl/base/data_parallel.h" #include "lib/jxl/base/status.h" #include "lib/jxl/field_encodings.h" #include "lib/jxl/fields.h" #include "lib/jxl/modular/encoding/context_predict.h" #include "lib/jxl/modular/modular_image.h" #include "lib/jxl/modular/options.h" namespace jxl { enum class TransformId : uint32_t { // G, R-G, B-G and variants (including YCoCg). kRCT = 0, // Color palette. Parameters are: [begin_c] [end_c] [nb_colors] kPalette = 1, // Squeezing (Haar-style) kSqueeze = 2, // Invalid for now. kInvalid = 3, }; struct SqueezeParams : public Fields { JXL_FIELDS_NAME(SqueezeParams) bool horizontal; bool in_place; uint32_t begin_c; uint32_t num_c; SqueezeParams(); Status VisitFields(Visitor *JXL_RESTRICT visitor) override { JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &horizontal)); JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &in_place)); JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Bits(3), BitsOffset(6, 8), BitsOffset(10, 72), BitsOffset(13, 1096), 0, &begin_c)); JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Val(1), Val(2), Val(3), BitsOffset(4, 4), 2, &num_c)); return true; } }; class Transform : public Fields { public: TransformId id; // for Palette and RCT. uint32_t begin_c; // for RCT. 42 possible values starting from 0. uint32_t rct_type; // Only for Palette and NearLossless. uint32_t num_c; // Only for Palette. uint32_t nb_colors; uint32_t nb_deltas; // for Squeeze. Default squeeze if empty. std::vector squeezes; // for NearLossless, not serialized. int max_delta_error; // Serialized for Palette. Predictor predictor; // for Palette, not serialized. bool ordered_palette = true; bool lossy_palette = false; explicit Transform(TransformId id); // default constructor for bundles. Transform() : Transform(TransformId::kInvalid) {} Status VisitFields(Visitor *JXL_RESTRICT visitor) override { JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Val(static_cast(TransformId::kRCT)), Val(static_cast(TransformId::kPalette)), Val(static_cast(TransformId::kSqueeze)), Val(static_cast(TransformId::kInvalid)), static_cast(TransformId::kRCT), reinterpret_cast(&id))); if (id == TransformId::kInvalid) { return JXL_FAILURE("Invalid transform ID"); } if (visitor->Conditional(id == TransformId::kRCT || id == TransformId::kPalette)) { JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Bits(3), BitsOffset(6, 8), BitsOffset(10, 72), BitsOffset(13, 1096), 0, &begin_c)); } if (visitor->Conditional(id == TransformId::kRCT)) { // 0-41, default YCoCg. JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(6), Bits(2), BitsOffset(4, 2), BitsOffset(6, 10), 6, &rct_type)); if (rct_type >= 42) { return JXL_FAILURE("Invalid transform RCT type"); } } if (visitor->Conditional(id == TransformId::kPalette)) { JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Val(1), Val(3), Val(4), BitsOffset(13, 1), 3, &num_c)); JXL_QUIET_RETURN_IF_ERROR(visitor->U32( BitsOffset(8, 0), BitsOffset(10, 256), BitsOffset(12, 1280), BitsOffset(16, 5376), 256, &nb_colors)); JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Val(0), BitsOffset(8, 1), BitsOffset(10, 257), BitsOffset(16, 1281), 0, &nb_deltas)); JXL_QUIET_RETURN_IF_ERROR( visitor->Bits(4, static_cast(Predictor::Zero), reinterpret_cast(&predictor))); if (predictor >= Predictor::Best) { return JXL_FAILURE("Invalid predictor"); } } if (visitor->Conditional(id == TransformId::kSqueeze)) { uint32_t num_squeezes = static_cast(squeezes.size()); JXL_QUIET_RETURN_IF_ERROR( visitor->U32(Val(0), BitsOffset(4, 1), BitsOffset(6, 9), BitsOffset(8, 41), 0, &num_squeezes)); if (visitor->IsReading()) squeezes.resize(num_squeezes); for (size_t i = 0; i < num_squeezes; i++) { JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&squeezes[i])); } } return true; } JXL_FIELDS_NAME(Transform) Status Inverse(Image &input, const weighted::Header &wp_header, ThreadPool *pool = nullptr) const; Status MetaApply(Image &input); }; Status CheckEqualChannels(const Image &image, uint32_t c1, uint32_t c2); static inline pixel_type PixelAdd(pixel_type a, pixel_type b) { return static_cast(static_cast(a) + static_cast(b)); } } // namespace jxl #endif // LIB_JXL_MODULAR_TRANSFORM_TRANSFORM_H_