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