Update PIEX

* Add IsOfType() and GEtNumberofBytesForIsOfType() to image_type_recognition_lite
* Add GetDngInformation() and GetOrientation() to piex
* Remove deprecated data entries from piex_types

cherry-pick of 2f5d8eafb5648056703d6b3dec237d293f75f99e

Bug: 27214608
Change-Id: I845b2b0e4a1c061df6b3956fb3dab258f471937b
diff --git a/src/image_type_recognition/image_type_recognition_lite.cc b/src/image_type_recognition/image_type_recognition_lite.cc
index 45429fd..e0c8491 100644
--- a/src/image_type_recognition/image_type_recognition_lite.cc
+++ b/src/image_type_recognition/image_type_recognition_lite.cc
@@ -61,6 +61,13 @@
 
   // Checks if source data belongs to current checker type.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const = 0;
+
+ protected:
+  // Limits the source length to the RequestedSize(), using it guarantees that
+  // we will not read more than this size from the source.
+  RangeCheckedBytePtr LimitSource(const RangeCheckedBytePtr& source) const {
+    return source.pointerToSubArray(0 /* pos */, RequestedSize());
+  }
 };
 
 // Check if the uint16 value at (source + offset) is equal to the target value.
@@ -150,10 +157,7 @@
   // 3. signature "SONY" in first requested bytes;
   // 4. correct signature for (section + version) in first requested bytes.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -209,10 +213,7 @@
   // 2. magic number "42" at the (offset == 2) position of the file;
   // 3. signature "CR2" at the (offset == 8) position of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -239,10 +240,7 @@
 
   // Check only the signature at the (offset == 6) position of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -271,10 +269,7 @@
   // 2. two tags (OriginalFileName and FirmwareVersion) can be found in the
   // first requested bytes of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -316,10 +311,7 @@
   // 2. at least two dng specific tags in the first requested bytes of the
   // file
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -370,10 +362,7 @@
   // 1. valid endianness at the beginning of the file;
   // 2. two tags (WhiteBalance and SerialNumber) in the first requested bytes.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -410,10 +399,7 @@
   // 2. signature "PKTS    " in the first requested bytes. Note the
   // "whitespace". It's important as they are special binary values.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(source, &use_big_endian)) {
@@ -498,10 +484,7 @@
   // special images that the signature locates in the middle of the file, and it
   // costs too  long time to check;
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -537,10 +520,7 @@
   // 4. the ReferenceBlackWhite tag in the requested bytes of the file;
   // 5. contains the NRW signature;
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -573,10 +553,7 @@
   // 2. tag at the (offset == 2) position of the file;
   // 3. signature "OLYMP" in the first requested bytes.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -611,10 +588,7 @@
   // 2. magic numbers at the (offset == 2 and offset==4) positions of the file;
   // 3. signature "AOC   " or "PENTAX  " in first requested bytes.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(limited_source, &use_big_endian)) {
@@ -649,10 +623,7 @@
 
   // Check only the signature at the beginning of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     const size_t kSignatureSize = 2;
     const string kSignature[kSignatureSize] = {
@@ -672,10 +643,7 @@
 
   // Check only the signature at the beginning of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     const string kSignature("FUJIFILM");
     return IsSignatureMatched(limited_source, 0 /* offset */, kSignature);
@@ -692,10 +660,7 @@
   // Check only the signature at the (offset == 25) position of the
   // file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     const string kSignature("ARECOYK");
     return IsSignatureMatched(limited_source, 25, kSignature);
@@ -712,10 +677,7 @@
   // Check two points: 1. valid endianness at the beginning of the
   // file; 2. tag at the (offset == 2) position of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(source, &use_big_endian)) {
@@ -740,10 +702,7 @@
   // 2. magic numbers at the (offset == 2 and offset==4) positions of the file;
   // 3. the signature "SAMSUNG" in the requested bytes of the file;
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     bool use_big_endian;
     if (!DetermineEndianness(source, &use_big_endian)) {
@@ -776,10 +735,7 @@
 
   // Check only the signature at the beginning of the file.
   virtual bool IsMyType(const RangeCheckedBytePtr& source) const {
-    // Limits the source length to the RequestedSize(), using it guarantees that
-    // we will not read more than this size from the source.
-    RangeCheckedBytePtr limited_source =
-        source.pointerToSubArray(0 /* pos */, RequestedSize());
+    RangeCheckedBytePtr limited_source = LimitSource(source);
 
     const string kSignature("FOVb", 4);
     return IsSignatureMatched(limited_source, 0 /* offset */, kSignature);
@@ -843,7 +799,34 @@
     return checkers_.back()->RequestedSize();
   }
 
+  bool IsOfType(const RangeCheckedBytePtr& source, const RawImageTypes type) {
+    const TypeChecker* type_checker = GetTypeCheckerForType(type);
+    if (type_checker) {
+      return type_checker->IsMyType(source);
+    } else {
+      return false;
+    }
+  }
+
+  size_t RequestedSizeForType(const RawImageTypes type) {
+    const TypeChecker* type_checker = GetTypeCheckerForType(type);
+    if (type_checker) {
+      return type_checker->RequestedSize();
+    } else {
+      return 0;
+    }
+  }
+
  private:
+  const TypeChecker* GetTypeCheckerForType(const RawImageTypes type) {
+    for (const auto* type_checker : checkers_) {
+      if (type_checker->Type() == type) {
+        return type_checker;
+      }
+    }
+    return nullptr;
+  }
+
   std::vector<TypeChecker*> checkers_;
 };
 
@@ -886,6 +869,10 @@
   return false;
 }
 
+bool IsOfType(const RangeCheckedBytePtr& source, const RawImageTypes type) {
+  return TypeCheckerList().IsOfType(source, type);
+}
+
 RawImageTypes RecognizeRawImageTypeLite(const RangeCheckedBytePtr& source) {
   return TypeCheckerList().GetType(source);
 }
@@ -894,6 +881,10 @@
   return TypeCheckerList().RequestedSize();
 }
 
+size_t GetNumberOfBytesForIsOfType(const RawImageTypes type) {
+  return TypeCheckerList().RequestedSizeForType(type);
+}
+
 bool IsRawLite(const RangeCheckedBytePtr& source) {
   return IsRaw(RecognizeRawImageTypeLite(source));
 }
diff --git a/src/image_type_recognition/image_type_recognition_lite.h b/src/image_type_recognition/image_type_recognition_lite.h
index 5b9ca64..a7e212d 100644
--- a/src/image_type_recognition/image_type_recognition_lite.h
+++ b/src/image_type_recognition/image_type_recognition_lite.h
@@ -61,6 +61,10 @@
 // Checks if the given type is a RAW image type.
 bool IsRaw(const RawImageTypes type);
 
+// Checks if the given source is from given type.
+bool IsOfType(const binary_parse::RangeCheckedBytePtr& source,
+              const RawImageTypes type);
+
 // This function will check the source and return the corresponding image type.
 // If the source is not a recognizable type, this function will return
 // kNonRawImage.
@@ -71,6 +75,10 @@
 // IsRawLite().
 size_t GetNumberOfBytesForIsRawLite();
 
+// Returns the maximum number of bytes needed to recognize a RAF image type in
+// IsOfType().
+size_t GetNumberOfBytesForIsOfType(const RawImageTypes type);
+
 // This function will check if the source belongs to one of the known RAW types.
 bool IsRawLite(const binary_parse::RangeCheckedBytePtr& source);
 
diff --git a/src/piex.cc b/src/piex.cc
index 244a44b..fd381db 100644
--- a/src/piex.cc
+++ b/src/piex.cc
@@ -34,44 +34,85 @@
 using tiff_directory::Endian;
 using tiff_directory::TiffDirectory;
 
