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