encoding.h (5432B)
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_ENCODING_ENCODING_H_ 7 #define LIB_JXL_MODULAR_ENCODING_ENCODING_H_ 8 9 #include <array> 10 #include <cstddef> 11 #include <cstdint> 12 #include <limits> 13 #include <vector> 14 15 #include "lib/jxl/base/compiler_specific.h" 16 #include "lib/jxl/base/status.h" 17 #include "lib/jxl/field_encodings.h" 18 #include "lib/jxl/modular/encoding/context_predict.h" 19 #include "lib/jxl/modular/encoding/dec_ma.h" 20 #include "lib/jxl/modular/modular_image.h" 21 #include "lib/jxl/modular/options.h" 22 #include "lib/jxl/modular/transform/transform.h" 23 24 namespace jxl { 25 26 struct ANSCode; 27 class BitReader; 28 29 // Valid range of properties for using lookup tables instead of trees. 30 constexpr int32_t kPropRangeFast = 512 << 4; 31 32 struct GroupHeader : public Fields { 33 GroupHeader(); 34 35 JXL_FIELDS_NAME(GroupHeader) 36 37 Status VisitFields(Visitor *JXL_RESTRICT visitor) override { 38 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &use_global_tree)); 39 JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&wp_header)); 40 uint32_t num_transforms = static_cast<uint32_t>(transforms.size()); 41 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), BitsOffset(4, 2), 42 BitsOffset(8, 18), 0, 43 &num_transforms)); 44 if (visitor->IsReading()) transforms.resize(num_transforms); 45 for (size_t i = 0; i < num_transforms; i++) { 46 JXL_QUIET_RETURN_IF_ERROR(visitor->VisitNested(&transforms[i])); 47 } 48 return true; 49 } 50 51 bool use_global_tree; 52 weighted::Header wp_header; 53 54 std::vector<Transform> transforms; 55 }; 56 57 FlatTree FilterTree(const Tree &global_tree, 58 std::array<pixel_type, kNumStaticProperties> &static_props, 59 size_t *num_props, bool *use_wp, bool *wp_only, 60 bool *gradient_only); 61 62 template <typename T, bool HAS_OFFSETS, bool HAS_MULTIPLIERS> 63 struct TreeLut { 64 std::array<T, 2 * kPropRangeFast> context_lookup; 65 std::array<int8_t, HAS_OFFSETS ? (2 * kPropRangeFast) : 0> offsets; 66 std::array<int8_t, HAS_MULTIPLIERS ? (2 * kPropRangeFast) : 0> multipliers; 67 }; 68 69 template <typename T, bool HAS_OFFSETS, bool HAS_MULTIPLIERS> 70 bool TreeToLookupTable(const FlatTree &tree, 71 TreeLut<T, HAS_OFFSETS, HAS_MULTIPLIERS> &lut) { 72 struct TreeRange { 73 // Begin *excluded*, end *included*. This works best with > vs <= decision 74 // nodes. 75 int begin, end; 76 size_t pos; 77 }; 78 std::vector<TreeRange> ranges; 79 ranges.push_back(TreeRange{-kPropRangeFast - 1, kPropRangeFast - 1, 0}); 80 while (!ranges.empty()) { 81 TreeRange cur = ranges.back(); 82 ranges.pop_back(); 83 if (cur.begin < -kPropRangeFast - 1 || cur.begin >= kPropRangeFast - 1 || 84 cur.end > kPropRangeFast - 1) { 85 // Tree is outside the allowed range, exit. 86 return false; 87 } 88 auto &node = tree[cur.pos]; 89 // Leaf. 90 if (node.property0 == -1) { 91 if (node.predictor_offset < std::numeric_limits<int8_t>::min() || 92 node.predictor_offset > std::numeric_limits<int8_t>::max()) { 93 return false; 94 } 95 if (node.multiplier < std::numeric_limits<int8_t>::min() || 96 node.multiplier > std::numeric_limits<int8_t>::max()) { 97 return false; 98 } 99 if (!HAS_MULTIPLIERS && node.multiplier != 1) { 100 return false; 101 } 102 if (!HAS_OFFSETS && node.predictor_offset != 0) { 103 return false; 104 } 105 for (int i = cur.begin + 1; i < cur.end + 1; i++) { 106 lut.context_lookup[i + kPropRangeFast] = node.childID; 107 if (HAS_MULTIPLIERS) { 108 lut.multipliers[i + kPropRangeFast] = node.multiplier; 109 } 110 if (HAS_OFFSETS) { 111 lut.offsets[i + kPropRangeFast] = node.predictor_offset; 112 } 113 } 114 continue; 115 } 116 // > side of top node. 117 if (node.properties[0] >= kNumStaticProperties) { 118 ranges.push_back(TreeRange({node.splitvals[0], cur.end, node.childID})); 119 ranges.push_back( 120 TreeRange({node.splitval0, node.splitvals[0], node.childID + 1})); 121 } else { 122 ranges.push_back(TreeRange({node.splitval0, cur.end, node.childID})); 123 } 124 // <= side 125 if (node.properties[1] >= kNumStaticProperties) { 126 ranges.push_back( 127 TreeRange({node.splitvals[1], node.splitval0, node.childID + 2})); 128 ranges.push_back( 129 TreeRange({cur.begin, node.splitvals[1], node.childID + 3})); 130 } else { 131 ranges.push_back( 132 TreeRange({cur.begin, node.splitval0, node.childID + 2})); 133 } 134 } 135 return true; 136 } 137 // TODO(veluca): make cleaner interfaces. 138 139 Status ValidateChannelDimensions(const Image &image, 140 const ModularOptions &options); 141 142 Status ModularGenericDecompress(BitReader *br, Image &image, 143 GroupHeader *header, size_t group_id, 144 ModularOptions *options, 145 bool undo_transforms = true, 146 const Tree *tree = nullptr, 147 const ANSCode *code = nullptr, 148 const std::vector<uint8_t> *ctx_map = nullptr, 149 bool allow_truncated_group = false); 150 } // namespace jxl 151 152 #endif // LIB_JXL_MODULAR_ENCODING_ENCODING_H_