exif.h (2956B)
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_EXIF_H_ 7 #define LIB_JXL_EXIF_H_ 8 9 // Basic parsing of Exif (just enough for the render-impacting things 10 // like orientation) 11 12 #include <jxl/codestream_header.h> 13 14 #include <cstddef> 15 #include <cstdint> 16 #include <vector> 17 18 #include "lib/jxl/base/byte_order.h" 19 #include "lib/jxl/base/compiler_specific.h" 20 21 namespace jxl { 22 23 constexpr uint16_t kExifOrientationTag = 274; 24 25 // Checks if a blob looks like Exif, and if so, sets bigendian 26 // according to the tiff endianness 27 JXL_INLINE bool IsExif(const std::vector<uint8_t>& exif, bool* bigendian) { 28 if (exif.size() < 12) return false; // not enough bytes for a valid exif blob 29 const uint8_t* t = exif.data(); 30 if (LoadLE32(t) == 0x2A004D4D) { 31 *bigendian = true; 32 return true; 33 } else if (LoadLE32(t) == 0x002A4949) { 34 *bigendian = false; 35 return true; 36 } 37 return false; // not a valid tiff header 38 } 39 40 // Finds the position of an Exif tag, or 0 if it is not found 41 JXL_INLINE size_t FindExifTagPosition(const std::vector<uint8_t>& exif, 42 uint16_t tagname) { 43 bool bigendian; 44 if (!IsExif(exif, &bigendian)) return 0; 45 const uint8_t* t = exif.data() + 4; 46 uint64_t offset = (bigendian ? LoadBE32(t) : LoadLE32(t)); 47 if (exif.size() < 12 + offset + 2 || offset < 8) return 0; 48 t += offset - 4; 49 if (offset + 2 >= exif.size()) return 0; 50 uint16_t nb_tags = (bigendian ? LoadBE16(t) : LoadLE16(t)); 51 t += 2; 52 while (nb_tags > 0) { 53 if (t + 12 >= exif.data() + exif.size()) return 0; 54 uint16_t tag = (bigendian ? LoadBE16(t) : LoadLE16(t)); 55 t += 2; 56 if (tag == tagname) return static_cast<size_t>(t - exif.data()); 57 t += 10; 58 nb_tags--; 59 } 60 return 0; 61 } 62 63 // TODO(jon): tag 1 can be used to represent Adobe RGB 1998 if it has value 64 // "R03" 65 // TODO(jon): set intrinsic dimensions according to 66 // https://discourse.wicg.io/t/proposal-exif-image-resolution-auto-and-from-image/4326/24 67 // Parses the Exif data just enough to extract any render-impacting info. 68 // If the Exif data is invalid or could not be parsed, then it is treated 69 // as a no-op. 70 JXL_INLINE void InterpretExif(const std::vector<uint8_t>& exif, 71 JxlOrientation* orientation) { 72 bool bigendian; 73 if (!IsExif(exif, &bigendian)) return; 74 size_t o_pos = FindExifTagPosition(exif, kExifOrientationTag); 75 if (o_pos) { 76 const uint8_t* t = exif.data() + o_pos; 77 uint16_t type = (bigendian ? LoadBE16(t) : LoadLE16(t)); 78 t += 2; 79 uint32_t count = (bigendian ? LoadBE32(t) : LoadLE32(t)); 80 t += 4; 81 uint16_t value = (bigendian ? LoadBE16(t) : LoadLE16(t)); 82 if (type == 3 && count == 1 && value >= 1 && value <= 8) { 83 *orientation = static_cast<JxlOrientation>(value); 84 } 85 } 86 } 87 88 } // namespace jxl 89 90 #endif // LIB_JXL_EXIF_H_