EXIF.cpp (12648B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "EXIF.h" 7 8 #include "mozilla/EndianUtils.h" 9 #include "mozilla/StaticPrefs_image.h" 10 11 namespace mozilla::image { 12 13 // Section references in this file refer to the EXIF v2.3 standard, also known 14 // as CIPA DC-008-Translation-2010. 15 16 // See Section 4.6.4, Table 4. 17 // Typesafe enums are intentionally not used here since we're comparing to raw 18 // integers produced by parsing. 19 enum class EXIFTag : uint16_t { 20 Orientation = 0x112, 21 XResolution = 0x11a, 22 YResolution = 0x11b, 23 PixelXDimension = 0xa002, 24 PixelYDimension = 0xa003, 25 ResolutionUnit = 0x128, 26 IFDPointer = 0x8769, 27 }; 28 29 // See Section 4.6.2. 30 enum EXIFType { 31 ByteType = 1, 32 ASCIIType = 2, 33 ShortType = 3, 34 LongType = 4, 35 RationalType = 5, 36 UndefinedType = 7, 37 SignedLongType = 9, 38 SignedRational = 10, 39 }; 40 41 static const char* EXIFHeader = "Exif\0\0"; 42 static const uint32_t EXIFHeaderLength = 6; 43 44 uint32_t EXIFParser::TIFFHeaderStart() const { 45 return mExpectExifIdCode ? EXIFHeaderLength : 0; 46 } 47 48 struct ParsedEXIFData { 49 Orientation orientation; 50 Maybe<float> resolutionX; 51 Maybe<float> resolutionY; 52 Maybe<uint32_t> pixelXDimension; 53 Maybe<uint32_t> pixelYDimension; 54 Maybe<ResolutionUnit> resolutionUnit; 55 }; 56 57 static float ToDppx(float aResolution, ResolutionUnit aUnit) { 58 constexpr float kPointsPerInch = 72.0f; 59 constexpr float kPointsPerCm = 1.0f / 2.54f; 60 switch (aUnit) { 61 case ResolutionUnit::Dpi: 62 return aResolution / kPointsPerInch; 63 case ResolutionUnit::Dpcm: 64 return aResolution / kPointsPerCm; 65 } 66 MOZ_CRASH("Unknown resolution unit?"); 67 } 68 69 static Resolution ResolutionFromParsedData(const ParsedEXIFData& aData, 70 const gfx::IntSize& aRealImageSize) { 71 if (!aData.resolutionUnit || !aData.resolutionX || !aData.resolutionY) { 72 return {}; 73 } 74 75 Resolution resolution{ToDppx(*aData.resolutionX, *aData.resolutionUnit), 76 ToDppx(*aData.resolutionY, *aData.resolutionUnit)}; 77 78 if (StaticPrefs::image_exif_density_correction_sanity_check_enabled()) { 79 if (!aData.pixelXDimension || !aData.pixelYDimension) { 80 return {}; 81 } 82 83 const gfx::IntSize exifSize(*aData.pixelXDimension, *aData.pixelYDimension); 84 85 gfx::IntSize scaledSize = aRealImageSize; 86 resolution.ApplyTo(scaledSize.width, scaledSize.height); 87 88 if (exifSize != scaledSize) { 89 return {}; 90 } 91 } 92 93 return resolution; 94 } 95 96 ///////////////////////////////////////////////////////////// 97 // Parse EXIF data, typically found in a JPEG's APP1 segment. 98 ///////////////////////////////////////////////////////////// 99 EXIFData EXIFParser::ParseEXIF(const uint8_t* aData, const uint32_t aLength, 100 const gfx::IntSize& aRealImageSize) { 101 if (!Initialize(aData, aLength)) { 102 return EXIFData(); 103 } 104 105 if (mExpectExifIdCode) { 106 if (!ParseEXIFHeader()) { 107 return EXIFData(); 108 } 109 } 110 111 uint32_t offsetIFD; 112 if (!ParseTIFFHeader(offsetIFD)) { 113 return EXIFData(); 114 } 115 116 JumpTo(offsetIFD); 117 118 ParsedEXIFData data; 119 ParseIFD(data); 120 121 return EXIFData{data.orientation, 122 ResolutionFromParsedData(data, aRealImageSize)}; 123 } 124 125 ///////////////////////////////////////////////////////// 126 // Parse the EXIF header. (Section 4.7.2, Figure 30) 127 ///////////////////////////////////////////////////////// 128 bool EXIFParser::ParseEXIFHeader() { 129 return MatchString(EXIFHeader, EXIFHeaderLength); 130 } 131 132 ///////////////////////////////////////////////////////// 133 // Parse the TIFF header. (Section 4.5.2, Table 1) 134 ///////////////////////////////////////////////////////// 135 bool EXIFParser::ParseTIFFHeader(uint32_t& aIFD0OffsetOut) { 136 // Determine byte order. 137 if (MatchString("MM\0*", 4)) { 138 mByteOrder = ByteOrder::BigEndian; 139 } else if (MatchString("II*\0", 4)) { 140 mByteOrder = ByteOrder::LittleEndian; 141 } else { 142 return false; 143 } 144 145 // Determine offset of the 0th IFD. (It shouldn't be greater than 64k, which 146 // is the maximum size of the entry APP1 segment.) 147 uint32_t ifd0Offset; 148 if (!ReadUInt32(ifd0Offset) || ifd0Offset > 64 * 1024) { 149 return false; 150 } 151 152 // The IFD offset is relative to the beginning of the TIFF header, which 153 // begins after the EXIF header, so we need to increase the offset 154 // appropriately. 155 aIFD0OffsetOut = ifd0Offset + TIFFHeaderStart(); 156 return true; 157 } 158 159 // An arbitrary limit on the amount of pointers that we'll chase, to prevent bad 160 // inputs getting us stuck. 161 constexpr uint32_t kMaxEXIFDepth = 16; 162 163 ///////////////////////////////////////////////////////// 164 // Parse the entries in IFD0. (Section 4.6.2) 165 ///////////////////////////////////////////////////////// 166 void EXIFParser::ParseIFD(ParsedEXIFData& aData, uint32_t aDepth) { 167 if (NS_WARN_IF(aDepth > kMaxEXIFDepth)) { 168 return; 169 } 170 171 uint16_t entryCount; 172 if (!ReadUInt16(entryCount)) { 173 return; 174 } 175 176 for (uint16_t entry = 0; entry < entryCount; ++entry) { 177 // Read the fields of the 12-byte entry. 178 uint16_t tag; 179 if (!ReadUInt16(tag)) { 180 return; 181 } 182 183 uint16_t type; 184 if (!ReadUInt16(type)) { 185 return; 186 } 187 188 uint32_t count; 189 if (!ReadUInt32(count)) { 190 return; 191 } 192 193 switch (EXIFTag(tag)) { 194 case EXIFTag::Orientation: 195 // We should have an orientation value here; go ahead and parse it. 196 if (!ParseOrientation(type, count, aData.orientation)) { 197 return; 198 } 199 break; 200 case EXIFTag::ResolutionUnit: 201 if (!ParseResolutionUnit(type, count, aData.resolutionUnit)) { 202 return; 203 } 204 break; 205 case EXIFTag::XResolution: 206 if (!ParseResolution(type, count, aData.resolutionX)) { 207 return; 208 } 209 break; 210 case EXIFTag::YResolution: 211 if (!ParseResolution(type, count, aData.resolutionY)) { 212 return; 213 } 214 break; 215 case EXIFTag::PixelXDimension: 216 if (!ParseDimension(type, count, aData.pixelXDimension)) { 217 return; 218 } 219 break; 220 case EXIFTag::PixelYDimension: 221 if (!ParseDimension(type, count, aData.pixelYDimension)) { 222 return; 223 } 224 break; 225 case EXIFTag::IFDPointer: { 226 uint32_t offset; 227 if (!ReadUInt32(offset)) { 228 return; 229 } 230 231 ScopedJump jump(*this, offset + TIFFHeaderStart()); 232 ParseIFD(aData, aDepth + 1); 233 break; 234 } 235 236 default: 237 Advance(4); 238 break; 239 } 240 } 241 } 242 243 bool EXIFParser::ReadRational(float& aOut) { 244 // Values larger than 4 bytes (like rationals) are specified as an offset into 245 // the TIFF header. 246 uint32_t valueOffset; 247 if (!ReadUInt32(valueOffset)) { 248 return false; 249 } 250 ScopedJump jumpToHeader(*this, valueOffset + TIFFHeaderStart()); 251 uint32_t numerator; 252 if (!ReadUInt32(numerator)) { 253 return false; 254 } 255 uint32_t denominator; 256 if (!ReadUInt32(denominator)) { 257 return false; 258 } 259 if (denominator == 0) { 260 return false; 261 } 262 aOut = float(numerator) / float(denominator); 263 return true; 264 } 265 266 bool EXIFParser::ParseResolution(uint16_t aType, uint32_t aCount, 267 Maybe<float>& aOut) { 268 if (aType != RationalType || aCount != 1) { 269 return false; 270 } 271 float value; 272 if (!ReadRational(value)) { 273 return false; 274 } 275 if (value == 0.0f) { 276 return false; 277 } 278 aOut = Some(value); 279 return true; 280 } 281 282 bool EXIFParser::ParseDimension(uint16_t aType, uint32_t aCount, 283 Maybe<uint32_t>& aOut) { 284 if (aCount != 1) { 285 return false; 286 } 287 288 switch (aType) { 289 case ShortType: { 290 uint16_t value; 291 if (!ReadUInt16(value)) { 292 return false; 293 } 294 aOut = Some(value); 295 Advance(2); 296 break; 297 } 298 case LongType: { 299 uint32_t value; 300 if (!ReadUInt32(value)) { 301 return false; 302 } 303 aOut = Some(value); 304 break; 305 } 306 default: 307 return false; 308 } 309 return true; 310 } 311 312 bool EXIFParser::ParseResolutionUnit(uint16_t aType, uint32_t aCount, 313 Maybe<ResolutionUnit>& aOut) { 314 if (aType != ShortType || aCount != 1) { 315 return false; 316 } 317 uint16_t value; 318 if (!ReadUInt16(value)) { 319 return false; 320 } 321 switch (value) { 322 case 2: 323 aOut = Some(ResolutionUnit::Dpi); 324 break; 325 case 3: 326 aOut = Some(ResolutionUnit::Dpcm); 327 break; 328 default: 329 return false; 330 } 331 332 // This is a 32-bit field, but the unit value only occupies the first 16 bits. 333 // We need to advance another 16 bits to consume the entire field. 334 Advance(2); 335 return true; 336 } 337 338 bool EXIFParser::ParseOrientation(uint16_t aType, uint32_t aCount, 339 Orientation& aOut) { 340 // Sanity check the type and count. 341 if (aType != ShortType || aCount != 1) { 342 return false; 343 } 344 345 uint16_t value; 346 if (!ReadUInt16(value)) { 347 return false; 348 } 349 350 switch (value) { 351 case 1: 352 aOut = Orientation(Angle::D0, Flip::Unflipped); 353 break; 354 case 2: 355 aOut = Orientation(Angle::D0, Flip::Horizontal); 356 break; 357 case 3: 358 aOut = Orientation(Angle::D180, Flip::Unflipped); 359 break; 360 case 4: 361 aOut = Orientation(Angle::D180, Flip::Horizontal); 362 break; 363 case 5: 364 aOut = Orientation(Angle::D90, Flip::Horizontal); 365 break; 366 case 6: 367 aOut = Orientation(Angle::D90, Flip::Unflipped); 368 break; 369 case 7: 370 aOut = Orientation(Angle::D270, Flip::Horizontal); 371 break; 372 case 8: 373 aOut = Orientation(Angle::D270, Flip::Unflipped); 374 break; 375 default: 376 return false; 377 } 378 379 // This is a 32-bit field, but the orientation value only occupies the first 380 // 16 bits. We need to advance another 16 bits to consume the entire field. 381 Advance(2); 382 return true; 383 } 384 385 bool EXIFParser::Initialize(const uint8_t* aData, const uint32_t aLength) { 386 if (aData == nullptr) { 387 return false; 388 } 389 390 // An APP1 segment larger than 64k violates the JPEG standard. 391 if (aLength > 64 * 1024) { 392 return false; 393 } 394 395 mStart = mCurrent = aData; 396 mLength = mRemainingLength = aLength; 397 mByteOrder = ByteOrder::Unknown; 398 return true; 399 } 400 401 void EXIFParser::Advance(const uint32_t aDistance) { 402 if (mRemainingLength >= aDistance) { 403 mCurrent += aDistance; 404 mRemainingLength -= aDistance; 405 } else { 406 mCurrent = mStart; 407 mRemainingLength = 0; 408 } 409 } 410 411 void EXIFParser::JumpTo(const uint32_t aOffset) { 412 if (mLength >= aOffset) { 413 mCurrent = mStart + aOffset; 414 mRemainingLength = mLength - aOffset; 415 } else { 416 mCurrent = mStart; 417 mRemainingLength = 0; 418 } 419 } 420 421 bool EXIFParser::MatchString(const char* aString, const uint32_t aLength) { 422 if (mRemainingLength < aLength) { 423 return false; 424 } 425 426 for (uint32_t i = 0; i < aLength; ++i) { 427 if (mCurrent[i] != aString[i]) { 428 return false; 429 } 430 } 431 432 Advance(aLength); 433 return true; 434 } 435 436 bool EXIFParser::MatchUInt16(const uint16_t aValue) { 437 if (mRemainingLength < 2) { 438 return false; 439 } 440 441 bool matched; 442 switch (mByteOrder) { 443 case ByteOrder::LittleEndian: 444 matched = LittleEndian::readUint16(mCurrent) == aValue; 445 break; 446 case ByteOrder::BigEndian: 447 matched = BigEndian::readUint16(mCurrent) == aValue; 448 break; 449 default: 450 MOZ_ASSERT_UNREACHABLE("Should know the byte order by now"); 451 matched = false; 452 } 453 454 if (matched) { 455 Advance(2); 456 } 457 458 return matched; 459 } 460 461 bool EXIFParser::ReadUInt16(uint16_t& aValue) { 462 if (mRemainingLength < 2) { 463 return false; 464 } 465 466 bool matched = true; 467 switch (mByteOrder) { 468 case ByteOrder::LittleEndian: 469 aValue = LittleEndian::readUint16(mCurrent); 470 break; 471 case ByteOrder::BigEndian: 472 aValue = BigEndian::readUint16(mCurrent); 473 break; 474 default: 475 MOZ_ASSERT_UNREACHABLE("Should know the byte order by now"); 476 matched = false; 477 } 478 479 if (matched) { 480 Advance(2); 481 } 482 483 return matched; 484 } 485 486 bool EXIFParser::ReadUInt32(uint32_t& aValue) { 487 if (mRemainingLength < 4) { 488 return false; 489 } 490 491 bool matched = true; 492 switch (mByteOrder) { 493 case ByteOrder::LittleEndian: 494 aValue = LittleEndian::readUint32(mCurrent); 495 break; 496 case ByteOrder::BigEndian: 497 aValue = BigEndian::readUint32(mCurrent); 498 break; 499 default: 500 MOZ_ASSERT_UNREACHABLE("Should know the byte order by now"); 501 matched = false; 502 } 503 504 if (matched) { 505 Advance(4); 506 } 507 508 return matched; 509 } 510 511 } // namespace mozilla::image