headers.cc (6674B)
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 #include "lib/jxl/headers.h" 7 8 #include <cstdint> 9 #include <limits> 10 11 #include "lib/jxl/fields.h" 12 #include "lib/jxl/frame_dimensions.h" 13 14 namespace jxl { 15 namespace { 16 17 struct Rational { 18 constexpr explicit Rational(uint32_t num, uint32_t den) 19 : num(num), den(den) {} 20 21 // Returns floor(multiplicand * rational). 22 constexpr uint32_t MulTruncate(uint32_t multiplicand) const { 23 return static_cast<uint64_t>(multiplicand) * num / den; 24 } 25 26 uint32_t num; 27 uint32_t den; 28 }; 29 30 Rational FixedAspectRatios(uint32_t ratio) { 31 JXL_DASSERT(0 != ratio && ratio < 8); 32 // Other candidates: 5/4, 7/5, 14/9, 16/10, 5/3, 21/9, 12/5 33 constexpr Rational kRatios[7] = {Rational(1, 1), // square 34 Rational(12, 10), // 35 Rational(4, 3), // camera 36 Rational(3, 2), // mobile camera 37 Rational(16, 9), // camera/display 38 Rational(5, 4), // 39 Rational(2, 1)}; // 40 return kRatios[ratio - 1]; 41 } 42 43 uint32_t FindAspectRatio(uint32_t xsize, uint32_t ysize) { 44 for (uint32_t r = 1; r < 8; ++r) { 45 if (xsize == FixedAspectRatios(r).MulTruncate(ysize)) { 46 return r; 47 } 48 } 49 return 0; // Must send xsize instead 50 } 51 52 } // namespace 53 54 size_t SizeHeader::xsize() const { 55 if (ratio_ != 0) { 56 return FixedAspectRatios(ratio_).MulTruncate( 57 static_cast<uint32_t>(ysize())); 58 } 59 return small_ ? ((xsize_div8_minus_1_ + 1) * 8) : xsize_; 60 } 61 62 Status SizeHeader::Set(size_t xsize64, size_t ysize64) { 63 constexpr size_t kDimensionCap = std::numeric_limits<uint32_t>::max(); 64 if (xsize64 > kDimensionCap || ysize64 > kDimensionCap) { 65 return JXL_FAILURE("Image too large"); 66 } 67 const uint32_t xsize32 = static_cast<uint32_t>(xsize64); 68 const uint32_t ysize32 = static_cast<uint32_t>(ysize64); 69 if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty image"); 70 ratio_ = FindAspectRatio(xsize32, ysize32); 71 small_ = ysize64 <= 256 && (ysize64 % kBlockDim) == 0 && 72 (ratio_ != 0 || (xsize64 <= 256 && (xsize64 % kBlockDim) == 0)); 73 if (small_) { 74 ysize_div8_minus_1_ = ysize32 / 8 - 1; 75 } else { 76 ysize_ = ysize32; 77 } 78 79 if (ratio_ == 0) { 80 if (small_) { 81 xsize_div8_minus_1_ = xsize32 / 8 - 1; 82 } else { 83 xsize_ = xsize32; 84 } 85 } 86 JXL_ENSURE(xsize() == xsize64); 87 JXL_ENSURE(ysize() == ysize64); 88 return true; 89 } 90 91 Status PreviewHeader::Set(size_t xsize64, size_t ysize64) { 92 const uint32_t xsize32 = static_cast<uint32_t>(xsize64); 93 const uint32_t ysize32 = static_cast<uint32_t>(ysize64); 94 if (xsize64 == 0 || ysize64 == 0) return JXL_FAILURE("Empty preview"); 95 div8_ = (xsize64 % kBlockDim) == 0 && (ysize64 % kBlockDim) == 0; 96 if (div8_) { 97 ysize_div8_ = ysize32 / 8; 98 } else { 99 ysize_ = ysize32; 100 } 101 102 ratio_ = FindAspectRatio(xsize32, ysize32); 103 if (ratio_ == 0) { 104 if (div8_) { 105 xsize_div8_ = xsize32 / 8; 106 } else { 107 xsize_ = xsize32; 108 } 109 } 110 JXL_ENSURE(xsize() == xsize64); 111 JXL_ENSURE(ysize() == ysize64); 112 return true; 113 } 114 115 size_t PreviewHeader::xsize() const { 116 if (ratio_ != 0) { 117 return FixedAspectRatios(ratio_).MulTruncate( 118 static_cast<uint32_t>(ysize())); 119 } 120 return div8_ ? (xsize_div8_ * 8) : xsize_; 121 } 122 123 SizeHeader::SizeHeader() { Bundle::Init(this); } 124 Status SizeHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { 125 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &small_)); 126 127 if (visitor->Conditional(small_)) { 128 JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &ysize_div8_minus_1_)); 129 } 130 if (visitor->Conditional(!small_)) { 131 // (Could still be small, but non-multiple of 8.) 132 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), 133 BitsOffset(18, 1), BitsOffset(30, 1), 134 1, &ysize_)); 135 } 136 137 JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); 138 if (visitor->Conditional(ratio_ == 0 && small_)) { 139 JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(5, 0, &xsize_div8_minus_1_)); 140 } 141 if (visitor->Conditional(ratio_ == 0 && !small_)) { 142 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(9, 1), BitsOffset(13, 1), 143 BitsOffset(18, 1), BitsOffset(30, 1), 144 1, &xsize_)); 145 } 146 147 return true; 148 } 149 150 PreviewHeader::PreviewHeader() { Bundle::Init(this); } 151 Status PreviewHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { 152 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &div8_)); 153 154 if (visitor->Conditional(div8_)) { 155 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), 156 BitsOffset(9, 33), 1, &ysize_div8_)); 157 } 158 if (visitor->Conditional(!div8_)) { 159 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), 160 BitsOffset(10, 321), 161 BitsOffset(12, 1345), 1, &ysize_)); 162 } 163 164 JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(3, 0, &ratio_)); 165 if (visitor->Conditional(ratio_ == 0 && div8_)) { 166 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(16), Val(32), BitsOffset(5, 1), 167 BitsOffset(9, 33), 1, &xsize_div8_)); 168 } 169 if (visitor->Conditional(ratio_ == 0 && !div8_)) { 170 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(BitsOffset(6, 1), BitsOffset(8, 65), 171 BitsOffset(10, 321), 172 BitsOffset(12, 1345), 1, &xsize_)); 173 } 174 175 return true; 176 } 177 178 AnimationHeader::AnimationHeader() { Bundle::Init(this); } 179 Status AnimationHeader::VisitFields(Visitor* JXL_RESTRICT visitor) { 180 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(100), Val(1000), BitsOffset(10, 1), 181 BitsOffset(30, 1), 1, &tps_numerator)); 182 JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(1), Val(1001), BitsOffset(8, 1), 183 BitsOffset(10, 1), 1, 184 &tps_denominator)); 185 186 JXL_QUIET_RETURN_IF_ERROR( 187 visitor->U32(Val(0), Bits(3), Bits(16), Bits(32), 0, &num_loops)); 188 189 JXL_QUIET_RETURN_IF_ERROR(visitor->Bool(false, &have_timecodes)); 190 return true; 191 } 192 193 Status ReadSizeHeader(BitReader* JXL_RESTRICT reader, 194 SizeHeader* JXL_RESTRICT size) { 195 return Bundle::Read(reader, size); 196 } 197 198 } // namespace jxl