Home | History | Annotate | Download | only in src
      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