-Error GetPreviewData(const TagSet& extended_tags,
-                     const std::uint32_t tiff_offset,
-                     const std::uint32_t number_of_ifds,
-                     StreamInterface* stream, TiffContent* tiff_content,
-                     PreviewImageData* preview_image_data) {
-  TagSet desired_tags = {kExifTagColorSpace,   kExifTagDateTimeOriginal,
-                         kExifTagExposureTime, kExifTagFnumber,
-                         kExifTagFocalLength,  kExifTagGps,
-                         kExifTagIsoSpeed,     kTiffTagDateTime,
-                         kTiffTagExifIfd,      kTiffTagCfaPatternDim,
-                         kTiffTagMake,         kTiffTagModel,
-                         kTiffTagOrientation};
+const std::uint32_t kRafOffsetToPreviewOffset = 84;
+
+bool GetDngInformation(const tiff_directory::TiffDirectory& tiff_directory,
+                       std::uint32_t* width, std::uint32_t* height,
+                       std::vector<std::uint32_t>* cfa_pattern_dim) {
+  if (!GetFullDimension32(tiff_directory, width, height) || *width == 0 ||
+      *height == 0) {
+    return false;
+  }
+
+  if (!tiff_directory.Get(kTiffTagCfaPatternDim, cfa_pattern_dim) ||
+      cfa_pattern_dim->size() != 2) {
+    return false;
+  }
+  return true;
+}
+
+bool GetDngInformation(const TagSet& extended_tags, StreamInterface* data,
+                       std::uint32_t* width, std::uint32_t* height,
+                       std::vector<std::uint32_t>* cfa_pattern_dim) {
+  TagSet desired_tags = {kExifTagDefaultCropSize, kTiffTagCfaPatternDim,
+                         kTiffTagExifIfd, kTiffTagSubFileType};
+  desired_tags.insert(extended_tags.cbegin(), extended_tags.cend());
+
+  TiffParser tiff_parser(data, 0 /* offset */);
+
+  TiffContent tiff_content;
+  if (!tiff_parser.Parse(desired_tags, 1, &tiff_content) ||
+      tiff_content.tiff_directory.empty()) {
+    return false;
+  }
+
+  // If IFD0 contains already the full dimensions we do not parse into the sub
+  // IFD.
+  const TiffDirectory& tiff_directory = tiff_content.tiff_directory[0];
+  if (tiff_directory.GetSubDirectories().empty()) {
+    return GetDngInformation(tiff_directory, width, height, cfa_pattern_dim);
+  } else {
+    return GetDngInformation(tiff_directory.GetSubDirectories()[0], width,
+                             height, cfa_pattern_dim);
+  }
+}
+
+bool GetPreviewData(const TagSet& extended_tags,
+                    const std::uint32_t tiff_offset,
+                    const std::uint32_t number_of_ifds, StreamInterface* stream,
+                    TiffContent* tiff_content,
+                    PreviewImageData* preview_image_data) {
+  TagSet desired_tags = {
+      kExifTagColorSpace, kExifTagDateTimeOriginal, kExifTagExposureTime,
+      kExifTagFnumber,    kExifTagFocalLength,      kExifTagGps,
+      kExifTagIsoSpeed,   kTiffTagCompression,      kTiffTagDateTime,
+      kTiffTagExifIfd,    kTiffTagCfaPatternDim,    kTiffTagMake,
+      kTiffTagModel,      kTiffTagOrientation,      kTiffTagPhotometric};
   desired_tags.insert(extended_tags.cbegin(), extended_tags.cend());
 
   TiffParser tiff_parser(stream, tiff_offset);
-  Error error = tiff_parser.Parse(desired_tags, number_of_ifds, tiff_content);
-  if (error != kOk) {
-    return error;
+
+  if (!tiff_parser.Parse(desired_tags, number_of_ifds, tiff_content)) {
+    return false;
   }
   if (tiff_content->tiff_directory.empty()) {
-    // Returns kFail if the stream does not contain any TIFF structure.
-    return kFail;
+    // Returns false if the stream does not contain any TIFF structure.
+    return false;
   }
   return tiff_parser.GetPreviewImageData(*tiff_content, preview_image_data);
 }
 
-Error GetPreviewData(const TagSet& extended_tags,
-                     const std::uint32_t number_of_ifds,
-                     StreamInterface* stream,
-                     PreviewImageData* preview_image_data) {
+bool GetPreviewData(const TagSet& extended_tags,
+                    const std::uint32_t number_of_ifds, StreamInterface* stream,
+                    PreviewImageData* preview_image_data) {
   const std::uint32_t kTiffOffset = 0;
   TiffContent tiff_content;
   return GetPreviewData(extended_tags, kTiffOffset, number_of_ifds, stream,
                         &tiff_content, preview_image_data);
 }
 
-Error GetExifData(const std::uint32_t exif_offset, StreamInterface* stream,
-                  PreviewImageData* preview_image_data) {
+bool GetExifData(const std::uint32_t exif_offset, StreamInterface* stream,
+                 PreviewImageData* preview_image_data) {
   const TagSet kExtendedTags = {kTiffTagJpegByteCount, kTiffTagJpegOffset};
   const std::uint32_t kNumberOfIfds = 2;
   TiffContent tiff_content;
@@ -88,80 +129,45 @@
 
   const std::uint32_t kNumberOfIfds = 2;
   PreviewImageData thumbnail_data;
-  if (GetPreviewData(desired_tags, kNumberOfIfds, stream, &thumbnail_data) ==
-      kOk) {
-    preview_image_data->thumbnail = thumbnail_data.preview;
-    // TODO: remove the old vars.
-    preview_image_data->thumbnail_offset = thumbnail_data.preview_offset;
-    preview_image_data->thumbnail_length = thumbnail_data.preview_length;
+  if (GetPreviewData(desired_tags, kNumberOfIfds, stream, &thumbnail_data)) {
+    preview_image_data->thumbnail = thumbnail_data.thumbnail;
   }
 }
 
-Error GetExifIfd(const Endian endian, StreamInterface* stream,
-                 TiffDirectory* exif_ifd) {
+bool GetExifIfd(const Endian endian, StreamInterface* stream,
+                TiffDirectory* exif_ifd) {
   const std::uint32_t kTiffOffset = 0;
   std::uint32_t offset_to_ifd;
   if (!Get32u(stream, sizeof(offset_to_ifd), endian, &offset_to_ifd)) {
-    return kFail;
+    return false;
   }
 
   std::uint32_t next_ifd_offset;
   TiffDirectory tiff_ifd(endian);
-  Error error =
-      ParseDirectory(kTiffOffset, offset_to_ifd, endian, {kTiffTagExifIfd},
-                     stream, &tiff_ifd, &next_ifd_offset);
-  if (error != kOk) {
-    return error;
+  if (!ParseDirectory(kTiffOffset, offset_to_ifd, endian, {kTiffTagExifIfd},
+                      stream, &tiff_ifd, &next_ifd_offset)) {
+    return false;
   }
 
   std::uint32_t exif_offset;
-  if (!tiff_ifd.Get(kTiffTagExifIfd, &exif_offset)) {
-    return kUnsupported;
+  if (tiff_ifd.Get(kTiffTagExifIfd, &exif_offset)) {
+    return ParseDirectory(kTiffOffset, exif_offset, endian,
+                          {kExifTagMakernotes}, stream, exif_ifd,
+                          &next_ifd_offset);
   }
 
-  return ParseDirectory(kTiffOffset, exif_offset, endian, {kExifTagMakernotes},
-                        stream, exif_ifd, &next_ifd_offset);
+  return true;
 }
 
-bool IsThumbnail(const Image& image) {
-  // According to Tiff/EP a thumbnail has max 256 pixels per dimension.
-  // http://standardsproposals.bsigroup.com/Home/getPDF/567
-  const std::uint16_t kThumbnailAxis = 256;
-  return image.width <= kThumbnailAxis && image.height <= kThumbnailAxis;
-}
-
-bool GetImageFromIfd(const TiffDirectory& ifd, StreamInterface* stream,
-                     Image* image) {
-  std::uint32_t compression;
-  std::uint32_t photometric_interpretation;
-  if (ifd.Get(kTiffTagPhotometric, &photometric_interpretation) &&
-      ifd.Get(kTiffTagCompression, &compression)) {
-    if (photometric_interpretation == 6 /* YCbCr */ &&
-        (compression == 6 /* JPEG(old) */ || compression == 7 /* JPEG */)) {
-      std::vector<std::uint32_t> strip_offsets;
-      std::vector<std::uint32_t> byte_counts;
-      if (ifd.Get(kTiffTagStripOffsets, &strip_offsets) &&
-          ifd.Get(kTiffTagStripByteCounts, &byte_counts) &&
-          strip_offsets.size() == 1 && byte_counts.size() == 1) {
-        image->length = byte_counts[0];
-        image->offset = strip_offsets[0];
-        return GetPreviewDimensions(image->offset, stream, &image->width,
-                                    &image->height);
-      }
-    }
-  }
-  return false;
-}
-
-Error GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian,
-                      const std::uint32_t skip_offset, StreamInterface* stream,
-                      std::uint32_t* makernote_offset,
-                      TiffDirectory* makernote_ifd) {
+bool GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian,
+                     const std::uint32_t skip_offset, StreamInterface* stream,
+                     std::uint32_t* makernote_offset,
+                     TiffDirectory* makernote_ifd) {
   std::uint32_t makernote_length;
   if (!exif_ifd.GetOffsetAndLength(kExifTagMakernotes,
                                    tiff_directory::TIFF_TYPE_UNDEFINED,
                                    makernote_offset, &makernote_length)) {
-    return kUnsupported;
+    return false;
   }
 
   std::uint32_t next_ifd_offset;
@@ -171,22 +177,22 @@
                         stream, makernote_ifd, &next_ifd_offset);
 }
 
-Error GetCameraSettingsIfd(const TiffDirectory& makernote_ifd,
-                           const std::uint32_t makernote_offset,
-                           const Endian endian, StreamInterface* stream,
-                           TiffDirectory* camera_settings_ifd) {
+bool GetCameraSettingsIfd(const TiffDirectory& makernote_ifd,
+                          const std::uint32_t makernote_offset,
+                          const Endian endian, StreamInterface* stream,
+                          TiffDirectory* camera_settings_ifd) {
   std::uint32_t camera_settings_offset;
   std::uint32_t camera_settings_length;
   if (!makernote_ifd.GetOffsetAndLength(
           kOlymTagCameraSettings, tiff_directory::TIFF_IFD,
           &camera_settings_offset, &camera_settings_length)) {
-    return kUnsupported;
+    return false;
   }
 
   std::uint32_t next_ifd_offset;
   if (!Get32u(stream, camera_settings_offset, endian,
               &camera_settings_offset)) {
-    return kFail;
+    return false;
   }
   return ParseDirectory(makernote_offset,
                         makernote_offset + camera_settings_offset, endian,
@@ -194,22 +200,22 @@
                         camera_settings_ifd, &next_ifd_offset);
 }
 
-Error GetRawProcessingIfd(const TagSet& desired_tags,
-                          const TiffDirectory& makernote_ifd,
-                          const std::uint32_t makernote_offset,
-                          const Endian endian, StreamInterface* stream,
-                          TiffDirectory* raw_processing_ifd) {
+bool GetRawProcessingIfd(const TagSet& desired_tags,
+                         const TiffDirectory& makernote_ifd,
+                         const std::uint32_t makernote_offset,
+                         const Endian endian, StreamInterface* stream,
+                         TiffDirectory* raw_processing_ifd) {
   std::uint32_t raw_processing_offset;
   std::uint32_t raw_processing_length;
   if (!makernote_ifd.GetOffsetAndLength(
           kOlymTagRawProcessing, tiff_directory::TIFF_IFD,
           &raw_processing_offset, &raw_processing_length)) {
-    return kUnsupported;
+    return false;
   }
 
   std::uint32_t next_ifd_offset;
   if (!Get32u(stream, raw_processing_offset, endian, &raw_processing_offset)) {
-    return kFail;
+    return false;
   }
 
   return ParseDirectory(
@@ -219,28 +225,25 @@
 
 // Retrieves the preview image offset and length from the camera settings and
 // the 'full_width' and 'full_height' from the raw processing ifd in 'stream'.
-// Returns kUnsupported if the camera settings are missing, since it is not able
-// to get the preview data.
-Error GetOlympusPreviewImage(StreamInterface* stream,
-                             PreviewImageData* preview_image_data) {
+// Returns false if anything is wrong.
+bool GetOlympusPreviewImage(StreamInterface* stream,
+                            PreviewImageData* preview_image_data) {
   Endian endian;
   if (!GetEndianness(0 /* tiff offset */, stream, &endian)) {
-    return kFail;
+    return false;
   }
 
   TiffDirectory exif_ifd(endian);
-  Error error = GetExifIfd(endian, stream, &exif_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetExifIfd(endian, stream, &exif_ifd)) {
+    return false;
   }
 
   std::uint32_t makernote_offset;
   TiffDirectory makernote_ifd(endian);
   const std::uint32_t kSkipMakernoteStart = 12;
-  error = GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
-                          &makernote_offset, &makernote_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
+                       &makernote_offset, &makernote_ifd)) {
+    return false;
   }
 
   const std::uint32_t kThumbnailTag = 0x0100;
@@ -249,41 +252,33 @@
             kThumbnailTag, tiff_directory::TIFF_TYPE_UNDEFINED,
             &preview_image_data->thumbnail.offset,
             &preview_image_data->thumbnail.length)) {
-      return kFail;
+      return false;
     }
-    // TODO: remove the old vars.
-    preview_image_data->thumbnail_offset = preview_image_data->thumbnail.offset;
-    preview_image_data->thumbnail_length = preview_image_data->thumbnail.length;
   }
 
   TiffDirectory camera_settings_ifd(endian);
-  error = GetCameraSettingsIfd(makernote_ifd, makernote_offset, endian, stream,
-                               &camera_settings_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetCameraSettingsIfd(makernote_ifd, makernote_offset, endian, stream,
+                            &camera_settings_ifd)) {
+    return false;
   }
 
   const std::uint32_t kPreviewOffset = 0x0101;
   const std::uint32_t kPreviewLength = 0x0102;
   if (!camera_settings_ifd.Has(kPreviewOffset) ||
       !camera_settings_ifd.Has(kPreviewLength)) {
-    return kUnsupported;
+    return false;
   }
 
   camera_settings_ifd.Get(kPreviewOffset, &preview_image_data->preview.offset);
   preview_image_data->preview.offset += makernote_offset;
   camera_settings_ifd.Get(kPreviewLength, &preview_image_data->preview.length);
-  // TODO: remove the old vars.
-  preview_image_data->preview_offset = preview_image_data->preview.offset;
-  preview_image_data->preview_length = preview_image_data->preview.length;
 
   // Get the crop size from the raw processing ifd.
   TiffDirectory raw_processing_ifd(endian);
-  error = GetRawProcessingIfd({kOlymTagAspectFrame}, makernote_ifd,
-                              makernote_offset, endian, stream,
-                              &raw_processing_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetRawProcessingIfd({kOlymTagAspectFrame}, makernote_ifd,
+                           makernote_offset, endian, stream,
+                           &raw_processing_ifd)) {
+    return false;
   }
 
   if (raw_processing_ifd.Has(kOlymTagAspectFrame)) {
@@ -300,40 +295,51 @@
     }
   }
 
-  return kOk;
+  return true;
 }
 
-Error PefGetColorSpace(StreamInterface* stream,
-                       PreviewImageData* preview_image_data) {
+bool PefGetColorSpace(StreamInterface* stream,
+                      PreviewImageData* preview_image_data) {
   Endian endian;
   if (!GetEndianness(0 /* tiff offset */, stream, &endian)) {
-    return kFail;
+    return false;
   }
 
   TiffDirectory exif_ifd(endian);
-  Error error = GetExifIfd(endian, stream, &exif_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetExifIfd(endian, stream, &exif_ifd)) {
+    return false;
   }
 
   std::uint32_t makernote_offset;
   TiffDirectory makernote_ifd(endian);
   const std::uint32_t kSkipMakernoteStart = 6;
-  error = GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
-                          &makernote_offset, &makernote_ifd);
-  if (error != kOk) {
-    return error;
+  if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream,
+                       &makernote_offset, &makernote_ifd)) {
+    return false;
   }
   if (makernote_ifd.Has(kPentaxTagColorSpace)) {
     std::uint32_t color_space;
     if (!makernote_ifd.Get(kPentaxTagColorSpace, &color_space)) {
-      return kFail;
+      return false;
     }
     preview_image_data->color_space = color_space == 0
                                           ? PreviewImageData::kSrgb
                                           : PreviewImageData::kAdobeRgb;
   }
-  return kOk;
+  return true;
+}
+
+bool RafGetOrientation(StreamInterface* stream, std::uint32_t* orientation) {
+  // Parse the Fuji RAW header to get the offset and length of the preview
+  // image, which contains the Exif information.
+  const Endian endian = tiff_directory::kBigEndian;
+  std::uint32_t preview_offset = 0;
+  if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset)) {
+    return false;
+  }
+
+  const std::uint32_t exif_offset = preview_offset + 12;
+  return GetExifOrientation(stream, exif_offset, orientation);
 }
 
 // Parses the Fuji Cfa header for the image width and height.
@@ -381,8 +387,11 @@
   GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data);
 
   const std::uint32_t kNumberOfIfds = 1;
-  return GetPreviewData(extended_tags, kNumberOfIfds, stream,
-                        preview_image_data);
+  if (GetPreviewData(extended_tags, kNumberOfIfds, stream,
+                     preview_image_data)) {
+    return kOk;
+  }
+  return kFail;
 }
 
 Error Cr2GetPreviewData(StreamInterface* stream,
@@ -393,22 +402,27 @@
   GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data);
 
   const std::uint32_t kNumberOfIfds = 1;
