From 604bae7c753098ee9e040da4270501b37a8663cf Mon Sep 17 00:00:00 2001 From: Yujie Qin Date: Wed, 6 Apr 2016 12:55:08 +0200 Subject: 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 --- src/piex.cc | 446 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 230 insertions(+), 216 deletions(-) (limited to 'src/piex.cc') 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* 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* 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 strip_offsets; - std::vector 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* 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 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 SupportedExtensions() { return {"ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "PEF", "RAF", "RW2", "SRW"}; } -- cgit v1.2.3