129345531d776962073312d423917406fc59b09f6Jaesung Chung// Copyright 2015 Google Inc. 229345531d776962073312d423917406fc59b09f6Jaesung Chung// 329345531d776962073312d423917406fc59b09f6Jaesung Chung// Licensed under the Apache License, Version 2.0 (the "License"); 429345531d776962073312d423917406fc59b09f6Jaesung Chung// you may not use this file except in compliance with the License. 529345531d776962073312d423917406fc59b09f6Jaesung Chung// You may obtain a copy of the License at 629345531d776962073312d423917406fc59b09f6Jaesung Chung// 729345531d776962073312d423917406fc59b09f6Jaesung Chung// http://www.apache.org/licenses/LICENSE-2.0 829345531d776962073312d423917406fc59b09f6Jaesung Chung// 929345531d776962073312d423917406fc59b09f6Jaesung Chung// Unless required by applicable law or agreed to in writing, software 1029345531d776962073312d423917406fc59b09f6Jaesung Chung// distributed under the License is distributed on an "AS IS" BASIS, 1129345531d776962073312d423917406fc59b09f6Jaesung Chung// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1229345531d776962073312d423917406fc59b09f6Jaesung Chung// See the License for the specific language governing permissions and 1329345531d776962073312d423917406fc59b09f6Jaesung Chung// limitations under the License. 1429345531d776962073312d423917406fc59b09f6Jaesung Chung// 1529345531d776962073312d423917406fc59b09f6Jaesung Chung//////////////////////////////////////////////////////////////////////////////// 1629345531d776962073312d423917406fc59b09f6Jaesung Chung 1729345531d776962073312d423917406fc59b09f6Jaesung Chung#ifndef PIEX_TIFF_PARSER_H_ 1829345531d776962073312d423917406fc59b09f6Jaesung Chung#define PIEX_TIFF_PARSER_H_ 1929345531d776962073312d423917406fc59b09f6Jaesung Chung 2029345531d776962073312d423917406fc59b09f6Jaesung Chung#include <cstdint> 2129345531d776962073312d423917406fc59b09f6Jaesung Chung#include <memory> 2229345531d776962073312d423917406fc59b09f6Jaesung Chung#include <set> 2329345531d776962073312d423917406fc59b09f6Jaesung Chung#include <vector> 2429345531d776962073312d423917406fc59b09f6Jaesung Chung 2529345531d776962073312d423917406fc59b09f6Jaesung Chung#include "src/piex_types.h" 2629345531d776962073312d423917406fc59b09f6Jaesung Chung#include "src/tiff_directory/tiff_directory.h" 2729345531d776962073312d423917406fc59b09f6Jaesung Chung 2829345531d776962073312d423917406fc59b09f6Jaesung Chungnamespace piex { 2929345531d776962073312d423917406fc59b09f6Jaesung Chung 30604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Specifies the maximum number of pixels for thumbnails in each direction. 310edcd9aecceaffe22368d91df82a0e4f6ff47d97Yujie Qinconst int kThumbnailMaxDimension = 512; 32604bae7c753098ee9e040da4270501b37a8663cfYujie Qin 3329345531d776962073312d423917406fc59b09f6Jaesung Chung// Specifies all tags that might be of interest to get the preview data. 343eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qinenum GpsTags { 353eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagLatitudeRef = 1, 363eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagLatitude = 2, 373eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagLongitudeRef = 3, 383eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagLongitude = 4, 393eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagAltitudeRef = 5, 403eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagAltitude = 6, 413eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagTimeStamp = 7, 423eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kGpsTagDateStamp = 29, 433eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin}; 443eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin 453eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qinenum TiffTags { 4629345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagColorSpace = 0xA001, 4729345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagDateTimeOriginal = 0x9003, 4829345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagDefaultCropSize = 0xC620, 4929345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagExposureTime = 0x829a, 5029345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagFnumber = 0x829d, 5129345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagFocalLength = 0x920A, 5229345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagGps = 0x8825, 5329345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagHeight = 0xA003, 5429345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagIsoSpeed = 0x8827, 5529345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagMakernotes = 0x927C, 5629345531d776962073312d423917406fc59b09f6Jaesung Chung kExifTagWidth = 0xA002, 5729345531d776962073312d423917406fc59b09f6Jaesung Chung kOlymTagAspectFrame = 0x1113, 5829345531d776962073312d423917406fc59b09f6Jaesung Chung kOlymTagCameraSettings = 0x2020, 5929345531d776962073312d423917406fc59b09f6Jaesung Chung kOlymTagRawProcessing = 0x2040, 6029345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagBottomBorder = 0x006, 6129345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagIso = 0x0017, 6229345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagJpegImage = 0x002E, 6329345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagLeftBorder = 0x0005, 6429345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagRightBorder = 0x007, 6529345531d776962073312d423917406fc59b09f6Jaesung Chung kPanaTagTopBorder = 0x0004, 663eaa83178e9d1722c126d598d3eee7fb383c2c85Yujie Qin kPentaxTagColorSpace = 0x0037, 6729345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagArtist = 0x013B, 6829345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagBitsPerSample = 0x0102, 69b415ce2eec78846ec705c983f98a74c9526f3faaEik Brauer kTiffTagCfaPatternDim = 0x828D, 7029345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagCompression = 0x0103, 7129345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagDateTime = 0x0132, 7229345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagExifIfd = 0x8769, 7329345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagImageDescription = 0x010E, 7429345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagImageLength = 0x0101, 7529345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagImageWidth = 0x0100, 7629345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagJpegByteCount = 0x0202, 7729345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagJpegOffset = 0x0201, 7829345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagMake = 0x010F, 7929345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagModel = 0x0110, 8029345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagOrientation = 0x0112, 8129345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagPhotometric = 0x0106, 8229345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagPlanarConfig = 0x011C, 8329345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagResolutionUnit = 0x0128, 8429345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagRowsPerStrip = 0x0116, 8529345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagSamplesPerPixel = 0x0115, 8629345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagSoftware = 0x0131, 8729345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagStripByteCounts = 0x0117, 8829345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagStripOffsets = 0x0111, 89604bae7c753098ee9e040da4270501b37a8663cfYujie Qin kTiffTagSubFileType = 0x00FE, 9029345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagSubIfd = 0x014A, 9129345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagTileByteCounts = 0x0145, 9229345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagTileLength = 0x0143, 9329345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagTileOffsets = 0x0144, 9429345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagTileWidth = 0x0142, 9529345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagXresolution = 0x011A, 9629345531d776962073312d423917406fc59b09f6Jaesung Chung kTiffTagYresolution = 0x011B, 9729345531d776962073312d423917406fc59b09f6Jaesung Chung}; 9829345531d776962073312d423917406fc59b09f6Jaesung Chung 99a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauertypedef std::set<tiff_directory::TiffDirectory::Tag> TagSet; 10029345531d776962073312d423917406fc59b09f6Jaesung Chungtypedef std::vector<tiff_directory::TiffDirectory> IfdVector; 10129345531d776962073312d423917406fc59b09f6Jaesung Chung 10229345531d776962073312d423917406fc59b09f6Jaesung Chungstruct TiffContent { 10329345531d776962073312d423917406fc59b09f6Jaesung Chung IfdVector tiff_directory; 10429345531d776962073312d423917406fc59b09f6Jaesung Chung std::unique_ptr<tiff_directory::TiffDirectory> exif_directory; 10529345531d776962073312d423917406fc59b09f6Jaesung Chung std::unique_ptr<tiff_directory::TiffDirectory> gps_directory; 10629345531d776962073312d423917406fc59b09f6Jaesung Chung}; 10729345531d776962073312d423917406fc59b09f6Jaesung Chung 10829345531d776962073312d423917406fc59b09f6Jaesung Chung// Reads 2 bytes, an unsigned 16bit from 'stream' at a certain 'offset'. The 10929345531d776962073312d423917406fc59b09f6Jaesung Chung// bytes get swapped according to the desired endianness returning true on 11029345531d776962073312d423917406fc59b09f6Jaesung Chung// success. Returns false when something is wrong. 11129345531d776962073312d423917406fc59b09f6Jaesung Chungbool Get16u(StreamInterface* stream, const std::uint32_t offset, 11229345531d776962073312d423917406fc59b09f6Jaesung Chung const tiff_directory::Endian& endian, std::uint16_t* value); 11329345531d776962073312d423917406fc59b09f6Jaesung Chung 11429345531d776962073312d423917406fc59b09f6Jaesung Chung// Reads 4 bytes, an unsigned 32bit 'value' from 'stream' at a certain 'offset'. 11529345531d776962073312d423917406fc59b09f6Jaesung Chung// The bytes get swapped according to the desired endianness returning true on 11629345531d776962073312d423917406fc59b09f6Jaesung Chung// success. Returns false when something is wrong. 11729345531d776962073312d423917406fc59b09f6Jaesung Chungbool Get32u(StreamInterface* stream, const std::uint32_t offset, 11829345531d776962073312d423917406fc59b09f6Jaesung Chung const tiff_directory::Endian& endian, std::uint32_t* value); 11929345531d776962073312d423917406fc59b09f6Jaesung Chung 12029345531d776962073312d423917406fc59b09f6Jaesung Chung// Retrieves a byte vector of size 'length' from 'stream' beginning at some 12129345531d776962073312d423917406fc59b09f6Jaesung Chung// 'offset' reading the data in chunks of one MiB. 12229345531d776962073312d423917406fc59b09f6Jaesung Chung// If 'error' is not set to kOk the returned value is invalid. 12329345531d776962073312d423917406fc59b09f6Jaesung Chungstd::vector<std::uint8_t> GetData(const size_t offset, const size_t length, 12429345531d776962073312d423917406fc59b09f6Jaesung Chung StreamInterface* stream, Error* error); 12529345531d776962073312d423917406fc59b09f6Jaesung Chung 12629345531d776962073312d423917406fc59b09f6Jaesung Chung// Retrieves the endianness of TIFF compliant data at 'tiff_offset' from 127604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// 'stream' returning true on success. Returns false when something is wrong. 12829345531d776962073312d423917406fc59b09f6Jaesung Chungbool GetEndianness(const std::uint32_t tiff_offset, StreamInterface* stream, 12929345531d776962073312d423917406fc59b09f6Jaesung Chung tiff_directory::Endian* endian); 13029345531d776962073312d423917406fc59b09f6Jaesung Chung 131604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Retrieves an image from tiff_directory. Return false when something is wrong. 132604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool GetImageData(const tiff_directory::TiffDirectory& tiff_directory, 133604bae7c753098ee9e040da4270501b37a8663cfYujie Qin StreamInterface* stream, Image* image); 134604bae7c753098ee9e040da4270501b37a8663cfYujie Qin 135604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Retrieves the width and height from the jpeg image returning true on 13629345531d776962073312d423917406fc59b09f6Jaesung Chung// success. Returns false when something is wrong. 137604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool GetJpegDimensions(const std::uint32_t jpeg_offset, StreamInterface* stream, 138604bae7c753098ee9e040da4270501b37a8663cfYujie Qin std::uint16_t* width, std::uint16_t* height); 139604bae7c753098ee9e040da4270501b37a8663cfYujie Qin 140604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// According to Tiff/EP a thumbnail has max 256 pixels per dimension. 141604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// http://standardsproposals.bsigroup.com/Home/getPDF/567 142604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool IsThumbnail(const Image& image, 143604bae7c753098ee9e040da4270501b37a8663cfYujie Qin const int max_dimension = kThumbnailMaxDimension); 14429345531d776962073312d423917406fc59b09f6Jaesung Chung 14529345531d776962073312d423917406fc59b09f6Jaesung Chung// Parses through a Tiff IFD and writes all 'desired_tags' to a 14629345531d776962073312d423917406fc59b09f6Jaesung Chung// 'tiff_directory'. 147604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Returns false if something with the Tiff data is wrong. 148604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool ParseDirectory(const std::uint32_t tiff_offset, 149604bae7c753098ee9e040da4270501b37a8663cfYujie Qin const std::uint32_t ifd_offset, 150604bae7c753098ee9e040da4270501b37a8663cfYujie Qin const tiff_directory::Endian endian, 151604bae7c753098ee9e040da4270501b37a8663cfYujie Qin const TagSet& desired_tags, StreamInterface* stream, 152604bae7c753098ee9e040da4270501b37a8663cfYujie Qin tiff_directory::TiffDirectory* tiff_directory, 153604bae7c753098ee9e040da4270501b37a8663cfYujie Qin std::uint32_t* next_ifd_offset); 154604bae7c753098ee9e040da4270501b37a8663cfYujie Qin 155604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Returns true if Exif orientation for the image can be obtained. False 156604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// otherwise. 157604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool GetExifOrientation(StreamInterface* stream, const std::uint32_t offset, 158604bae7c753098ee9e040da4270501b37a8663cfYujie Qin std::uint32_t* orientation); 159604bae7c753098ee9e040da4270501b37a8663cfYujie Qin 160604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// Reads the width and height of the full resolution image. The tag groups are 161604bae7c753098ee9e040da4270501b37a8663cfYujie Qin// exclusive. 162604bae7c753098ee9e040da4270501b37a8663cfYujie Qinbool GetFullDimension32(const tiff_directory::TiffDirectory& tiff_directory, 163604bae7c753098ee9e040da4270501b37a8663cfYujie Qin std::uint32_t* width, std::uint32_t* height); 16429345531d776962073312d423917406fc59b09f6Jaesung Chung 16529345531d776962073312d423917406fc59b09f6Jaesung Chung// Enables us to parse through data that complies to the Tiff/EP specification. 16629345531d776962073312d423917406fc59b09f6Jaesung Chungclass TiffParser { 16729345531d776962073312d423917406fc59b09f6Jaesung Chung public: 16829345531d776962073312d423917406fc59b09f6Jaesung Chung // The caller owns 'stream' and is responsible to keep it alive while the 16929345531d776962073312d423917406fc59b09f6Jaesung Chung // TiffParser object is used. 17029345531d776962073312d423917406fc59b09f6Jaesung Chung explicit TiffParser(StreamInterface* stream); 17129345531d776962073312d423917406fc59b09f6Jaesung Chung TiffParser(StreamInterface* stream, const std::uint32_t offset); 17229345531d776962073312d423917406fc59b09f6Jaesung Chung 17329345531d776962073312d423917406fc59b09f6Jaesung Chung // Runs over the Tiff IFD, Exif IFD and subIFDs to get the preview image data. 174604bae7c753098ee9e040da4270501b37a8663cfYujie Qin // Returns false if something with the Tiff tags is wrong. 175604bae7c753098ee9e040da4270501b37a8663cfYujie Qin bool GetPreviewImageData(const TiffContent& tiff_content, 176604bae7c753098ee9e040da4270501b37a8663cfYujie Qin PreviewImageData* image_metadata); 17729345531d776962073312d423917406fc59b09f6Jaesung Chung 178604bae7c753098ee9e040da4270501b37a8663cfYujie Qin // Returns false if called more that once or something with the Tiff data is 17929345531d776962073312d423917406fc59b09f6Jaesung Chung // wrong. 180604bae7c753098ee9e040da4270501b37a8663cfYujie Qin bool Parse(const TagSet& desired_tags, const std::uint16_t max_number_ifds, 181604bae7c753098ee9e040da4270501b37a8663cfYujie Qin TiffContent* tiff_content); 18229345531d776962073312d423917406fc59b09f6Jaesung Chung 18329345531d776962073312d423917406fc59b09f6Jaesung Chung private: 18429345531d776962073312d423917406fc59b09f6Jaesung Chung // Disallow copy and assignment. 18529345531d776962073312d423917406fc59b09f6Jaesung Chung TiffParser(const TiffParser&) = delete; 18629345531d776962073312d423917406fc59b09f6Jaesung Chung TiffParser& operator=(const TiffParser&) = delete; 18729345531d776962073312d423917406fc59b09f6Jaesung Chung 188604bae7c753098ee9e040da4270501b37a8663cfYujie Qin bool ParseIfd(const std::uint32_t ifd_offset, const TagSet& desired_tags, 189604bae7c753098ee9e040da4270501b37a8663cfYujie Qin const std::uint16_t max_number_ifds, IfdVector* tiff_directory); 190604bae7c753098ee9e040da4270501b37a8663cfYujie Qin bool ParseGpsData(const tiff_directory::TiffDirectory* tiff_ifd, 191604bae7c753098ee9e040da4270501b37a8663cfYujie Qin TiffContent* tiff_content); 19229345531d776962073312d423917406fc59b09f6Jaesung Chung 19329345531d776962073312d423917406fc59b09f6Jaesung Chung StreamInterface* stream_ = nullptr; 19429345531d776962073312d423917406fc59b09f6Jaesung Chung std::uint32_t tiff_offset_ = 0; 19529345531d776962073312d423917406fc59b09f6Jaesung Chung tiff_directory::Endian endian_; 19629345531d776962073312d423917406fc59b09f6Jaesung Chung}; 19729345531d776962073312d423917406fc59b09f6Jaesung Chung 19829345531d776962073312d423917406fc59b09f6Jaesung Chung} // namespace piex 19929345531d776962073312d423917406fc59b09f6Jaesung Chung 20029345531d776962073312d423917406fc59b09f6Jaesung Chung#endif // PIEX_TIFF_PARSER_H_ 201