aboutsummaryrefslogtreecommitdiff
path: root/src/tiff_parser.h
blob: e19dea2c2a5705873ff3dd702ccc8dc9f425037a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2015 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

#ifndef PIEX_TIFF_PARSER_H_
#define PIEX_TIFF_PARSER_H_

#include <cstdint>
#include <memory>
#include <set>
#include <vector>

#include "src/piex_types.h"
#include "src/tiff_directory/tiff_directory.h"

namespace piex {

// Specifies the maximum number of pixels for thumbnails in each direction.
const int kThumbnailMaxDimension = 512;

// Specifies all tags that might be of interest to get the preview data.
enum GpsTags {
  kGpsTagLatitudeRef = 1,
  kGpsTagLatitude = 2,
  kGpsTagLongitudeRef = 3,
  kGpsTagLongitude = 4,
  kGpsTagAltitudeRef = 5,
  kGpsTagAltitude = 6,
  kGpsTagTimeStamp = 7,
  kGpsTagDateStamp = 29,
};

enum TiffTags {
  kExifTagColorSpace = 0xA001,
  kExifTagDateTimeOriginal = 0x9003,
  kExifTagDefaultCropSize = 0xC620,
  kExifTagExposureTime = 0x829a,
  kExifTagFnumber = 0x829d,
  kExifTagFocalLength = 0x920A,
  kExifTagGps = 0x8825,
  kExifTagHeight = 0xA003,
  kExifTagIsoSpeed = 0x8827,
  kExifTagMakernotes = 0x927C,
  kExifTagWidth = 0xA002,
  kOlymTagAspectFrame = 0x1113,
  kOlymTagCameraSettings = 0x2020,
  kOlymTagRawProcessing = 0x2040,
  kPanaTagBottomBorder = 0x006,
  kPanaTagIso = 0x0017,
  kPanaTagJpegImage = 0x002E,
  kPanaTagLeftBorder = 0x0005,
  kPanaTagRightBorder = 0x007,
  kPanaTagTopBorder = 0x0004,
  kPentaxTagColorSpace = 0x0037,
  kTiffTagArtist = 0x013B,
  kTiffTagBitsPerSample = 0x0102,
  kTiffTagCfaPatternDim = 0x828D,
  kTiffTagCompression = 0x0103,
  kTiffTagDateTime = 0x0132,
  kTiffTagExifIfd = 0x8769,
  kTiffTagImageDescription = 0x010E,
  kTiffTagImageLength = 0x0101,
  kTiffTagImageWidth = 0x0100,
  kTiffTagJpegByteCount = 0x0202,
  kTiffTagJpegOffset = 0x0201,
  kTiffTagMake = 0x010F,
  kTiffTagModel = 0x0110,
  kTiffTagOrientation = 0x0112,
  kTiffTagPhotometric = 0x0106,
  kTiffTagPlanarConfig = 0x011C,
  kTiffTagResolutionUnit = 0x0128,
  kTiffTagRowsPerStrip = 0x0116,
  kTiffTagSamplesPerPixel = 0x0115,
  kTiffTagSoftware = 0x0131,
  kTiffTagStripByteCounts = 0x0117,
  kTiffTagStripOffsets = 0x0111,
  kTiffTagSubFileType = 0x00FE,
  kTiffTagSubIfd = 0x014A,
  kTiffTagTileByteCounts = 0x0145,
  kTiffTagTileLength = 0x0143,
  kTiffTagTileOffsets = 0x0144,
  kTiffTagTileWidth = 0x0142,
  kTiffTagXresolution = 0x011A,
  kTiffTagYresolution = 0x011B,
};

typedef std::set<tiff_directory::TiffDirectory::Tag> TagSet;
typedef std::vector<tiff_directory::TiffDirectory> IfdVector;

struct TiffContent {
  IfdVector tiff_directory;
  std::unique_ptr<tiff_directory::TiffDirectory> exif_directory;
  std::unique_ptr<tiff_directory::TiffDirectory> gps_directory;
};

// Reads 2 bytes, an unsigned 16bit from 'stream' at a certain 'offset'. The
// bytes get swapped according to the desired endianness returning true on
// success. Returns false when something is wrong.
bool Get16u(StreamInterface* stream, const std::uint32_t offset,
            const tiff_directory::Endian& endian, std::uint16_t* value);

// Reads 4 bytes, an unsigned 32bit 'value' from 'stream' at a certain 'offset'.
// The bytes get swapped according to the desired endianness returning true on
// success. Returns false when something is wrong.
bool Get32u(StreamInterface* stream, const std::uint32_t offset,
            const tiff_directory::Endian& endian, std::uint32_t* value);

// Retrieves a byte vector of size 'length' from 'stream' beginning at some
// 'offset' reading the data in chunks of one MiB.
// If 'error' is not set to kOk the returned value is invalid.
std::vector<std::uint8_t> GetData(const size_t offset, const size_t length,
                                  StreamInterface* stream, Error* error);

// Retrieves the endianness of TIFF compliant data at 'tiff_offset' from
// 'stream' returning true on success. Returns false when something is wrong.
bool GetEndianness(const std::uint32_t tiff_offset, StreamInterface* stream,
                   tiff_directory::Endian* endian);

// Retrieves an image from tiff_directory. Return false when something is wrong.
bool GetImageData(const tiff_directory::TiffDirectory& tiff_directory,
                  StreamInterface* stream, Image* image);

// Retrieves the width and height from the jpeg image returning true on
// success. Returns false when something is wrong.
bool GetJpegDimensions(const std::uint32_t jpeg_offset, StreamInterface* stream,
                       std::uint16_t* width, std::uint16_t* height);

// According to Tiff/EP a thumbnail has max 256 pixels per dimension.
// http://standardsproposals.bsigroup.com/Home/getPDF/567
bool IsThumbnail(const Image& image,
                 const int max_dimension = kThumbnailMaxDimension);

// Parses through a Tiff IFD and writes all 'desired_tags' to a
// 'tiff_directory'.
// Returns false if something with the Tiff data is wrong.
bool ParseDirectory(const std::uint32_t tiff_offset,
                    const std::uint32_t ifd_offset,
                    const tiff_directory::Endian endian,
                    const TagSet& desired_tags, StreamInterface* stream,
                    tiff_directory::TiffDirectory* tiff_directory,
                    std::uint32_t* next_ifd_offset);

// Returns true if Exif orientation for the image can be obtained. False
// otherwise.
bool GetExifOrientation(StreamInterface* stream, const std::uint32_t offset,
                        std::uint32_t* orientation);

// Reads the width and height of the full resolution image. The tag groups are
// exclusive.
bool GetFullDimension32(const tiff_directory::TiffDirectory& tiff_directory,
                        std::uint32_t* width, std::uint32_t* height);

// Reads the width and height of the crop information if available.
// Returns false if an error occurred.
bool GetFullCropDimension(const tiff_directory::TiffDirectory& tiff_directory,
                          std::uint32_t* width, std::uint32_t* height);

// Reads 1 or more rational values for a tag and stores results into data.
// Returns false if an error occurred.
bool GetRational(const tiff_directory::TiffDirectory::Tag& tag,
                 const tiff_directory::TiffDirectory& directory,
                 const int data_size, PreviewImageData::Rational* data);

// Enables us to parse through data that complies to the Tiff/EP specification.
class TiffParser {
 public:
  // The caller owns 'stream' and is responsible to keep it alive while the
  // TiffParser object is used.
  explicit TiffParser(StreamInterface* stream);
  TiffParser(StreamInterface* stream, const std::uint32_t offset);

  // Runs over the Tiff IFD, Exif IFD and subIFDs to get the preview image data.
  // Returns false if something with the Tiff tags is wrong.
  bool GetPreviewImageData(const TiffContent& tiff_content,
                           PreviewImageData* preview_image_data);

  // Returns false if called more that once or something with the Tiff data is
  // wrong.
  bool Parse(const TagSet& desired_tags, const std::uint16_t max_number_ifds,
             TiffContent* tiff_content);

 private:
  // Disallow copy and assignment.
  TiffParser(const TiffParser&) = delete;
  TiffParser& operator=(const TiffParser&) = delete;

  bool ParseIfd(const std::uint32_t ifd_offset, const TagSet& desired_tags,
                const std::uint16_t max_number_ifds, IfdVector* tiff_directory);
  bool ParseGpsData(const tiff_directory::TiffDirectory* tiff_ifd,
                    TiffContent* tiff_content);

  StreamInterface* stream_ = nullptr;
  std::uint32_t tiff_offset_ = 0;
  tiff_directory::Endian endian_;
};

}  // namespace piex

#endif  // PIEX_TIFF_PARSER_H_