1cb93a386Sopenharmony_ci// Copyright 2015 Google Inc. 2cb93a386Sopenharmony_ci// 3cb93a386Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4cb93a386Sopenharmony_ci// you may not use this file except in compliance with the License. 5cb93a386Sopenharmony_ci// You may obtain a copy of the License at 6cb93a386Sopenharmony_ci// 7cb93a386Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8cb93a386Sopenharmony_ci// 9cb93a386Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10cb93a386Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11cb93a386Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12cb93a386Sopenharmony_ci// See the License for the specific language governing permissions and 13cb93a386Sopenharmony_ci// limitations under the License. 14cb93a386Sopenharmony_ci// 15cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include "src/piex.h" 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci#include <cstdint> 20cb93a386Sopenharmony_ci#include <limits> 21cb93a386Sopenharmony_ci#include <set> 22cb93a386Sopenharmony_ci#include <vector> 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ci#include "src/binary_parse/range_checked_byte_ptr.h" 25cb93a386Sopenharmony_ci#include "src/image_type_recognition/image_type_recognition_lite.h" 26cb93a386Sopenharmony_ci#include "src/tiff_parser.h" 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_cinamespace piex { 29cb93a386Sopenharmony_cinamespace { 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ciusing binary_parse::RangeCheckedBytePtr; 32cb93a386Sopenharmony_ciusing image_type_recognition::RawImageTypes; 33cb93a386Sopenharmony_ciusing image_type_recognition::RecognizeRawImageTypeLite; 34cb93a386Sopenharmony_ciusing tiff_directory::Endian; 35cb93a386Sopenharmony_ciusing tiff_directory::TiffDirectory; 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ciconst std::uint32_t kRafOffsetToPreviewOffset = 84; 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cibool GetDngInformation(const tiff_directory::TiffDirectory& tiff_directory, 40cb93a386Sopenharmony_ci std::uint32_t* width, std::uint32_t* height, 41cb93a386Sopenharmony_ci std::vector<std::uint32_t>* cfa_pattern_dim) { 42cb93a386Sopenharmony_ci if (!GetFullDimension32(tiff_directory, width, height) || *width == 0 || 43cb93a386Sopenharmony_ci *height == 0) { 44cb93a386Sopenharmony_ci return false; 45cb93a386Sopenharmony_ci } 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci if (!tiff_directory.Get(kTiffTagCfaPatternDim, cfa_pattern_dim) || 48cb93a386Sopenharmony_ci cfa_pattern_dim->size() != 2) { 49cb93a386Sopenharmony_ci return false; 50cb93a386Sopenharmony_ci } 51cb93a386Sopenharmony_ci return true; 52cb93a386Sopenharmony_ci} 53cb93a386Sopenharmony_ci 54cb93a386Sopenharmony_cibool GetDngInformation(const TagSet& extended_tags, StreamInterface* data, 55cb93a386Sopenharmony_ci std::uint32_t* width, std::uint32_t* height, 56cb93a386Sopenharmony_ci std::vector<std::uint32_t>* cfa_pattern_dim) { 57cb93a386Sopenharmony_ci TagSet desired_tags = {kExifTagDefaultCropSize, kTiffTagCfaPatternDim, 58cb93a386Sopenharmony_ci kTiffTagExifIfd, kTiffTagSubFileType}; 59cb93a386Sopenharmony_ci desired_tags.insert(extended_tags.cbegin(), extended_tags.cend()); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci TiffParser tiff_parser(data, 0 /* offset */); 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci TiffContent tiff_content; 64cb93a386Sopenharmony_ci if (!tiff_parser.Parse(desired_tags, 1, &tiff_content) || 65cb93a386Sopenharmony_ci tiff_content.tiff_directory.empty()) { 66cb93a386Sopenharmony_ci return false; 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci // If IFD0 contains already the full dimensions we do not parse into the sub 70cb93a386Sopenharmony_ci // IFD. 71cb93a386Sopenharmony_ci const TiffDirectory& tiff_directory = tiff_content.tiff_directory[0]; 72cb93a386Sopenharmony_ci if (tiff_directory.GetSubDirectories().empty()) { 73cb93a386Sopenharmony_ci return GetDngInformation(tiff_directory, width, height, cfa_pattern_dim); 74cb93a386Sopenharmony_ci } else { 75cb93a386Sopenharmony_ci return GetDngInformation(tiff_directory.GetSubDirectories()[0], width, 76cb93a386Sopenharmony_ci height, cfa_pattern_dim); 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_cibool GetPreviewData(const TagSet& extended_tags, 81cb93a386Sopenharmony_ci const std::uint32_t tiff_offset, 82cb93a386Sopenharmony_ci const std::uint32_t number_of_ifds, StreamInterface* stream, 83cb93a386Sopenharmony_ci TiffContent* tiff_content, 84cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 85cb93a386Sopenharmony_ci TagSet desired_tags = { 86cb93a386Sopenharmony_ci kExifTagColorSpace, kExifTagDateTimeOriginal, kExifTagExposureTime, 87cb93a386Sopenharmony_ci kExifTagFnumber, kExifTagFocalLength, kExifTagGps, 88cb93a386Sopenharmony_ci kExifTagIsoSpeed, kTiffTagCompression, kTiffTagDateTime, 89cb93a386Sopenharmony_ci kTiffTagExifIfd, kTiffTagCfaPatternDim, kTiffTagMake, 90cb93a386Sopenharmony_ci kTiffTagModel, kTiffTagOrientation, kTiffTagPhotometric}; 91cb93a386Sopenharmony_ci desired_tags.insert(extended_tags.cbegin(), extended_tags.cend()); 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci TiffParser tiff_parser(stream, tiff_offset); 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci if (!tiff_parser.Parse(desired_tags, number_of_ifds, tiff_content)) { 96cb93a386Sopenharmony_ci return false; 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci if (tiff_content->tiff_directory.empty()) { 99cb93a386Sopenharmony_ci // Returns false if the stream does not contain any TIFF structure. 100cb93a386Sopenharmony_ci return false; 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci return tiff_parser.GetPreviewImageData(*tiff_content, preview_image_data); 103cb93a386Sopenharmony_ci} 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_cibool GetPreviewData(const TagSet& extended_tags, 106cb93a386Sopenharmony_ci const std::uint32_t number_of_ifds, StreamInterface* stream, 107cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 108cb93a386Sopenharmony_ci const std::uint32_t kTiffOffset = 0; 109cb93a386Sopenharmony_ci TiffContent tiff_content; 110cb93a386Sopenharmony_ci return GetPreviewData(extended_tags, kTiffOffset, number_of_ifds, stream, 111cb93a386Sopenharmony_ci &tiff_content, preview_image_data); 112cb93a386Sopenharmony_ci} 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_cibool GetExifData(const std::uint32_t exif_offset, StreamInterface* stream, 115cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 116cb93a386Sopenharmony_ci const TagSet kExtendedTags = {kTiffTagJpegByteCount, kTiffTagJpegOffset}; 117cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 2; 118cb93a386Sopenharmony_ci TiffContent tiff_content; 119cb93a386Sopenharmony_ci return GetPreviewData(kExtendedTags, exif_offset, kNumberOfIfds, stream, 120cb93a386Sopenharmony_ci &tiff_content, preview_image_data); 121cb93a386Sopenharmony_ci} 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci// Reads the jpeg compressed thumbnail information. 124cb93a386Sopenharmony_civoid GetThumbnailOffsetAndLength(const TagSet& extended_tags, 125cb93a386Sopenharmony_ci StreamInterface* stream, 126cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 127cb93a386Sopenharmony_ci TagSet desired_tags = {kTiffTagJpegByteCount, kTiffTagJpegOffset}; 128cb93a386Sopenharmony_ci desired_tags.insert(extended_tags.cbegin(), extended_tags.cend()); 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 2; 131cb93a386Sopenharmony_ci PreviewImageData thumbnail_data; 132cb93a386Sopenharmony_ci if (GetPreviewData(desired_tags, kNumberOfIfds, stream, &thumbnail_data)) { 133cb93a386Sopenharmony_ci preview_image_data->thumbnail = thumbnail_data.thumbnail; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci} 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_cibool GetExifIfd(const Endian endian, StreamInterface* stream, 138cb93a386Sopenharmony_ci TiffDirectory* exif_ifd) { 139cb93a386Sopenharmony_ci const std::uint32_t kTiffOffset = 0; 140cb93a386Sopenharmony_ci std::uint32_t offset_to_ifd; 141cb93a386Sopenharmony_ci if (!Get32u(stream, sizeof(offset_to_ifd), endian, &offset_to_ifd)) { 142cb93a386Sopenharmony_ci return false; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci std::uint32_t next_ifd_offset; 146cb93a386Sopenharmony_ci TiffDirectory tiff_ifd(endian); 147cb93a386Sopenharmony_ci if (!ParseDirectory(kTiffOffset, offset_to_ifd, endian, {kTiffTagExifIfd}, 148cb93a386Sopenharmony_ci stream, &tiff_ifd, &next_ifd_offset)) { 149cb93a386Sopenharmony_ci return false; 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci std::uint32_t exif_offset; 153cb93a386Sopenharmony_ci if (tiff_ifd.Get(kTiffTagExifIfd, &exif_offset)) { 154cb93a386Sopenharmony_ci return ParseDirectory(kTiffOffset, exif_offset, endian, 155cb93a386Sopenharmony_ci {kExifTagMakernotes}, stream, exif_ifd, 156cb93a386Sopenharmony_ci &next_ifd_offset); 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci return true; 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_cibool GetMakernoteIfd(const TiffDirectory& exif_ifd, const Endian endian, 163cb93a386Sopenharmony_ci const std::uint32_t skip_offset, StreamInterface* stream, 164cb93a386Sopenharmony_ci std::uint32_t* makernote_offset, 165cb93a386Sopenharmony_ci TiffDirectory* makernote_ifd) { 166cb93a386Sopenharmony_ci std::uint32_t makernote_length; 167cb93a386Sopenharmony_ci if (!exif_ifd.GetOffsetAndLength(kExifTagMakernotes, 168cb93a386Sopenharmony_ci tiff_directory::TIFF_TYPE_UNDEFINED, 169cb93a386Sopenharmony_ci makernote_offset, &makernote_length)) { 170cb93a386Sopenharmony_ci return false; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci std::uint32_t next_ifd_offset; 174cb93a386Sopenharmony_ci return ParseDirectory(*makernote_offset, *makernote_offset + skip_offset, 175cb93a386Sopenharmony_ci endian, {kTiffTagImageWidth, kOlymTagCameraSettings, 176cb93a386Sopenharmony_ci kOlymTagRawProcessing, kPentaxTagColorSpace}, 177cb93a386Sopenharmony_ci stream, makernote_ifd, &next_ifd_offset); 178cb93a386Sopenharmony_ci} 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_cibool GetCameraSettingsIfd(const TiffDirectory& makernote_ifd, 181cb93a386Sopenharmony_ci const std::uint32_t makernote_offset, 182cb93a386Sopenharmony_ci const Endian endian, StreamInterface* stream, 183cb93a386Sopenharmony_ci TiffDirectory* camera_settings_ifd) { 184cb93a386Sopenharmony_ci std::uint32_t camera_settings_offset; 185cb93a386Sopenharmony_ci std::uint32_t camera_settings_length; 186cb93a386Sopenharmony_ci if (!makernote_ifd.GetOffsetAndLength( 187cb93a386Sopenharmony_ci kOlymTagCameraSettings, tiff_directory::TIFF_IFD, 188cb93a386Sopenharmony_ci &camera_settings_offset, &camera_settings_length)) { 189cb93a386Sopenharmony_ci return false; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci std::uint32_t next_ifd_offset; 193cb93a386Sopenharmony_ci if (!Get32u(stream, camera_settings_offset, endian, 194cb93a386Sopenharmony_ci &camera_settings_offset)) { 195cb93a386Sopenharmony_ci return false; 196cb93a386Sopenharmony_ci } 197cb93a386Sopenharmony_ci return ParseDirectory(makernote_offset, 198cb93a386Sopenharmony_ci makernote_offset + camera_settings_offset, endian, 199cb93a386Sopenharmony_ci {kTiffTagBitsPerSample, kTiffTagImageLength}, stream, 200cb93a386Sopenharmony_ci camera_settings_ifd, &next_ifd_offset); 201cb93a386Sopenharmony_ci} 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_cibool GetRawProcessingIfd(const TagSet& desired_tags, 204cb93a386Sopenharmony_ci const TiffDirectory& makernote_ifd, 205cb93a386Sopenharmony_ci const std::uint32_t makernote_offset, 206cb93a386Sopenharmony_ci const Endian endian, StreamInterface* stream, 207cb93a386Sopenharmony_ci TiffDirectory* raw_processing_ifd) { 208cb93a386Sopenharmony_ci std::uint32_t raw_processing_offset; 209cb93a386Sopenharmony_ci std::uint32_t raw_processing_length; 210cb93a386Sopenharmony_ci if (!makernote_ifd.GetOffsetAndLength( 211cb93a386Sopenharmony_ci kOlymTagRawProcessing, tiff_directory::TIFF_IFD, 212cb93a386Sopenharmony_ci &raw_processing_offset, &raw_processing_length)) { 213cb93a386Sopenharmony_ci return false; 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci std::uint32_t next_ifd_offset; 217cb93a386Sopenharmony_ci if (!Get32u(stream, raw_processing_offset, endian, &raw_processing_offset)) { 218cb93a386Sopenharmony_ci return false; 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci return ParseDirectory( 222cb93a386Sopenharmony_ci makernote_offset, makernote_offset + raw_processing_offset, endian, 223cb93a386Sopenharmony_ci desired_tags, stream, raw_processing_ifd, &next_ifd_offset); 224cb93a386Sopenharmony_ci} 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci// Retrieves the preview image offset and length from the camera settings and 227cb93a386Sopenharmony_ci// the 'full_width' and 'full_height' from the raw processing ifd in 'stream'. 228cb93a386Sopenharmony_ci// Returns false if anything is wrong. 229cb93a386Sopenharmony_cibool GetOlympusPreviewImage(StreamInterface* stream, 230cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 231cb93a386Sopenharmony_ci Endian endian; 232cb93a386Sopenharmony_ci if (!GetEndianness(0 /* tiff offset */, stream, &endian)) { 233cb93a386Sopenharmony_ci return false; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci TiffDirectory exif_ifd(endian); 237cb93a386Sopenharmony_ci if (!GetExifIfd(endian, stream, &exif_ifd)) { 238cb93a386Sopenharmony_ci return false; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci std::uint32_t makernote_offset; 242cb93a386Sopenharmony_ci TiffDirectory makernote_ifd(endian); 243cb93a386Sopenharmony_ci const std::uint32_t kSkipMakernoteStart = 12; 244cb93a386Sopenharmony_ci if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream, 245cb93a386Sopenharmony_ci &makernote_offset, &makernote_ifd)) { 246cb93a386Sopenharmony_ci return false; 247cb93a386Sopenharmony_ci } 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci const std::uint32_t kThumbnailTag = 0x0100; 250cb93a386Sopenharmony_ci if (makernote_ifd.Has(kThumbnailTag)) { 251cb93a386Sopenharmony_ci if (!makernote_ifd.GetOffsetAndLength( 252cb93a386Sopenharmony_ci kThumbnailTag, tiff_directory::TIFF_TYPE_UNDEFINED, 253cb93a386Sopenharmony_ci &preview_image_data->thumbnail.offset, 254cb93a386Sopenharmony_ci &preview_image_data->thumbnail.length)) { 255cb93a386Sopenharmony_ci return false; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci TiffDirectory camera_settings_ifd(endian); 260cb93a386Sopenharmony_ci if (!GetCameraSettingsIfd(makernote_ifd, makernote_offset, endian, stream, 261cb93a386Sopenharmony_ci &camera_settings_ifd)) { 262cb93a386Sopenharmony_ci return false; 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci const std::uint32_t kPreviewOffset = 0x0101; 266cb93a386Sopenharmony_ci const std::uint32_t kPreviewLength = 0x0102; 267cb93a386Sopenharmony_ci if (!camera_settings_ifd.Has(kPreviewOffset) || 268cb93a386Sopenharmony_ci !camera_settings_ifd.Has(kPreviewLength)) { 269cb93a386Sopenharmony_ci return false; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci 272cb93a386Sopenharmony_ci camera_settings_ifd.Get(kPreviewOffset, &preview_image_data->preview.offset); 273cb93a386Sopenharmony_ci preview_image_data->preview.offset += makernote_offset; 274cb93a386Sopenharmony_ci camera_settings_ifd.Get(kPreviewLength, &preview_image_data->preview.length); 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci // Get the crop size from the raw processing ifd. 277cb93a386Sopenharmony_ci TiffDirectory raw_processing_ifd(endian); 278cb93a386Sopenharmony_ci if (!GetRawProcessingIfd({kOlymTagAspectFrame}, makernote_ifd, 279cb93a386Sopenharmony_ci makernote_offset, endian, stream, 280cb93a386Sopenharmony_ci &raw_processing_ifd)) { 281cb93a386Sopenharmony_ci return false; 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci 284cb93a386Sopenharmony_ci if (raw_processing_ifd.Has(kOlymTagAspectFrame)) { 285cb93a386Sopenharmony_ci std::vector<std::uint32_t> aspect_frame(4); 286cb93a386Sopenharmony_ci if (raw_processing_ifd.Get(kOlymTagAspectFrame, &aspect_frame) && 287cb93a386Sopenharmony_ci aspect_frame[2] > aspect_frame[0] && 288cb93a386Sopenharmony_ci aspect_frame[3] > aspect_frame[1]) { 289cb93a386Sopenharmony_ci preview_image_data->full_width = aspect_frame[2] - aspect_frame[0] + 1; 290cb93a386Sopenharmony_ci preview_image_data->full_height = aspect_frame[3] - aspect_frame[1] + 1; 291cb93a386Sopenharmony_ci if (preview_image_data->full_width < preview_image_data->full_height) { 292cb93a386Sopenharmony_ci std::swap(preview_image_data->full_width, 293cb93a386Sopenharmony_ci preview_image_data->full_height); 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci } 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci return true; 299cb93a386Sopenharmony_ci} 300cb93a386Sopenharmony_ci 301cb93a386Sopenharmony_cibool PefGetColorSpace(StreamInterface* stream, 302cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 303cb93a386Sopenharmony_ci Endian endian; 304cb93a386Sopenharmony_ci if (!GetEndianness(0 /* tiff offset */, stream, &endian)) { 305cb93a386Sopenharmony_ci return false; 306cb93a386Sopenharmony_ci } 307cb93a386Sopenharmony_ci 308cb93a386Sopenharmony_ci TiffDirectory exif_ifd(endian); 309cb93a386Sopenharmony_ci if (!GetExifIfd(endian, stream, &exif_ifd)) { 310cb93a386Sopenharmony_ci return false; 311cb93a386Sopenharmony_ci } 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci std::uint32_t makernote_offset; 314cb93a386Sopenharmony_ci TiffDirectory makernote_ifd(endian); 315cb93a386Sopenharmony_ci const std::uint32_t kSkipMakernoteStart = 6; 316cb93a386Sopenharmony_ci if (!GetMakernoteIfd(exif_ifd, endian, kSkipMakernoteStart, stream, 317cb93a386Sopenharmony_ci &makernote_offset, &makernote_ifd)) { 318cb93a386Sopenharmony_ci return false; 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci if (makernote_ifd.Has(kPentaxTagColorSpace)) { 321cb93a386Sopenharmony_ci std::uint32_t color_space; 322cb93a386Sopenharmony_ci if (!makernote_ifd.Get(kPentaxTagColorSpace, &color_space)) { 323cb93a386Sopenharmony_ci return false; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci preview_image_data->color_space = color_space == 0 326cb93a386Sopenharmony_ci ? PreviewImageData::kSrgb 327cb93a386Sopenharmony_ci : PreviewImageData::kAdobeRgb; 328cb93a386Sopenharmony_ci } 329cb93a386Sopenharmony_ci return true; 330cb93a386Sopenharmony_ci} 331cb93a386Sopenharmony_ci 332cb93a386Sopenharmony_cibool RafGetOrientation(StreamInterface* stream, std::uint32_t* orientation) { 333cb93a386Sopenharmony_ci // Parse the Fuji RAW header to get the offset and length of the preview 334cb93a386Sopenharmony_ci // image, which contains the Exif information. 335cb93a386Sopenharmony_ci const Endian endian = tiff_directory::kBigEndian; 336cb93a386Sopenharmony_ci std::uint32_t preview_offset = 0; 337cb93a386Sopenharmony_ci if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset)) { 338cb93a386Sopenharmony_ci return false; 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci 341cb93a386Sopenharmony_ci const std::uint32_t exif_offset = preview_offset + 12; 342cb93a386Sopenharmony_ci return GetExifOrientation(stream, exif_offset, orientation); 343cb93a386Sopenharmony_ci} 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci// Parses the Fuji Cfa header for the image width and height. 346cb93a386Sopenharmony_cibool RafGetDimension(StreamInterface* stream, std::uint32_t* width, 347cb93a386Sopenharmony_ci std::uint32_t* height) { 348cb93a386Sopenharmony_ci const Endian endian = tiff_directory::kBigEndian; 349cb93a386Sopenharmony_ci std::uint32_t cfa_header_index = 0; // actual position in the cfa header. 350cb93a386Sopenharmony_ci std::uint32_t cfa_header_entries = 0; 351cb93a386Sopenharmony_ci if (!Get32u(stream, 92 /* cfa header offset */, endian, &cfa_header_index) || 352cb93a386Sopenharmony_ci !Get32u(stream, cfa_header_index, endian, &cfa_header_entries)) { 353cb93a386Sopenharmony_ci return false; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci // Add 4 to point to the actual read position in the cfa header. 357cb93a386Sopenharmony_ci cfa_header_index += 4; 358cb93a386Sopenharmony_ci 359cb93a386Sopenharmony_ci for (std::uint32_t i = 0; i < cfa_header_entries; ++i) { 360cb93a386Sopenharmony_ci std::uint16_t id = 0; 361cb93a386Sopenharmony_ci std::uint16_t length = 0; 362cb93a386Sopenharmony_ci if (!Get16u(stream, cfa_header_index, endian, &id) || 363cb93a386Sopenharmony_ci !Get16u(stream, cfa_header_index + 2, endian, &length)) { 364cb93a386Sopenharmony_ci return false; 365cb93a386Sopenharmony_ci } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci std::uint16_t tmp_width = 0; 368cb93a386Sopenharmony_ci std::uint16_t tmp_height = 0; 369cb93a386Sopenharmony_ci if (id == 0x0111 /* tags the crop dimensions */ && 370cb93a386Sopenharmony_ci Get16u(stream, cfa_header_index + 4, endian, &tmp_height) && 371cb93a386Sopenharmony_ci Get16u(stream, cfa_header_index + 6, endian, &tmp_width)) { 372cb93a386Sopenharmony_ci *width = tmp_width; 373cb93a386Sopenharmony_ci *height = tmp_height; 374cb93a386Sopenharmony_ci return true; 375cb93a386Sopenharmony_ci } 376cb93a386Sopenharmony_ci cfa_header_index += 4u + length; 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci return false; 379cb93a386Sopenharmony_ci} 380cb93a386Sopenharmony_ci 381cb93a386Sopenharmony_ciError ArwGetPreviewData(StreamInterface* stream, 382cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 383cb93a386Sopenharmony_ci const TagSet extended_tags = {kExifTagHeight, kExifTagWidth, 384cb93a386Sopenharmony_ci kTiffTagJpegByteCount, kTiffTagJpegOffset, 385cb93a386Sopenharmony_ci kTiffTagSubIfd}; 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ci GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data); 388cb93a386Sopenharmony_ci 389cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 1; 390cb93a386Sopenharmony_ci if (GetPreviewData(extended_tags, kNumberOfIfds, stream, 391cb93a386Sopenharmony_ci preview_image_data)) { 392cb93a386Sopenharmony_ci return kOk; 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci return kFail; 395cb93a386Sopenharmony_ci} 396cb93a386Sopenharmony_ci 397cb93a386Sopenharmony_ciError Cr2GetPreviewData(StreamInterface* stream, 398cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 399cb93a386Sopenharmony_ci const TagSet extended_tags = {kExifTagHeight, kExifTagWidth, 400cb93a386Sopenharmony_ci kTiffTagStripByteCounts, kTiffTagStripOffsets}; 401cb93a386Sopenharmony_ci 402cb93a386Sopenharmony_ci GetThumbnailOffsetAndLength(TagSet(), stream, preview_image_data); 403cb93a386Sopenharmony_ci 404cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 1; 405cb93a386Sopenharmony_ci if (GetPreviewData(extended_tags, kNumberOfIfds, stream, 406cb93a386Sopenharmony_ci preview_image_data)) { 407cb93a386Sopenharmony_ci return kOk; 408cb93a386Sopenharmony_ci } 409cb93a386Sopenharmony_ci return kFail; 410cb93a386Sopenharmony_ci} 411cb93a386Sopenharmony_ci 412cb93a386Sopenharmony_ciError DngGetPreviewData(StreamInterface* stream, 413cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 414cb93a386Sopenharmony_ci // Some thumbnails from DngCreator are larger than the specified 256 pixel. 415cb93a386Sopenharmony_ci const int kDngThumbnailMaxDimension = 512; 416cb93a386Sopenharmony_ci 417cb93a386Sopenharmony_ci const TagSet extended_tags = { 418cb93a386Sopenharmony_ci kExifTagDefaultCropSize, kTiffTagImageWidth, kTiffTagImageLength, 419cb93a386Sopenharmony_ci kTiffTagStripByteCounts, kTiffTagStripOffsets, kTiffTagSubIfd}; 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci TiffContent tiff_content; 422cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 3; 423cb93a386Sopenharmony_ci if (!GetPreviewData(extended_tags, 0, kNumberOfIfds, stream, &tiff_content, 424cb93a386Sopenharmony_ci preview_image_data)) { 425cb93a386Sopenharmony_ci return kFail; 426cb93a386Sopenharmony_ci } 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci const TiffDirectory& tiff_directory = tiff_content.tiff_directory[0]; 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ci if (!GetFullCropDimension(tiff_directory, &preview_image_data->full_width, 431cb93a386Sopenharmony_ci &preview_image_data->full_height)) { 432cb93a386Sopenharmony_ci return kFail; 433cb93a386Sopenharmony_ci } 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci // Find the jpeg compressed thumbnail and preview image. 436cb93a386Sopenharmony_ci Image preview; 437cb93a386Sopenharmony_ci Image thumbnail; 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci // Search for images in IFD0 440cb93a386Sopenharmony_ci Image temp_image; 441cb93a386Sopenharmony_ci if (GetImageData(tiff_directory, stream, &temp_image)) { 442cb93a386Sopenharmony_ci if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) { 443cb93a386Sopenharmony_ci thumbnail = temp_image; 444cb93a386Sopenharmony_ci } else if (temp_image.format == Image::kJpegCompressed) { 445cb93a386Sopenharmony_ci preview = temp_image; 446cb93a386Sopenharmony_ci } 447cb93a386Sopenharmony_ci } 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci // Search for images in other IFDs 450cb93a386Sopenharmony_ci for (const auto& ifd : tiff_directory.GetSubDirectories()) { 451cb93a386Sopenharmony_ci if (GetImageData(ifd, stream, &temp_image)) { 452cb93a386Sopenharmony_ci // Try to find the largest thumbnail/preview. 453cb93a386Sopenharmony_ci if (IsThumbnail(temp_image, kDngThumbnailMaxDimension)) { 454cb93a386Sopenharmony_ci if (temp_image > thumbnail) { 455cb93a386Sopenharmony_ci thumbnail = temp_image; 456cb93a386Sopenharmony_ci } 457cb93a386Sopenharmony_ci } else { 458cb93a386Sopenharmony_ci if (temp_image > preview && 459cb93a386Sopenharmony_ci temp_image.format == Image::kJpegCompressed) { 460cb93a386Sopenharmony_ci preview = temp_image; 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci } 463cb93a386Sopenharmony_ci } 464cb93a386Sopenharmony_ci } 465cb93a386Sopenharmony_ci preview_image_data->preview = preview; 466cb93a386Sopenharmony_ci preview_image_data->thumbnail = thumbnail; 467cb93a386Sopenharmony_ci 468cb93a386Sopenharmony_ci return kOk; 469cb93a386Sopenharmony_ci} 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ciError NefGetPreviewData(StreamInterface* stream, 472cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 473cb93a386Sopenharmony_ci const TagSet extended_tags = {kTiffTagImageWidth, kTiffTagImageLength, 474cb93a386Sopenharmony_ci kTiffTagJpegByteCount, kTiffTagJpegOffset, 475cb93a386Sopenharmony_ci kTiffTagStripByteCounts, kTiffTagStripOffsets, 476cb93a386Sopenharmony_ci kTiffTagSubIfd}; 477cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 2; 478cb93a386Sopenharmony_ci if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, 479cb93a386Sopenharmony_ci preview_image_data)) { 480cb93a386Sopenharmony_ci return kFail; 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci if (preview_image_data->thumbnail.length == 0) { 484cb93a386Sopenharmony_ci PreviewImageData thumbnail_data; 485cb93a386Sopenharmony_ci GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data); 486cb93a386Sopenharmony_ci preview_image_data->thumbnail = thumbnail_data.thumbnail; 487cb93a386Sopenharmony_ci } 488cb93a386Sopenharmony_ci 489cb93a386Sopenharmony_ci // The Nikon RAW data provides the dimensions of the sensor image, which are 490cb93a386Sopenharmony_ci // slightly larger than the dimensions of the preview image. In order to 491cb93a386Sopenharmony_ci // determine the correct full width and height of the image, the preview image 492cb93a386Sopenharmony_ci // size needs to be taken into account. Based on experiments the preview image 493cb93a386Sopenharmony_ci // dimensions must be at least 90% of the sensor image dimensions to let it be 494cb93a386Sopenharmony_ci // a full size preview image. 495cb93a386Sopenharmony_ci if (preview_image_data->preview.length > 0) { // when preview image exists 496cb93a386Sopenharmony_ci const float kEpsilon = 0.9f; 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci std::uint16_t width; 499cb93a386Sopenharmony_ci std::uint16_t height; 500cb93a386Sopenharmony_ci if (!GetJpegDimensions(preview_image_data->preview.offset, stream, &width, 501cb93a386Sopenharmony_ci &height) || 502cb93a386Sopenharmony_ci preview_image_data->full_width == 0 || 503cb93a386Sopenharmony_ci preview_image_data->full_height == 0) { 504cb93a386Sopenharmony_ci return kUnsupported; 505cb93a386Sopenharmony_ci } 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci if (static_cast<float>(width) / 508cb93a386Sopenharmony_ci static_cast<float>(preview_image_data->full_width) > 509cb93a386Sopenharmony_ci kEpsilon || 510cb93a386Sopenharmony_ci static_cast<float>(height) / 511cb93a386Sopenharmony_ci static_cast<float>(preview_image_data->full_height) > 512cb93a386Sopenharmony_ci kEpsilon) { 513cb93a386Sopenharmony_ci preview_image_data->full_width = width; 514cb93a386Sopenharmony_ci preview_image_data->full_height = height; 515cb93a386Sopenharmony_ci } 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci return kOk; 518cb93a386Sopenharmony_ci} 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ciError OrfGetPreviewData(StreamInterface* stream, 521cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 522cb93a386Sopenharmony_ci if (!GetExifData(0, stream, preview_image_data)) { 523cb93a386Sopenharmony_ci return kFail; 524cb93a386Sopenharmony_ci } 525cb93a386Sopenharmony_ci // Omit errors, because some images do not contain any preview data. 526cb93a386Sopenharmony_ci GetOlympusPreviewImage(stream, preview_image_data); 527cb93a386Sopenharmony_ci return kOk; 528cb93a386Sopenharmony_ci} 529cb93a386Sopenharmony_ci 530cb93a386Sopenharmony_ciError PefGetPreviewData(StreamInterface* stream, 531cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 532cb93a386Sopenharmony_ci const TagSet extended_tags = {kTiffTagImageWidth, kTiffTagImageLength, 533cb93a386Sopenharmony_ci kTiffTagJpegByteCount, kTiffTagJpegOffset, 534cb93a386Sopenharmony_ci kTiffTagSubIfd}; 535cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 3; 536cb93a386Sopenharmony_ci if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, 537cb93a386Sopenharmony_ci preview_image_data) || 538cb93a386Sopenharmony_ci !PefGetColorSpace(stream, preview_image_data)) { 539cb93a386Sopenharmony_ci return kFail; 540cb93a386Sopenharmony_ci } 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci PreviewImageData thumbnail_data; 543cb93a386Sopenharmony_ci GetThumbnailOffsetAndLength(TagSet(), stream, &thumbnail_data); 544cb93a386Sopenharmony_ci preview_image_data->thumbnail = thumbnail_data.thumbnail; 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ci return kOk; 547cb93a386Sopenharmony_ci} 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ciError RafGetPreviewData(StreamInterface* stream, 550cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 551cb93a386Sopenharmony_ci // Parse the Fuji RAW header to get the offset and length of the preview 552cb93a386Sopenharmony_ci // image, which contains the Exif information. 553cb93a386Sopenharmony_ci const Endian endian = tiff_directory::kBigEndian; 554cb93a386Sopenharmony_ci std::uint32_t preview_offset = 0; 555cb93a386Sopenharmony_ci std::uint32_t preview_length = 0; 556cb93a386Sopenharmony_ci if (!Get32u(stream, kRafOffsetToPreviewOffset, endian, &preview_offset) || 557cb93a386Sopenharmony_ci !Get32u(stream, kRafOffsetToPreviewOffset + 4, endian, &preview_length)) { 558cb93a386Sopenharmony_ci return kFail; 559cb93a386Sopenharmony_ci } 560cb93a386Sopenharmony_ci 561cb93a386Sopenharmony_ci if (!RafGetDimension(stream, &preview_image_data->full_width, 562cb93a386Sopenharmony_ci &preview_image_data->full_height)) { 563cb93a386Sopenharmony_ci return kFail; 564cb93a386Sopenharmony_ci } 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci if (preview_length > 0) { // when preview image exists 567cb93a386Sopenharmony_ci // Parse the Exif information from the preview image. 568cb93a386Sopenharmony_ci const std::uint32_t exif_offset = preview_offset + 12; 569cb93a386Sopenharmony_ci if (!GetExifData(exif_offset, stream, preview_image_data)) { 570cb93a386Sopenharmony_ci return kFail; 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci 574cb93a386Sopenharmony_ci // Merge the Exif data with the RAW data to form the preview_image_data. 575cb93a386Sopenharmony_ci preview_image_data->thumbnail.offset += 160; // Skip the cfa header. 576cb93a386Sopenharmony_ci preview_image_data->preview.offset = preview_offset; 577cb93a386Sopenharmony_ci preview_image_data->preview.length = preview_length; 578cb93a386Sopenharmony_ci return kOk; 579cb93a386Sopenharmony_ci} 580cb93a386Sopenharmony_ci 581cb93a386Sopenharmony_ciError Rw2GetPreviewData(StreamInterface* stream, 582cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 583cb93a386Sopenharmony_ci const TagSet extended_tags = {kPanaTagTopBorder, kPanaTagLeftBorder, 584cb93a386Sopenharmony_ci kPanaTagBottomBorder, kPanaTagRightBorder, 585cb93a386Sopenharmony_ci kPanaTagIso, kPanaTagJpegImage, 586cb93a386Sopenharmony_ci kTiffTagJpegByteCount, kTiffTagJpegOffset}; 587cb93a386Sopenharmony_ci // Parse the RAW data to get the ISO, offset and length of the preview image, 588cb93a386Sopenharmony_ci // which contains the Exif information. 589cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 1; 590cb93a386Sopenharmony_ci PreviewImageData preview_data; 591cb93a386Sopenharmony_ci if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, &preview_data)) { 592cb93a386Sopenharmony_ci return kFail; 593cb93a386Sopenharmony_ci } 594cb93a386Sopenharmony_ci 595cb93a386Sopenharmony_ci if (preview_data.preview.length > 0) { // when preview image exists 596cb93a386Sopenharmony_ci // Parse the Exif information from the preview image. 597cb93a386Sopenharmony_ci const std::uint32_t exif_offset = preview_data.preview.offset + 12; 598cb93a386Sopenharmony_ci if (!GetExifData(exif_offset, stream, preview_image_data)) { 599cb93a386Sopenharmony_ci return kFail; 600cb93a386Sopenharmony_ci } 601cb93a386Sopenharmony_ci preview_image_data->thumbnail.offset += exif_offset; 602cb93a386Sopenharmony_ci } 603cb93a386Sopenharmony_ci 604cb93a386Sopenharmony_ci // Merge the Exif data with the RAW data to form the preview_image_data. 605cb93a386Sopenharmony_ci preview_image_data->preview = preview_data.preview; 606cb93a386Sopenharmony_ci preview_image_data->iso = preview_data.iso; 607cb93a386Sopenharmony_ci preview_image_data->full_width = preview_data.full_width; 608cb93a386Sopenharmony_ci preview_image_data->full_height = preview_data.full_height; 609cb93a386Sopenharmony_ci 610cb93a386Sopenharmony_ci return kOk; 611cb93a386Sopenharmony_ci} 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ciError SrwGetPreviewData(StreamInterface* stream, 614cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 615cb93a386Sopenharmony_ci GetThumbnailOffsetAndLength({kTiffTagSubIfd}, stream, preview_image_data); 616cb93a386Sopenharmony_ci 617cb93a386Sopenharmony_ci const TagSet extended_tags = {kExifTagWidth, kExifTagHeight, 618cb93a386Sopenharmony_ci kTiffTagJpegByteCount, kTiffTagJpegOffset, 619cb93a386Sopenharmony_ci kTiffTagSubIfd}; 620cb93a386Sopenharmony_ci const std::uint32_t kNumberOfIfds = 1; 621cb93a386Sopenharmony_ci if (!GetPreviewData(extended_tags, kNumberOfIfds, stream, 622cb93a386Sopenharmony_ci preview_image_data)) { 623cb93a386Sopenharmony_ci return kFail; 624cb93a386Sopenharmony_ci } 625cb93a386Sopenharmony_ci return kOk; 626cb93a386Sopenharmony_ci} 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci} // namespace 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_cisize_t BytesRequiredForIsRaw() { 631cb93a386Sopenharmony_ci return image_type_recognition::GetNumberOfBytesForIsRawLite(); 632cb93a386Sopenharmony_ci} 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_cibool IsRaw(StreamInterface* data) { 635cb93a386Sopenharmony_ci const size_t bytes = BytesRequiredForIsRaw(); 636cb93a386Sopenharmony_ci if (data == nullptr) { 637cb93a386Sopenharmony_ci return false; 638cb93a386Sopenharmony_ci } 639cb93a386Sopenharmony_ci 640cb93a386Sopenharmony_ci // Read required number of bytes into a vector. 641cb93a386Sopenharmony_ci std::vector<std::uint8_t> file_header(bytes); 642cb93a386Sopenharmony_ci if (data->GetData(0, file_header.size(), file_header.data()) != kOk) { 643cb93a386Sopenharmony_ci return false; 644cb93a386Sopenharmony_ci } 645cb93a386Sopenharmony_ci 646cb93a386Sopenharmony_ci RangeCheckedBytePtr data_buffer(file_header.data(), file_header.size()); 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_ci return image_type_recognition::IsRawLite(data_buffer); 649cb93a386Sopenharmony_ci} 650cb93a386Sopenharmony_ci 651cb93a386Sopenharmony_ciError GetPreviewImageData(StreamInterface* data, 652cb93a386Sopenharmony_ci PreviewImageData* preview_image_data) { 653cb93a386Sopenharmony_ci const size_t bytes = BytesRequiredForIsRaw(); 654cb93a386Sopenharmony_ci if (data == nullptr || bytes == 0) { 655cb93a386Sopenharmony_ci return kFail; 656cb93a386Sopenharmony_ci } 657cb93a386Sopenharmony_ci 658cb93a386Sopenharmony_ci std::vector<std::uint8_t> file_header(bytes); 659cb93a386Sopenharmony_ci Error error = data->GetData(0, file_header.size(), file_header.data()); 660cb93a386Sopenharmony_ci if (error != kOk) { 661cb93a386Sopenharmony_ci return error; 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci RangeCheckedBytePtr header_buffer(file_header.data(), file_header.size()); 664cb93a386Sopenharmony_ci 665cb93a386Sopenharmony_ci switch (RecognizeRawImageTypeLite(header_buffer)) { 666cb93a386Sopenharmony_ci case image_type_recognition::kArwImage: 667cb93a386Sopenharmony_ci return ArwGetPreviewData(data, preview_image_data); 668cb93a386Sopenharmony_ci case image_type_recognition::kCr2Image: 669cb93a386Sopenharmony_ci return Cr2GetPreviewData(data, preview_image_data); 670cb93a386Sopenharmony_ci case image_type_recognition::kDngImage: 671cb93a386Sopenharmony_ci return DngGetPreviewData(data, preview_image_data); 672cb93a386Sopenharmony_ci case image_type_recognition::kNefImage: 673cb93a386Sopenharmony_ci case image_type_recognition::kNrwImage: 674cb93a386Sopenharmony_ci return NefGetPreviewData(data, preview_image_data); 675cb93a386Sopenharmony_ci case image_type_recognition::kOrfImage: 676cb93a386Sopenharmony_ci return OrfGetPreviewData(data, preview_image_data); 677cb93a386Sopenharmony_ci case image_type_recognition::kPefImage: 678cb93a386Sopenharmony_ci return PefGetPreviewData(data, preview_image_data); 679cb93a386Sopenharmony_ci case image_type_recognition::kRafImage: 680cb93a386Sopenharmony_ci return RafGetPreviewData(data, preview_image_data); 681cb93a386Sopenharmony_ci case image_type_recognition::kRw2Image: 682cb93a386Sopenharmony_ci return Rw2GetPreviewData(data, preview_image_data); 683cb93a386Sopenharmony_ci case image_type_recognition::kSrwImage: 684cb93a386Sopenharmony_ci return SrwGetPreviewData(data, preview_image_data); 685cb93a386Sopenharmony_ci default: 686cb93a386Sopenharmony_ci return kUnsupported; 687cb93a386Sopenharmony_ci } 688cb93a386Sopenharmony_ci} 689cb93a386Sopenharmony_ci 690cb93a386Sopenharmony_cibool GetDngInformation(StreamInterface* data, std::uint32_t* width, 691cb93a386Sopenharmony_ci std::uint32_t* height, 692cb93a386Sopenharmony_ci std::vector<std::uint32_t>* cfa_pattern_dim) { 693cb93a386Sopenharmony_ci // If IFD0 contains already the full dimensions we do not parse into the sub 694cb93a386Sopenharmony_ci // IFD. 695cb93a386Sopenharmony_ci if (!GetDngInformation({}, data, width, height, cfa_pattern_dim)) { 696cb93a386Sopenharmony_ci return GetDngInformation({kTiffTagSubIfd}, data, width, height, 697cb93a386Sopenharmony_ci cfa_pattern_dim); 698cb93a386Sopenharmony_ci } 699cb93a386Sopenharmony_ci return true; 700cb93a386Sopenharmony_ci} 701cb93a386Sopenharmony_ci 702cb93a386Sopenharmony_cibool GetOrientation(StreamInterface* data, std::uint32_t* orientation) { 703cb93a386Sopenharmony_ci using image_type_recognition::GetNumberOfBytesForIsOfType; 704cb93a386Sopenharmony_ci using image_type_recognition::IsOfType; 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci std::vector<std::uint8_t> file_header( 707cb93a386Sopenharmony_ci GetNumberOfBytesForIsOfType(image_type_recognition::kRafImage)); 708cb93a386Sopenharmony_ci if (data->GetData(0, file_header.size(), file_header.data()) != kOk) { 709cb93a386Sopenharmony_ci return false; 710cb93a386Sopenharmony_ci } 711cb93a386Sopenharmony_ci 712cb93a386Sopenharmony_ci // For RAF files a special routine is necessary to get orientation. For others 713cb93a386Sopenharmony_ci // the general approach is sufficient. 714cb93a386Sopenharmony_ci if (IsOfType(RangeCheckedBytePtr(file_header.data(), file_header.size()), 715cb93a386Sopenharmony_ci image_type_recognition::kRafImage)) { 716cb93a386Sopenharmony_ci return RafGetOrientation(data, orientation); 717cb93a386Sopenharmony_ci } else { 718cb93a386Sopenharmony_ci return GetExifOrientation(data, 0 /* offset */, orientation); 719cb93a386Sopenharmony_ci } 720cb93a386Sopenharmony_ci} 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_cistd::vector<std::string> SupportedExtensions() { 723cb93a386Sopenharmony_ci return {"ARW", "CR2", "DNG", "NEF", "NRW", "ORF", "PEF", "RAF", "RW2", "SRW"}; 724cb93a386Sopenharmony_ci} 725cb93a386Sopenharmony_ci 726cb93a386Sopenharmony_ci} // namespace piex 727