-  return GetPreviewData(extended_tags, kNumberOfIfds, stream,
-                        preview_image_data);
+  if (GetPreviewData(extended_tags, kNumberOfIfds, stream,
+                     preview_image_data)) {
+    return kOk;
+  }
+  return kFail;
 }
 
 Error DngGetPreviewData(StreamInterface* stream,
                         PreviewImageData* preview_image_data) {
+  // Some thumbnails from DngCreator are larger than the specified 256 pixel.
+  const int kDngThumbnailMaxDimension = 512;
+
   const TagSet extended_tags = {
-      kExifTagDefaultCropSize, kTiffTagCompression,  kTiffTagPhotometric,
+      kExifTagDefaultCropSize, kTiffTagImageWidth,   kTiffTagImageLength,
       kTiffTagStripByteCounts, kTiffTagStripOffsets, kTiffTagSubIfd};
 
   TiffContent tiff_content;
   const std::uint32_t kNumberOfIfds = 4;
-  Error error = GetPreviewData(extended_tags, 0, kNumberOfIfds, stream,
-                               &tiff_content, preview_image_data);
-  if (error != kOk) {
-    return error;
+  if (!GetPreviewData(extended_tags, 0, kNumberOfIfds, stream, &tiff_content,
+                      preview_image_data)) {
+    return kFail;
   }
 
   // Find the jpeg compressed thumbnail and preview image.
@@ -417,24 +431,25 @@
 
   // Search for images in IFD0
   Image temp_image;
-  if (GetImageFromIfd(tiff_content.tiff_directory[0], stream, &temp_image)) {
-    if (IsThumbnail(temp_image)) {
+  if (GetImageData(tiff_content.tiff_directory[0], stream, &temp_image)) {
+    if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) {
       thumbnail = temp_image;
-    } else {
+    } else if (temp_image.format == Image::kJpegCompressed) {
       preview = temp_image;
     }
   }
 
   // Search for images in other IFDs
   for (const auto& ifd : tiff_content.tiff_directory[0].GetSubDirectories()) {
-    if (GetImageFromIfd(ifd, stream, &temp_image)) {
+    if (GetImageData(ifd, stream, &temp_image)) {
       // Try to find the largest thumbnail/preview.
-      if (IsThumbnail(temp_image)) {
+      if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) {
         if (temp_image > thumbnail) {
           thumbnail = temp_image;
         }
       } else {
-        if (temp_image > preview) {
+        if (temp_image > preview &&
+            temp_image.format == Image::kJpegCompressed) {
           preview = temp_image;
         }
       }
@@ -442,33 +457,27 @@
   }
   preview_image_data->preview = preview;
   preview_image_data->thumbnail = thumbnail;
-  // TODO: remove the old vars.
-  preview_image_data->preview_length = preview.length;
-  preview_image_data->preview_offset = preview.offset;
-  preview_image_data->thumbnail_length = thumbnail.length;
-  preview_image_data->thumbnail_offset = thumbnail.offset;
 
   return kOk;
 }
 
 Error NefGetPreviewData(StreamInterface* stream,
                         PreviewImageData* preview_image_data) {
-  const TagSet extended_tags = {kTiffTagImageWidth, kTiffTagImageLength,
-                                kTiffTagJpegByteCount, kTiffTagJpegOffset,
+  const TagSet extended_tags = {kTiffTagImageWidth,      kTiffTagImageLength,
+                                kTiffTagJpegByteCount,   kTiffTagJpegOffset,
+                                kTiffTagStripByteCounts, kTiffTagStripOffsets,
                                 kTiffTagSubIfd};
   const std::uint32_t kNumberOfIfds = 2;
-  Error error =
-      GetPreviewData(extended_tags, kNumberOfIfds, stream, preview_image_data);
-  if (error != kOk) {
-    return error;
+  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
+                      preview_image_data)) {
+    return kFail;
   }
 
-  PreviewImageData thumbnail_data;
-  GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data);
-  preview_image_data->thumbnail = thumbnail_data.thumbnail;
-  // TODO: remove the old vars.
-  preview_image_data->thumbnail_offset = thumbnail_data.thumbnail_offset;
-  preview_image_data->thumbnail_length = thumbnail_data.thumbnail_length;
+  if (preview_image_data->thumbnail.length == 0) {
+    PreviewImageData thumbnail_data;
+    GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data);
+    preview_image_data->thumbnail = thumbnail_data.thumbnail;
+  }
 
   // The Nikon RAW data provides the dimensions of the sensor image, which are
   // slightly larger than the dimensions of the preview image. In order to
@@ -476,13 +485,13 @@
   // size needs to be taken into account. Based on experiments the preview image
   // dimensions must be at least 90% of the sensor image dimensions to let it be
   // a full size preview image.
-  if (preview_image_data->preview_length > 0) {  // when preview image exists
+  if (preview_image_data->preview.length > 0) {  // when preview image exists
     const float kEpsilon = 0.9f;
 
     std::uint16_t width;
     std::uint16_t height;
-    if (!GetPreviewDimensions(preview_image_data->preview_offset, stream,
-                              &width, &height) ||
+    if (!GetJpegDimensions(preview_image_data->preview.offset, stream, &width,
+                           &height) ||
         preview_image_data->full_width == 0 ||
         preview_image_data->full_height == 0) {
       return kUnsupported;
@@ -503,13 +512,12 @@
 
 Error OrfGetPreviewData(StreamInterface* stream,
                         PreviewImageData* preview_image_data) {
-  // Omit kUnsupported, because the exif data does not contain any preview
-  // image.
-  if (GetExifData(0, stream, preview_image_data) == kFail) {
+  if (!GetExifData(0, stream, preview_image_data)) {
     return kFail;
   }
-
-  return GetOlympusPreviewImage(stream, preview_image_data);
+  // Omit errors, because some images do not contain any preview data.
+  GetOlympusPreviewImage(stream, preview_image_data);
+  return kOk;
 }
 
 Error PefGetPreviewData(StreamInterface* stream,
@@ -518,23 +526,15 @@
                                 kTiffTagJpegByteCount, kTiffTagJpegOffset,
                                 kTiffTagSubIfd};
   const std::uint32_t kNumberOfIfds = 3;
-  Error error =
-      GetPreviewData(extended_tags, kNumberOfIfds, stream, preview_image_data);
-  if (error != kOk) {
-    return error;
-  }
-
-  error = PefGetColorSpace(stream, preview_image_data);
-  if (error != kOk) {
-    return error;
+  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
+                      preview_image_data) ||
+      !PefGetColorSpace(stream, preview_image_data)) {
+    return kFail;
   }
 
   PreviewImageData thumbnail_data;
   GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data);
   preview_image_data->thumbnail = thumbnail_data.thumbnail;
-  // TODO: remove the old vars.
-  preview_image_data->thumbnail_offset = thumbnail_data.thumbnail_offset;
-  preview_image_data->thumbnail_length = thumbnail_data.thumbnail_length;
 
   return kOk;
 }
@@ -546,8 +546,8 @@
   const Endian endian = tiff_directory::kBigEndian;
   std::uint32_t preview_offset = 0;
   std::uint32_t preview_length = 0;
-  if (!Get32u(stream, 84 /* preview offset */, endian, &preview_offset) ||
-      !Get32u(stream, 88 /* preview length */, endian, &preview_length)) {
+  if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset) ||
+      !Get32u(stream, kRafOffsetToPreviewOffset + 4, endian, &preview_length)) {
     return kFail;
   }
 
@@ -557,26 +557,17 @@
   }
 
   if (preview_length > 0) {  // when preview image exists
-    // Parse the Exif information from the preview image. Omit kUnsupported,
-    // because the exif data does not contain any preview image.
+    // Parse the Exif information from the preview image.
     const std::uint32_t exif_offset = preview_offset + 12;
-    if (GetExifData(exif_offset, stream, preview_image_data) == kFail) {
+    if (!GetExifData(exif_offset, stream, preview_image_data)) {
       return kFail;
     }
   }
 
   // Merge the Exif data with the RAW data to form the preview_image_data.
-  // The preview offset and length extracted from the Exif data are actually
-  // the thumbnail offset and length.
-  preview_image_data->thumbnail = preview_image_data->preview;
   preview_image_data->thumbnail.offset += 160;  // Skip the cfa header.
   preview_image_data->preview.offset = preview_offset;
   preview_image_data->preview.length = preview_length;
-  // TODO: remove the old vars.
-  preview_image_data->thumbnail_offset = preview_image_data->thumbnail.offset;
-  preview_image_data->thumbnail_length = preview_image_data->thumbnail.length;
-  preview_image_data->preview_offset = preview_image_data->preview.offset;
-  preview_image_data->preview_length = preview_image_data->preview.length;
   return kOk;
 }
 
@@ -590,26 +581,17 @@
   // which contains the Exif information.
   const std::uint32_t kNumberOfIfds = 1;
   PreviewImageData preview_data;
-  Error error =
-      GetPreviewData(extended_tags, kNumberOfIfds, stream, &preview_data);
-  if (error != kOk) {
-    return error;
+  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, &preview_data)) {
+    return kFail;
   }
 
-  if (preview_data.preview_length > 0) {  // when preview image exists
-    // Parse the Exif information from the preview image. Omit kUnsupported,
-    // because the exif data does not contain any preview image.
-    const std::uint32_t exif_offset = preview_data.preview_offset + 12;
-    if (GetExifData(exif_offset, stream, preview_image_data) == kFail) {
+  if (preview_data.preview.length > 0) {  // when preview image exists
+    // Parse the Exif information from the preview image.
+    const std::uint32_t exif_offset = preview_data.preview.offset + 12;
+    if (!GetExifData(exif_offset, stream, preview_image_data)) {
       return kFail;
     }
-    // The preview offset and length extracted from the Exif data are actually
-    // the thumbnail offset and length.
-    preview_image_data->thumbnail = preview_image_data->preview;
     preview_image_data->thumbnail.offset += exif_offset;
-    // TODO: remove old vars.
-    preview_image_data->thumbnail_offset = preview_image_data->thumbnail.offset;
-    preview_image_data->thumbnail_length = preview_image_data->thumbnail.length;
   }
 
   // Merge the Exif data with the RAW data to form the preview_image_data.
@@ -617,9 +599,6 @@
   preview_image_data->iso = preview_data.iso;
   preview_image_data->full_width = preview_data.full_width;
   preview_image_data->full_height = preview_data.full_height;
-  // TODO: remove old vars.
-  preview_image_data->preview_offset = preview_image_data->preview.offset;
-  preview_image_data->preview_length = preview_image_data->preview.length;
 
   return kOk;
 }
@@ -632,8 +611,11 @@
                                 kTiffTagJpegByteCount, kTiffTagJpegOffset,
                                 kTiffTagSubIfd};
   const std::uint32_t kNumberOfIfds = 1;
-  return GetPreviewData(extended_tags, kNumberOfIfds, stream,
-                        preview_image_data);
+  if (!GetPreviewData(extended_tags, kNumberOfIfds, stream,
+                      preview_image_data)) {
+    return kFail;
+  }
+  return kOk;
 }
 
 }  // namespace
@@ -698,6 +680,38 @@
   }
 }
 
