aboutsummaryrefslogtreecommitdiff
path: root/src/piex.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/piex.cc')
-rw-r--r--src/piex.cc446
1 files changed, 230 insertions, 216 deletions
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 image_type_recognition::RecognizeRawImageTypeLite;
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 @@ void GetThumbnailOffsetAndLength(const TagSet& extended_tags,
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);
-}
-
-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;
+ return true;
}
-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 @@ Error GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian,
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 @@ Error GetCameraSettingsIfd(const TiffDirectory& makernote_ifd,
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 @@ Error GetRawProcessingIfd(const TagSet& desired_tags,
// 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 @@ Error GetOlympusPreviewImage(StreamInterface* stream,
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 @@ Error GetOlympusPreviewImage(StreamInterface* stream,
}
}
- 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 @@ Error ArwGetPreviewData(StreamInterface* stream,
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 @@ Error Cr2GetPreviewData(StreamInterface* stream,
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 @@ Error DngGetPreviewData(StreamInterface* stream,
// 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 @@ Error DngGetPreviewData(StreamInterface* stream,
}
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 @@ Error NefGetPreviewData(StreamInterface* stream,
// 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 NefGetPreviewData(StreamInterface* stream,
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 @@ Error PefGetPreviewData(StreamInterface* stream,
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 @@ Error RafGetPreviewData(StreamInterface* stream,
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 @@ Error RafGetPreviewData(StreamInterface* stream,
}
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 @@ Error Rw2GetPreviewData(StreamInterface* stream,
// 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 @@ Error Rw2GetPreviewData(StreamInterface* stream,
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 @@ Error SrwGetPreviewData(StreamInterface* stream,
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 @@ Error GetPreviewImageData(StreamInterface* data,
}
}
+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"};
}