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