+bool GetDngInformation(StreamInterface* data, std::uint32_t* width,
+                       std::uint32_t* height,
+                       std::vector<std::uint32_t>* cfa_pattern_dim) {
+  // If IFD0 contains already the full dimensions we do not parse into the sub
+  // IFD.
+  if (!GetDngInformation({}, data, width, height, cfa_pattern_dim)) {
+    return GetDngInformation({kTiffTagSubIfd}, data, width, height,
+                             cfa_pattern_dim);
+  }
+  return true;
+}
+
+bool GetOrientation(StreamInterface* data, std::uint32_t* orientation) {
+  using image_type_recognition::GetNumberOfBytesForIsOfType;
+  using image_type_recognition::IsOfType;
+
+  std::vector<std::uint8_t> file_header(
+      GetNumberOfBytesForIsOfType(image_type_recognition::kRafImage));
+  if (data->GetData(0, file_header.size(), file_header.data()) != kOk) {
+    return false;
+  }
+
+  // For RAF files a special routine is necessary to get orientation. For others
+  // the general approach is sufficient.
+  if (IsOfType(RangeCheckedBytePtr(file_header.data(), file_header.size()),
+               image_type_recognition::kRafImage)) {
+    return RafGetOrientation(data, orientation);
+  } else {
+    return GetExifOrientation(data, 0 /* offset */, orientation);
+  }
+}
+
 std::vector<std::string> SupportedExtensions() {
   return {"ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "PEF", "RAF", "RW2", "SRW"};
 }
diff --git a/src/piex.h b/src/piex.h
index 13c190f..3225421 100644
--- a/src/piex.h
+++ b/src/piex.h
@@ -16,7 +16,6 @@
 //
 // The purpose of the preview-image-extractor (piex) is to find and extract the
 // largest JPEG compressed preview image contained in a RAW file.
-// For details: go/piex
 //
 // Even for unsupported RAW files we want to provide high quality images using a
 // dedicated, small and portable library. That is possible by taking the preview
@@ -74,6 +73,16 @@
 Error GetPreviewImageData(StreamInterface* data,
                           PreviewImageData* preview_image_data);
 
+// Returns true if the full width and height and the mosaic pattern dimension of
+// a DNG image could be obtained. False otherwise.
+bool GetDngInformation(StreamInterface* data, std::uint32_t* width,
+                       std::uint32_t* height,
+                       std::vector<std::uint32_t>* cfa_pattern_dim);
+
+// Returns true if Exif orientation for the image can be obtained. False
+// otherwise.
+bool GetOrientation(StreamInterface* data, std::uint32_t* orientation);
+
 // Returns a vector of upper case file extensions, which are used as a first
 // step to quickly guess a supported file format.
 std::vector<std::string> SupportedExtensions();
diff --git a/src/piex_types.h b/src/piex_types.h
index b4824fc..4fdb7c2 100644
--- a/src/piex_types.h
+++ b/src/piex_types.h
@@ -36,6 +36,7 @@
 struct Image {
   enum Format {
     kJpegCompressed,
+    kUncompressedRgb,
   };
 
   std::uint16_t width = 0;
@@ -80,12 +81,6 @@
   // correctly. A thumbnail is typically 160x120 pixel small and usually
   // has black borders at the top and bottom. If length is 0 the image could not
   // be extracted.
-  // Note: Deprecate the offset, length versions. Use these Image structs
-  // instead.
-  std::uint32_t preview_offset = 0;
-  std::uint32_t preview_length = 0;
-  std::uint32_t thumbnail_offset = 0;
-  std::uint32_t thumbnail_length = 0;
   Image preview;
   Image thumbnail;
 
diff --git a/src/tiff_parser.cc b/src/tiff_parser.cc
index 618ac80..697e320 100644
--- a/src/tiff_parser.cc
+++ b/src/tiff_parser.cc
@@ -17,6 +17,8 @@
 #include "src/tiff_parser.h"
 
 #include <cstring>
+#include <limits>
+#include <numeric>
 
 #include "src/tiff_directory/tiff_directory.h"
 
@@ -38,54 +40,17 @@
 const std::uint32_t kStartOfImage = 0xFFD8;
 const std::uint32_t kStartOfScan = 0xFFDA;
 
-// Reads the width and height of the full resolution image. The tag groups are
-// exclusive.
-bool GetFullDimension(const TiffDirectory& tiff_directory, std::uint32_t* width,
-                      std::uint32_t* height) {
-  if (tiff_directory.Has(kExifTagWidth) && tiff_directory.Has(kExifTagHeight)) {
-    if (!tiff_directory.Get(kExifTagWidth, width) ||
-        !tiff_directory.Get(kExifTagHeight, height)) {
-      return false;
-    }
-  } else if (tiff_directory.Has(kTiffTagImageWidth) &&
-             tiff_directory.Has(kTiffTagImageLength)) {
-    if (!tiff_directory.Get(kTiffTagImageWidth, width) ||
-        !tiff_directory.Get(kTiffTagImageLength, height)) {
-      return false;
-    }
-  } else if (tiff_directory.Has(kPanaTagTopBorder) &&
-             tiff_directory.Has(kPanaTagLeftBorder) &&
-             tiff_directory.Has(kPanaTagBottomBorder) &&
-             tiff_directory.Has(kPanaTagRightBorder)) {
-    std::uint32_t left;
-    std::uint32_t right;
-    std::uint32_t top;
-    std::uint32_t bottom;
-    if (tiff_directory.Get(kPanaTagLeftBorder, &left) &&
-        tiff_directory.Get(kPanaTagRightBorder, &right) &&
-        tiff_directory.Get(kPanaTagTopBorder, &top) &&
-        tiff_directory.Get(kPanaTagBottomBorder, &bottom) && bottom > top &&
-        right > left) {
-      *height = bottom - top;
-      *width = right - left;
-    } else {
-      return false;
-    }
-  } else if (tiff_directory.Has(kExifTagDefaultCropSize)) {
-    std::vector<std::uint32_t> crop(2);
-    std::vector<Rational> crop_rational(2);
-    if (tiff_directory.Get(kExifTagDefaultCropSize, &crop)) {
-      *width = crop[0];
-      *height = crop[1];
-    } else if (tiff_directory.Get(kExifTagDefaultCropSize, &crop_rational) &&
-               crop_rational[0].denominator != 0 &&
-               crop_rational[1].denominator != 0) {
-      *width = crop_rational[0].numerator / crop_rational[0].denominator;
-      *height = crop_rational[1].numerator / crop_rational[1].denominator;
-    } else {
-      return false;
-    }
+bool GetFullDimension16(const TiffDirectory& tiff_directory,
+                        std::uint16_t* width, std::uint16_t* height) {
+  std::uint32_t tmp_width = 0;
+  std::uint32_t tmp_height = 0;
+  if (!GetFullDimension32(tiff_directory, &tmp_width, &tmp_height) ||
+      tmp_width > std::numeric_limits<std::uint16_t>::max() ||
+      tmp_height > std::numeric_limits<std::uint16_t>::max()) {
+    return false;
   }
+  *width = static_cast<std::uint16_t>(tmp_width);
+  *height = static_cast<std::uint16_t>(tmp_height);
   return true;
 }
 
@@ -160,45 +125,34 @@
   }
 }
 
-Error FillPreviewImageData(const TiffDirectory& tiff_directory,
-                           PreviewImageData* preview_image_data) {
-  bool success = true;
-  // Get preview_offset and preview_length
-  if (tiff_directory.Has(kTiffTagStripOffsets) &&
-      tiff_directory.Has(kTiffTagStripByteCounts)) {
-    std::vector<std::uint32_t> strip_offsets;
-    std::vector<std::uint32_t> strip_byte_counts;
-    if (!tiff_directory.Get(kTiffTagStripOffsets, &strip_offsets) ||
-        !tiff_directory.Get(kTiffTagStripByteCounts, &strip_byte_counts)) {
-      return kFail;
+void GetImageSize(const TiffDirectory& tiff_directory, StreamInterface* stream,
+                  Image* image) {
+  switch (image->format) {
+    case Image::kUncompressedRgb: {
+      GetFullDimension16(tiff_directory, &image->width, &image->height);
+      break;
     }
-    if (strip_offsets.size() == 1 && strip_byte_counts.size() == 1) {
-      preview_image_data->preview.offset = strip_offsets[0];
-      preview_image_data->preview.length = strip_byte_counts[0];
-      // TODO: remove old vars.
-      preview_image_data->preview_offset = strip_offsets[0];
-      preview_image_data->preview_length = strip_byte_counts[0];
+    case Image::kJpegCompressed: {
+      GetJpegDimensions(image->offset, stream, &image->width, &image->height);
+      break;
     }
-  } else if (tiff_directory.Has(kTiffTagJpegOffset) &&
-             tiff_directory.Has(kTiffTagJpegByteCount)) {
-    success &= tiff_directory.Get(kTiffTagJpegOffset,
-                                  &preview_image_data->preview.offset);
-    success &= tiff_directory.Get(kTiffTagJpegByteCount,
-                                  &preview_image_data->preview.length);
-    // TODO: remove old vars.
-    preview_image_data->preview_offset = preview_image_data->preview.offset;
-    preview_image_data->preview_length = preview_image_data->preview.length;
+    default: { return; }
+  }
+}
 
-  } else if (tiff_directory.Has(kPanaTagJpegImage)) {
-    if (!tiff_directory.GetOffsetAndLength(
-            kPanaTagJpegImage, TIFF_TYPE_UNDEFINED,
-            &preview_image_data->preview.offset,
-            &preview_image_data->preview.length)) {
-      return kFail;
+bool FillPreviewImageData(const TiffDirectory& tiff_directory,
+                          StreamInterface* stream,
+                          PreviewImageData* preview_image_data) {
+  bool success = true;
+  // Get preview or thumbnail. The code assumes that only thumbnails can be
+  // uncompressed. Preview images are always JPEG compressed.
+  Image image;
+  if (GetImageData(tiff_directory, stream, &image)) {
+    if (IsThumbnail(image)) {
+      preview_image_data->thumbnail = image;
+    } else if (image.format == Image::kJpegCompressed) {
+      preview_image_data->preview = image;
     }
-    // TODO: remove old vars.
-    preview_image_data->preview_offset = preview_image_data->preview.offset;
-    preview_image_data->preview_length = preview_image_data->preview.length;
   }
 
   // Get exif_orientation if it was not set already.
@@ -219,8 +173,8 @@
     }
   }
 
-  success &= GetFullDimension(tiff_directory, &preview_image_data->full_width,
-                              &preview_image_data->full_height);
+  success &= GetFullDimension32(tiff_directory, &preview_image_data->full_width,
+                                &preview_image_data->full_height);
 
   if (tiff_directory.Has(kTiffTagMake)) {
     success &= tiff_directory.Get(kTiffTagMake, &preview_image_data->maker);
@@ -265,11 +219,7 @@
                            &preview_image_data->focal_length);
   }
 
-  if (!success) {
-    return kFail;
-  }
-
-  return kOk;
+  return success;
 }
 
 const TiffDirectory* FindFirstTagInIfds(const TiffDirectory::Tag& tag,
@@ -289,12 +239,28 @@
   return NULL;
 }
 
+// Return true if all data blocks are ordered one after the other without gaps.
+bool OffsetsAreConsecutive(
+    const std::vector<std::uint32_t>& strip_offsets,
+    const std::vector<std::uint32_t>& strip_byte_counts) {
+  if (strip_offsets.size() != strip_byte_counts.size() ||
+      strip_offsets.empty()) {
+    return false;
+  }
+
+  for (size_t i = 0; i < strip_offsets.size() - 1; ++i) {
+    if (strip_offsets[i] + strip_byte_counts[i] != strip_offsets[i + 1]) {
+      return false;
+    }
+  }
+  return true;
+}
+
 // Gets the SubIfd content.
-void ParseSubIfds(const std::uint32_t tiff_offset, const TagSet& desired_tags,
+bool ParseSubIfds(const std::uint32_t tiff_offset, const TagSet& desired_tags,
                   const std::uint32_t max_number_ifds, const Endian endian,
-                  StreamInterface* stream, TiffDirectory* tiff_ifd,
-                  Error* error) {
-  if (*error == kOk && tiff_ifd->Has(kTiffTagSubIfd)) {
+                  StreamInterface* stream, TiffDirectory* tiff_ifd) {
+  if (tiff_ifd->Has(kTiffTagSubIfd)) {
     std::uint32_t offset = 0;
     std::uint32_t length = 0;
     tiff_ifd->GetOffsetAndLength(kTiffTagSubIfd, TIFF_TYPE_LONG, &offset,
@@ -303,21 +269,20 @@
     for (std::uint32_t j = 0; j < length && j < max_number_ifds; ++j) {
       std::uint32_t sub_offset;
       if (!Get32u(stream, offset + 4 * j, endian, &sub_offset)) {
-        *error = kFail;
-        return;
+        return false;
       }
 
       std::uint32_t next_ifd_offset;
       TiffDirectory sub_ifd(static_cast<Endian>(endian));
-      *error = ParseDirectory(tiff_offset, sub_offset, endian, desired_tags,
-                              stream, &sub_ifd, &next_ifd_offset);
-      if (*error != kOk) {
-        return;
+      if (!ParseDirectory(tiff_offset, sub_offset, endian, desired_tags, stream,
+                          &sub_ifd, &next_ifd_offset)) {
+        return false;
       }
 
       tiff_ifd->AddSubDirectory(sub_ifd);
     }
   }
+  return true;
 }
 
 }  // namespace
@@ -397,9 +362,72 @@
   }
 }
 
-bool GetPreviewDimensions(const std::uint32_t jpeg_offset,
-                          StreamInterface* stream, std::uint16_t* width,
-                          std::uint16_t* height) {
+bool GetImageData(const TiffDirectory& tiff_directory, StreamInterface* stream,
+                  Image* image) {
+  std::uint32_t length = 0;
+  std::uint32_t offset = 0;
+
+  if (tiff_directory.Has(kTiffTagJpegOffset) &&
+      tiff_directory.Has(kTiffTagJpegByteCount)) {
+    if (!tiff_directory.Get(kTiffTagJpegOffset, &offset) ||
+        !tiff_directory.Get(kTiffTagJpegByteCount, &length)) {
+      return false;
+    }
+    image->format = Image::kJpegCompressed;
+  } else if (tiff_directory.Has(kTiffTagStripOffsets) &&
+             tiff_directory.Has(kTiffTagStripByteCounts)) {
+    std::vector<std::uint32_t> strip_offsets;
+    std::vector<std::uint32_t> strip_byte_counts;
+    if (!tiff_directory.Get(kTiffTagStripOffsets, &strip_offsets) ||
+        !tiff_directory.Get(kTiffTagStripByteCounts, &strip_byte_counts)) {
+      return false;
+    }
+
+    std::uint32_t compression = 0;
+    if (!OffsetsAreConsecutive(strip_offsets, strip_byte_counts) ||
+        !tiff_directory.Get(kTiffTagCompression, &compression)) {
+      return false;
+    }
+
+    std::uint32_t photometric_interpretation = 0;
+    if (tiff_directory.Get(kTiffTagPhotometric, &photometric_interpretation) &&
+        photometric_interpretation != 2 /* RGB */ &&
+        photometric_interpretation != 6 /* YCbCr */) {
+      return false;
+    }
+
+    switch (compression) {
+      case 1: /*uncompressed*/
+        image->format = Image::kUncompressedRgb;
+        break;
+      case 6: /* JPEG(old) */
+      case 7: /* JPEG */
+        image->format = Image::kJpegCompressed;
+        break;
+      default:
+        return false;
+    }
+    length = static_cast<std::uint32_t>(
+        std::accumulate(strip_byte_counts.begin(), strip_byte_counts.end(), 0));
+    offset = strip_offsets[0];
+  } else if (tiff_directory.Has(kPanaTagJpegImage)) {
+    if (!tiff_directory.GetOffsetAndLength(
+            kPanaTagJpegImage, TIFF_TYPE_UNDEFINED, &offset, &length)) {
+      return false;
+    }
+    image->format = Image::kJpegCompressed;
+  } else {
+    return false;
+  }
+
+  image->length = length;
+  image->offset = offset;
+  GetImageSize(tiff_directory, stream, image);
+  return true;
+}
+
+bool GetJpegDimensions(const std::uint32_t jpeg_offset, StreamInterface* stream,
+                       std::uint16_t* width, std::uint16_t* height) {
   const Endian endian = kBigEndian;
   std::uint32_t offset = jpeg_offset;
   std::uint16_t segment;
@@ -432,14 +460,18 @@
   return false;
 }
 
-Error ParseDirectory(const std::uint32_t tiff_offset,
-                     const std::uint32_t ifd_offset, const Endian endian,
-                     const TagSet& desired_tags, StreamInterface* stream,
-                     TiffDirectory* tiff_directory,
-                     std::uint32_t* next_ifd_offset) {
+bool IsThumbnail(const Image& image, const int max_dimension) {
+  return image.width <= max_dimension && image.height <= max_dimension;
+}
+
+bool ParseDirectory(const std::uint32_t tiff_offset,
+                    const std::uint32_t ifd_offset, const Endian endian,
+                    const TagSet& desired_tags, StreamInterface* stream,
+                    TiffDirectory* tiff_directory,
+                    std::uint32_t* next_ifd_offset) {
   std::uint16_t number_of_entries;
   if (!Get16u(stream, ifd_offset, endian, &number_of_entries)) {
-    return kFail;
+    return false;
   }
 
   for (std::uint32_t i = 0;
@@ -455,14 +487,14 @@
         continue;
       }
     } else {
-      return kFail;
+      return false;
     }
 
     const size_t type_size = SizeOfType(type, nullptr /* no error */);
 
     // Check that type_size * number_of_elements does not exceed UINT32_MAX.
     if (type_size != 0 && number_of_elements > UINT32_MAX / type_size) {
-      return kFail;
+      return false;
     }
     const size_t byte_count =
         type_size * static_cast<size_t>(number_of_elements);
@@ -482,17 +514,93 @@
     const std::vector<std::uint8_t> data =
         GetData(value_offset, byte_count, stream, &error);
     if (error != kOk) {
-      return error;
+      return false;
     }
     tiff_directory->AddEntry(tag, type, number_of_elements, value_offset, data);
   }
 
-  if (Get32u(stream, ifd_offset + 2u + number_of_entries * 12u, endian,
-             next_ifd_offset)) {
-    return kOk;
-  } else {
-    return kFail;
+  return Get32u(stream, ifd_offset + 2u + number_of_entries * 12u, endian,
+                next_ifd_offset);
+}
+
+bool GetExifOrientation(StreamInterface* stream, const std::uint32_t offset,
+                        std::uint32_t* orientation) {
+  const TagSet kOrientationTagSet = {kTiffTagOrientation};
+  const std::uint32_t kNumberOfIfds = 1;
+
+  TiffContent tiff_content;
+  if (!TiffParser(stream, offset)
+           .Parse(kOrientationTagSet, kNumberOfIfds, &tiff_content)) {
+    return false;
   }
+
+  for (const auto& tiff_directory : tiff_content.tiff_directory) {
+    if (tiff_directory.Has(kTiffTagOrientation) &&
+        tiff_directory.Get(kTiffTagOrientation, orientation)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool GetFullDimension32(const TiffDirectory& tiff_directory,
+                        std::uint32_t* width, std::uint32_t* height) {
+  // The sub file type needs to be 0 (main image) to contain a valid full
+  // dimensions. This is important in particular for DNG.
+  if (tiff_directory.Has(kTiffTagSubFileType)) {
+    std::uint32_t sub_file_type;
+    if (!tiff_directory.Get(kTiffTagSubFileType, &sub_file_type) ||
+        sub_file_type != 0) {
+      return false;
+    }
+  }
+
+  if (tiff_directory.Has(kExifTagWidth) && tiff_directory.Has(kExifTagHeight)) {
+    if (!tiff_directory.Get(kExifTagWidth, width) ||
+        !tiff_directory.Get(kExifTagHeight, height)) {
+      return false;
+    }
+  } else if (tiff_directory.Has(kTiffTagImageWidth) &&
+             tiff_directory.Has(kTiffTagImageLength)) {
+    if (!tiff_directory.Get(kTiffTagImageWidth, width) ||
+        !tiff_directory.Get(kTiffTagImageLength, height)) {
+      return false;
+    }
+  } else if (tiff_directory.Has(kPanaTagTopBorder) &&
+             tiff_directory.Has(kPanaTagLeftBorder) &&
+             tiff_directory.Has(kPanaTagBottomBorder) &&
+             tiff_directory.Has(kPanaTagRightBorder)) {
+    std::uint32_t left;
+    std::uint32_t right;
+    std::uint32_t top;
+    std::uint32_t bottom;
+    if (tiff_directory.Get(kPanaTagLeftBorder, &left) &&
+        tiff_directory.Get(kPanaTagRightBorder, &right) &&
+        tiff_directory.Get(kPanaTagTopBorder, &top) &&
+        tiff_directory.Get(kPanaTagBottomBorder, &bottom) && bottom > top &&
+        right > left) {
+      *height = bottom - top;
+      *width = right - left;
+    } else {
+      return false;
+    }
+  } else if (tiff_directory.Has(kExifTagDefaultCropSize)) {
+    std::vector<std::uint32_t> crop(2);
+    std::vector<Rational> crop_rational(2);
+    if (tiff_directory.Get(kExifTagDefaultCropSize, &crop)) {
+      *width = crop[0];
+      *height = crop[1];
+    } else if (tiff_directory.Get(kExifTagDefaultCropSize, &crop_rational) &&
+               crop_rational[0].denominator != 0 &&
+               crop_rational[1].denominator != 0) {
+      *width = crop_rational[0].numerator / crop_rational[0].denominator;
+      *height = crop_rational[1].numerator / crop_rational[1].denominator;
+    } else {
+      return false;
+    }
+  }
+  return true;
 }
 
 TiffParser::TiffParser(StreamInterface* stream) : stream_(stream) {}
@@ -500,34 +608,35 @@
 TiffParser::TiffParser(StreamInterface* stream, const std::uint32_t offset)
     : stream_(stream), tiff_offset_(offset) {}
 
-Error TiffParser::GetPreviewImageData(const TiffContent& tiff_content,
-                                      PreviewImageData* preview_image_data) {
-  Error error = kOk;
+bool TiffParser::GetPreviewImageData(const TiffContent& tiff_content,
+                                     PreviewImageData* preview_image_data) {
+  bool success = true;
   for (const auto& tiff_directory : tiff_content.tiff_directory) {
-    error = FillPreviewImageData(tiff_directory, preview_image_data);
-    if (error == kOk && tiff_directory.Has(kTiffTagExifIfd) &&
+    success = FillPreviewImageData(tiff_directory, stream_, preview_image_data);
+    if (success && tiff_directory.Has(kTiffTagExifIfd) &&
         tiff_content.exif_directory) {
-      error = FillPreviewImageData(*tiff_content.exif_directory,
-                                   preview_image_data);
+      success = FillPreviewImageData(*tiff_content.exif_directory, stream_,
+                                     preview_image_data);
     }
-    if (error == kOk && tiff_directory.Has(kExifTagGps) &&
+    if (success && tiff_directory.Has(kExifTagGps) &&
         tiff_content.gps_directory) {
       FillGpsPreviewImageData(*tiff_content.gps_directory, preview_image_data);
     }
     for (const auto& sub_directory : tiff_directory.GetSubDirectories()) {
-      if (error == kOk) {
-        error = FillPreviewImageData(sub_directory, preview_image_data);
+      if (success) {
+        success =
+            FillPreviewImageData(sub_directory, stream_, preview_image_data);
       }
     }
   }
-  return error;
+  return success;
 }
 
-Error TiffParser::Parse(const TagSet& desired_tags,
-                        const std::uint16_t max_number_ifds,
-                        TiffContent* tiff_content) {
+bool TiffParser::Parse(const TagSet& desired_tags,
+                       const std::uint16_t max_number_ifds,
+                       TiffContent* tiff_content) {
   if (!tiff_content->tiff_directory.empty()) {
-    return kFail;  // You shall call Parse() only once.
+    return false;  // You shall call Parse() only once.
   }
 
   const std::uint32_t kTiffIdentifierSize = 4;
@@ -535,13 +644,12 @@
   if (!GetEndianness(tiff_offset_, stream_, &endian_) ||
       !Get32u(stream_, tiff_offset_ + kTiffIdentifierSize, endian_,
               &offset_to_ifd)) {
-    return kFail;
+    return false;
   }
 
-  Error error = ParseIfd(tiff_offset_ + offset_to_ifd, desired_tags,
-                         max_number_ifds, &tiff_content->tiff_directory);
-  if (error != kOk) {
-    return error;
+  if (!ParseIfd(tiff_offset_ + offset_to_ifd, desired_tags, max_number_ifds,
+                &tiff_content->tiff_directory)) {
+    return false;
   }
 
   // Get the Exif data.
@@ -553,11 +661,10 @@
     if (tiff_ifd->Get(kTiffTagExifIfd, &offset)) {
       tiff_content->exif_directory.reset(new TiffDirectory(endian_));
       std::uint32_t next_ifd_offset;
-      error = ParseDirectory(
-          tiff_offset_, tiff_offset_ + offset, endian_, desired_tags, stream_,
-          tiff_content->exif_directory.get(), &next_ifd_offset);
-      if (error != kOk) {
-        return error;
+      if (!ParseDirectory(
+              tiff_offset_, tiff_offset_ + offset, endian_, desired_tags,
+              stream_, tiff_content->exif_directory.get(), &next_ifd_offset)) {
+        return false;
       }
 
       return ParseGpsData(tiff_ifd, tiff_content);
@@ -572,34 +679,32 @@
     return ParseGpsData(tiff_ifd, tiff_content);
   }
 
-  return error;
+  return true;
 }
 
-Error TiffParser::ParseIfd(const std::uint32_t offset_to_ifd,
-                           const TagSet& desired_tags,
-                           const std::uint16_t max_number_ifds,
-                           IfdVector* tiff_directory) {
+bool TiffParser::ParseIfd(const std::uint32_t offset_to_ifd,
+                          const TagSet& desired_tags,
+                          const std::uint16_t max_number_ifds,
+                          IfdVector* tiff_directory) {
   std::uint32_t next_ifd_offset;
   TiffDirectory tiff_ifd(static_cast<Endian>(endian_));
-  Error error =
-      ParseDirectory(tiff_offset_, offset_to_ifd, endian_, desired_tags,
-                     stream_, &tiff_ifd, &next_ifd_offset);
-
-  ParseSubIfds(tiff_offset_, desired_tags, max_number_ifds, endian_, stream_,
-               &tiff_ifd, &error);
-  if (error == kOk) {
-    tiff_directory->push_back(tiff_ifd);
-    if (next_ifd_offset != 0 && tiff_directory->size() < max_number_ifds) {
-      error = ParseIfd(tiff_offset_ + next_ifd_offset, desired_tags,
-                       max_number_ifds, tiff_directory);
-    }
+  if (!ParseDirectory(tiff_offset_, offset_to_ifd, endian_, desired_tags,
+                      stream_, &tiff_ifd, &next_ifd_offset) ||
+      !ParseSubIfds(tiff_offset_, desired_tags, max_number_ifds, endian_,
+                    stream_, &tiff_ifd)) {
+    return false;
   }
 
-  return error;
+  tiff_directory->push_back(tiff_ifd);
+  if (next_ifd_offset != 0 && tiff_directory->size() < max_number_ifds) {
+    return ParseIfd(tiff_offset_ + next_ifd_offset, desired_tags,
+                    max_number_ifds, tiff_directory);
+  }
+  return true;
 }
 
-Error TiffParser::ParseGpsData(const TiffDirectory* tiff_ifd,
-                               TiffContent* tiff_content) {
+bool TiffParser::ParseGpsData(const TiffDirectory* tiff_ifd,
+                              TiffContent* tiff_content) {
   std::uint32_t offset;
   if (tiff_ifd->Get(kExifTagGps, &offset)) {
     tiff_content->gps_directory.reset(new TiffDirectory(endian_));
@@ -612,7 +717,7 @@
                           gps_tags, stream_, tiff_content->gps_directory.get(),
                           &next_ifd_offset);
   }
-  return kOk;
+  return true;
 }
 
 }  // namespace piex
diff --git a/src/tiff_parser.h b/src/tiff_parser.h
index 553b652..a19b71e 100644
--- a/src/tiff_parser.h
+++ b/src/tiff_parser.h
@@ -27,6 +27,9 @@
 
 namespace piex {
 
+// Specifies the maximum number of pixels for thumbnails in each direction.
+const int kThumbnailMaxDimension = 256;
+
 // Specifies all tags that might be of interest to get the preview data.
 enum GpsTags {
   kGpsTagLatitudeRef = 1,
@@ -83,6 +86,7 @@
   kTiffTagSoftware = 0x0131,
   kTiffTagStripByteCounts = 0x0117,
   kTiffTagStripOffsets = 0x0111,
+  kTiffTagSubFileType = 0x00FE,
   kTiffTagSubIfd = 0x014A,
   kTiffTagTileByteCounts = 0x0145,
   kTiffTagTileLength = 0x0143,
@@ -120,25 +124,43 @@
                                   StreamInterface* stream, Error* error);
 
 // Retrieves the endianness of TIFF compliant data at 'tiff_offset' from
-// 'stream' returning true on success. Returns false if when something is wrong.
+// '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 the width and height from the jpeg preview returning true on
+// 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 GetPreviewDimensions(const std::uint32_t jpeg_offset,
-                          StreamInterface* stream, std::uint16_t* width,
-                          std::uint16_t* height);
+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'.
-// Sets 'error' to kFail if something with the Tiff data is wrong.
-Error 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 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);
 
 // Enables us to parse through data that complies to the Tiff/EP specification.
 class TiffParser {
@@ -149,25 +171,24 @@
   TiffParser(StreamInterface* stream, const std::uint32_t offset);
 
   // Runs over the Tiff IFD, Exif IFD and subIFDs to get the preview image data.
-  // Returns kFail if something with the Tiff tags is wrong.
-  Error GetPreviewImageData(const TiffContent& tiff_content,
-                            PreviewImageData* image_metadata);
+  // Returns false if something with the Tiff tags is wrong.
+  bool GetPreviewImageData(const TiffContent& tiff_content,
+                           PreviewImageData* image_metadata);
 
-  // Returns kFail if called more that once or something with the Tiff data is
+  // Returns false if called more that once or something with the Tiff data is
   // wrong.
-  Error Parse(const TagSet& desired_tags, const std::uint16_t max_number_ifds,
-              TiffContent* tiff_content);
+  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;
 
-  Error ParseIfd(const std::uint32_t ifd_offset, const TagSet& desired_tags,
-                 const std::uint16_t max_number_ifds,
-                 IfdVector* tiff_directory);
-  Error ParseGpsData(const tiff_directory::TiffDirectory* tiff_ifd,
-                     TiffContent* tiff_content);
+  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;