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