1 // Copyright 2015 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 #ifndef PIEX_TIFF_PARSER_H_ 18 #define PIEX_TIFF_PARSER_H_ 19 20 #include <cstdint> 21 #include <memory> 22 #include <set> 23 #include <vector> 24 25 #include "src/piex_types.h" 26 #include "src/tiff_directory/tiff_directory.h" 27 28 namespace piex { 29 30 // Specifies the maximum number of pixels for thumbnails in each direction. 31 const int kThumbnailMaxDimension = 512; 32 33 // Specifies all tags that might be of interest to get the preview data. 34 enum GpsTags { 35 kGpsTagLatitudeRef = 1, 36 kGpsTagLatitude = 2, 37 kGpsTagLongitudeRef = 3, 38 kGpsTagLongitude = 4, 39 kGpsTagAltitudeRef = 5, 40 kGpsTagAltitude = 6, 41 kGpsTagTimeStamp = 7, 42 kGpsTagDateStamp = 29, 43 }; 44 45 enum TiffTags { 46 kExifTagColorSpace = 0xA001, 47 kExifTagDateTimeOriginal = 0x9003, 48 kExifTagDefaultCropSize = 0xC620, 49 kExifTagExposureTime = 0x829a, 50 kExifTagFnumber = 0x829d, 51 kExifTagFocalLength = 0x920A, 52 kExifTagGps = 0x8825, 53 kExifTagHeight = 0xA003, 54 kExifTagIsoSpeed = 0x8827, 55 kExifTagMakernotes = 0x927C, 56 kExifTagWidth = 0xA002, 57 kOlymTagAspectFrame = 0x1113, 58 kOlymTagCameraSettings = 0x2020, 59 kOlymTagRawProcessing = 0x2040, 60 kPanaTagBottomBorder = 0x006, 61 kPanaTagIso = 0x0017, 62 kPanaTagJpegImage = 0x002E, 63 kPanaTagLeftBorder = 0x0005, 64 kPanaTagRightBorder = 0x007, 65 kPanaTagTopBorder = 0x0004, 66 kPentaxTagColorSpace = 0x0037, 67 kTiffTagArtist = 0x013B, 68 kTiffTagBitsPerSample = 0x0102, 69 kTiffTagCfaPatternDim = 0x828D, 70 kTiffTagCompression = 0x0103, 71 kTiffTagDateTime = 0x0132, 72 kTiffTagExifIfd = 0x8769, 73 kTiffTagImageDescription = 0x010E, 74 kTiffTagImageLength = 0x0101, 75 kTiffTagImageWidth = 0x0100, 76 kTiffTagJpegByteCount = 0x0202, 77 kTiffTagJpegOffset = 0x0201, 78 kTiffTagMake = 0x010F, 79 kTiffTagModel = 0x0110, 80 kTiffTagOrientation = 0x0112, 81 kTiffTagPhotometric = 0x0106, 82 kTiffTagPlanarConfig = 0x011C, 83 kTiffTagResolutionUnit = 0x0128, 84 kTiffTagRowsPerStrip = 0x0116, 85 kTiffTagSamplesPerPixel = 0x0115, 86 kTiffTagSoftware = 0x0131, 87 kTiffTagStripByteCounts = 0x0117, 88 kTiffTagStripOffsets = 0x0111, 89 kTiffTagSubFileType = 0x00FE, 90 kTiffTagSubIfd = 0x014A, 91 kTiffTagTileByteCounts = 0x0145, 92 kTiffTagTileLength = 0x0143, 93 kTiffTagTileOffsets = 0x0144, 94 kTiffTagTileWidth = 0x0142, 95 kTiffTagXresolution = 0x011A, 96 kTiffTagYresolution = 0x011B, 97 }; 98 99 typedef std::set<tiff_directory::TiffDirectory::Tag> TagSet; 100 typedef std::vector<tiff_directory::TiffDirectory> IfdVector; 101 102 struct TiffContent { 103 IfdVector tiff_directory; 104 std::unique_ptr<tiff_directory::TiffDirectory> exif_directory; 105 std::unique_ptr<tiff_directory::TiffDirectory> gps_directory; 106 }; 107 108 // Reads 2 bytes, an unsigned 16bit from 'stream' at a certain 'offset'. The 109 // bytes get swapped according to the desired endianness returning true on 110 // success. Returns false when something is wrong. 111 bool Get16u(StreamInterface* stream, const std::uint32_t offset, 112 const tiff_directory::Endian& endian, std::uint16_t* value); 113 114 // Reads 4 bytes, an unsigned 32bit 'value' from 'stream' at a certain 'offset'. 115 // The bytes get swapped according to the desired endianness returning true on 116 // success. Returns false when something is wrong. 117 bool Get32u(StreamInterface* stream, const std::uint32_t offset, 118 const tiff_directory::Endian& endian, std::uint32_t* value); 119 120 // Retrieves a byte vector of size 'length' from 'stream' beginning at some 121 // 'offset' reading the data in chunks of one MiB. 122 // If 'error' is not set to kOk the returned value is invalid. 123 std::vector<std::uint8_t> GetData(const size_t offset, const size_t length, 124 StreamInterface* stream, Error* error); 125 126 // Retrieves the endianness of TIFF compliant data at 'tiff_offset' from 127 // 'stream' returning true on success. Returns false when something is wrong. 128 bool GetEndianness(const std::uint32_t tiff_offset, StreamInterface* stream, 129 tiff_directory::Endian* endian); 130 131 // Retrieves an image from tiff_directory. Return false when something is wrong. 132 bool GetImageData(const tiff_directory::TiffDirectory& tiff_directory, 133 StreamInterface* stream, Image* image); 134 135 // Retrieves the width and height from the jpeg image returning true on 136 // success. Returns false when something is wrong. 137 bool GetJpegDimensions(const std::uint32_t jpeg_offset, StreamInterface* stream, 138 std::uint16_t* width, std::uint16_t* height); 139 140 // According to Tiff/EP a thumbnail has max 256 pixels per dimension. 141 // http://standardsproposals.bsigroup.com/Home/getPDF/567 142 bool IsThumbnail(const Image& image, 143 const int max_dimension = kThumbnailMaxDimension); 144 145 // Parses through a Tiff IFD and writes all 'desired_tags' to a 146 // 'tiff_directory'. 147 // Returns false if something with the Tiff data is wrong. 148 bool ParseDirectory(const std::uint32_t tiff_offset, 149 const std::uint32_t ifd_offset, 150 const tiff_directory::Endian endian, 151 const TagSet& desired_tags, StreamInterface* stream, 152 tiff_directory::TiffDirectory* tiff_directory, 153 std::uint32_t* next_ifd_offset); 154 155 // Returns true if Exif orientation for the image can be obtained. False 156 // otherwise. 157 bool GetExifOrientation(StreamInterface* stream, const std::uint32_t offset, 158 std::uint32_t* orientation); 159 160 // Reads the width and height of the full resolution image. The tag groups are 161 // exclusive. 162 bool GetFullDimension32(const tiff_directory::TiffDirectory& tiff_directory, 163 std::uint32_t* width, std::uint32_t* height); 164 165 // Reads the width and height of the crop information if available. 166 // Returns false if an error occurred. 167 bool GetFullCropDimension(const tiff_directory::TiffDirectory& tiff_directory, 168 std::uint32_t* width, std::uint32_t* height); 169 170 // Enables us to parse through data that complies to the Tiff/EP specification. 171 class TiffParser { 172 public: 173 // The caller owns 'stream' and is responsible to keep it alive while the 174 // TiffParser object is used. 175 explicit TiffParser(StreamInterface* stream); 176 TiffParser(StreamInterface* stream, const std::uint32_t offset); 177 178 // Runs over the Tiff IFD, Exif IFD and subIFDs to get the preview image data. 179 // Returns false if something with the Tiff tags is wrong. 180 bool GetPreviewImageData(const TiffContent& tiff_content, 181 PreviewImageData* image_metadata); 182 183 // Returns false if called more that once or something with the Tiff data is 184 // wrong. 185 bool Parse(const TagSet& desired_tags, const std::uint16_t max_number_ifds, 186 TiffContent* tiff_content); 187 188 private: 189 // Disallow copy and assignment. 190 TiffParser(const TiffParser&) = delete; 191 TiffParser& operator=(const TiffParser&) = delete; 192 193 bool ParseIfd(const std::uint32_t ifd_offset, const TagSet& desired_tags, 194 const std::uint16_t max_number_ifds, IfdVector* tiff_directory); 195 bool ParseGpsData(const tiff_directory::TiffDirectory* tiff_ifd, 196 TiffContent* tiff_content); 197 198 StreamInterface* stream_ = nullptr; 199 std::uint32_t tiff_offset_ = 0; 200 tiff_directory::Endian endian_; 201 }; 202 203 } // namespace piex 204 205 #endif // PIEX_TIFF_PARSER_H_ 206