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