212 lines
8.0 KiB
C++
212 lines
8.0 KiB
C++
// 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_
|