1 /*****************************************************************************/ 2 // Copyright 2007-2011 Adobe Systems Incorporated 3 // All Rights Reserved. 4 // 5 // NOTICE: Adobe permits you to use, modify, and distribute this file in 6 // accordance with the terms of the Adobe license agreement accompanying it. 7 /*****************************************************************************/ 8 9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_preview.cpp#1 $ */ 10 /* $DateTime: 2012/05/30 13:28:51 $ */ 11 /* $Change: 832332 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_preview.h" 17 18 #include "dng_assertions.h" 19 #include "dng_image.h" 20 #include "dng_image_writer.h" 21 #include "dng_memory.h" 22 #include "dng_stream.h" 23 #include "dng_tag_codes.h" 24 #include "dng_tag_values.h" 25 26 /*****************************************************************************/ 27 28 class dng_preview_tag_set: public dng_basic_tag_set 29 { 30 31 private: 32 33 tag_string fApplicationNameTag; 34 35 tag_string fApplicationVersionTag; 36 37 tag_string fSettingsNameTag; 38 39 dng_fingerprint fSettingsDigest; 40 41 tag_uint8_ptr fSettingsDigestTag; 42 43 tag_uint32 fColorSpaceTag; 44 45 tag_string fDateTimeTag; 46 47 tag_real64 fRawToPreviewGainTag; 48 49 tag_uint32 fCacheVersionTag; 50 51 public: 52 53 dng_preview_tag_set (dng_tiff_directory &directory, 54 const dng_preview &preview, 55 const dng_ifd &ifd); 56 57 virtual ~dng_preview_tag_set (); 58 59 }; 60 61 /*****************************************************************************/ 62 63 dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory, 64 const dng_preview &preview, 65 const dng_ifd &ifd) 66 67 : dng_basic_tag_set (directory, ifd) 68 69 , fApplicationNameTag (tcPreviewApplicationName, 70 preview.fInfo.fApplicationName, 71 false) 72 73 , fApplicationVersionTag (tcPreviewApplicationVersion, 74 preview.fInfo.fApplicationVersion, 75 false) 76 77 , fSettingsNameTag (tcPreviewSettingsName, 78 preview.fInfo.fSettingsName, 79 false) 80 81 , fSettingsDigest (preview.fInfo.fSettingsDigest) 82 83 , fSettingsDigestTag (tcPreviewSettingsDigest, 84 fSettingsDigest.data, 85 16) 86 87 , fColorSpaceTag (tcPreviewColorSpace, 88 preview.fInfo.fColorSpace) 89 90 , fDateTimeTag (tcPreviewDateTime, 91 preview.fInfo.fDateTime, 92 true) 93 94 , fRawToPreviewGainTag (tcRawToPreviewGain, 95 preview.fInfo.fRawToPreviewGain) 96 97 , fCacheVersionTag (tcCacheVersion, 98 preview.fInfo.fCacheVersion) 99 100 { 101 102 if (preview.fInfo.fApplicationName.NotEmpty ()) 103 { 104 105 directory.Add (&fApplicationNameTag); 106 107 } 108 109 if (preview.fInfo.fApplicationVersion.NotEmpty ()) 110 { 111 112 directory.Add (&fApplicationVersionTag); 113 114 } 115 116 if (preview.fInfo.fSettingsName.NotEmpty ()) 117 { 118 119 directory.Add (&fSettingsNameTag); 120 121 } 122 123 if (preview.fInfo.fSettingsDigest.IsValid ()) 124 { 125 126 directory.Add (&fSettingsDigestTag); 127 128 } 129 130 if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum) 131 { 132 133 directory.Add (&fColorSpaceTag); 134 135 } 136 137 if (preview.fInfo.fDateTime.NotEmpty ()) 138 { 139 140 directory.Add (&fDateTimeTag); 141 142 } 143 144 if (preview.fInfo.fRawToPreviewGain != 1.0) 145 { 146 147 directory.Add (&fRawToPreviewGainTag); 148 149 } 150 151 if (preview.fInfo.fCacheVersion != 0) 152 { 153 154 directory.Add (&fCacheVersionTag); 155 156 } 157 158 } 159 160 /*****************************************************************************/ 161 162 dng_preview_tag_set::~dng_preview_tag_set () 163 { 164 165 } 166 167 /*****************************************************************************/ 168 169 dng_preview::dng_preview () 170 171 : fInfo () 172 173 { 174 175 } 176 177 /*****************************************************************************/ 178 179 dng_preview::~dng_preview () 180 { 181 182 } 183 184 /*****************************************************************************/ 185 186 dng_image_preview::dng_image_preview () 187 188 : fImage () 189 , fIFD () 190 191 { 192 193 } 194 195 /*****************************************************************************/ 196 197 dng_image_preview::~dng_image_preview () 198 { 199 200 } 201 202 /*****************************************************************************/ 203 204 dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const 205 { 206 207 fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage 208 : sfAltPreviewImage; 209 210 fIFD.fImageWidth = fImage->Width (); 211 fIFD.fImageLength = fImage->Height (); 212 213 fIFD.fSamplesPerPixel = fImage->Planes (); 214 215 fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero 216 : piRGB; 217 218 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 219 220 for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) 221 { 222 fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; 223 } 224 225 fIFD.SetSingleStrip (); 226 227 return new dng_preview_tag_set (directory, *this, fIFD); 228 229 } 230 231 /*****************************************************************************/ 232 233 void dng_image_preview::WriteData (dng_host &host, 234 dng_image_writer &writer, 235 dng_basic_tag_set &basic, 236 dng_stream &stream) const 237 { 238 239 writer.WriteImage (host, 240 fIFD, 241 basic, 242 stream, 243 *fImage.Get ()); 244 245 } 246 247 /*****************************************************************************/ 248 249 class dng_jpeg_preview_tag_set: public dng_preview_tag_set 250 { 251 252 private: 253 254 dng_urational fCoefficientsData [3]; 255 256 tag_urational_ptr fCoefficientsTag; 257 258 uint16 fSubSamplingData [2]; 259 260 tag_uint16_ptr fSubSamplingTag; 261 262 tag_uint16 fPositioningTag; 263 264 dng_urational fReferenceData [6]; 265 266 tag_urational_ptr fReferenceTag; 267 268 public: 269 270 dng_jpeg_preview_tag_set (dng_tiff_directory &directory, 271 const dng_jpeg_preview &preview, 272 const dng_ifd &ifd); 273 274 virtual ~dng_jpeg_preview_tag_set (); 275 276 }; 277 278 /******************************************************************************/ 279 280 dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory, 281 const dng_jpeg_preview &preview, 282 const dng_ifd &ifd) 283 284 : dng_preview_tag_set (directory, preview, ifd) 285 286 , fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3) 287 288 , fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2) 289 290 , fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning) 291 292 , fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6) 293 294 { 295 296 if (preview.fPhotometricInterpretation == piYCbCr) 297 { 298 299 fCoefficientsData [0] = dng_urational (299, 1000); 300 fCoefficientsData [1] = dng_urational (587, 1000); 301 fCoefficientsData [2] = dng_urational (114, 1000); 302 303 directory.Add (&fCoefficientsTag); 304 305 fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h; 306 fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v; 307 308 directory.Add (&fSubSamplingTag); 309 310 directory.Add (&fPositioningTag); 311 312 fReferenceData [0] = dng_urational ( 0, 1); 313 fReferenceData [1] = dng_urational (255, 1); 314 fReferenceData [2] = dng_urational (128, 1); 315 fReferenceData [3] = dng_urational (255, 1); 316 fReferenceData [4] = dng_urational (128, 1); 317 fReferenceData [5] = dng_urational (255, 1); 318 319 directory.Add (&fReferenceTag); 320 321 } 322 323 } 324 325 /*****************************************************************************/ 326 327 dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set () 328 { 329 330 } 331 332 /*****************************************************************************/ 333 334 dng_jpeg_preview::dng_jpeg_preview () 335 336 : fPreviewSize () 337 , fPhotometricInterpretation (piYCbCr) 338 , fYCbCrSubSampling (1, 1) 339 , fYCbCrPositioning (2) 340 , fCompressedData () 341 342 { 343 344 } 345 346 /*****************************************************************************/ 347 348 dng_jpeg_preview::~dng_jpeg_preview () 349 { 350 351 } 352 353 /*****************************************************************************/ 354 355 dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const 356 { 357 358 dng_ifd ifd; 359 360 ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage 361 : sfAltPreviewImage; 362 363 ifd.fImageWidth = fPreviewSize.h; 364 ifd.fImageLength = fPreviewSize.v; 365 366 ifd.fPhotometricInterpretation = fPhotometricInterpretation; 367 368 ifd.fBitsPerSample [0] = 8; 369 ifd.fBitsPerSample [1] = 8; 370 ifd.fBitsPerSample [2] = 8; 371 372 ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3); 373 374 ifd.fCompression = ccJPEG; 375 ifd.fPredictor = cpNullPredictor; 376 377 ifd.SetSingleStrip (); 378 379 return new dng_jpeg_preview_tag_set (directory, *this, ifd); 380 381 } 382 383 /*****************************************************************************/ 384 385 void dng_jpeg_preview::WriteData (dng_host & /* host */, 386 dng_image_writer & /* writer */, 387 dng_basic_tag_set &basic, 388 dng_stream &stream) const 389 { 390 391 basic.SetTileOffset (0, (uint32) stream.Position ()); 392 393 basic.SetTileByteCount (0, fCompressedData->LogicalSize ()); 394 395 stream.Put (fCompressedData->Buffer (), 396 fCompressedData->LogicalSize ()); 397 398 if (fCompressedData->LogicalSize () & 1) 399 { 400 stream.Put_uint8 (0); 401 } 402 403 } 404 405 /*****************************************************************************/ 406 407 void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const 408 { 409 410 DNG_ASSERT (fCompressedData.Get (), 411 "SpoolAdobeThumbnail: no data"); 412 413 DNG_ASSERT (fPhotometricInterpretation == piYCbCr, 414 "SpoolAdobeThumbnail: Non-YCbCr"); 415 416 uint32 compressedSize = fCompressedData->LogicalSize (); 417 418 stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); 419 stream.Put_uint16 (1036); 420 stream.Put_uint16 (0); 421 422 stream.Put_uint32 (compressedSize + 28); 423 424 uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4; 425 426 stream.Put_uint32 (1); 427 stream.Put_uint32 (fPreviewSize.h); 428 stream.Put_uint32 (fPreviewSize.v); 429 stream.Put_uint32 (widthBytes); 430 stream.Put_uint32 (widthBytes * fPreviewSize.v); 431 stream.Put_uint32 (compressedSize); 432 stream.Put_uint16 (24); 433 stream.Put_uint16 (1); 434 435 stream.Put (fCompressedData->Buffer (), 436 compressedSize); 437 438 if (compressedSize & 1) 439 { 440 stream.Put_uint8 (0); 441 } 442 443 } 444 445 /*****************************************************************************/ 446 447 class dng_raw_preview_tag_set: public dng_preview_tag_set 448 { 449 450 private: 451 452 tag_data_ptr fOpcodeList2Tag; 453 454 tag_uint32_ptr fWhiteLevelTag; 455 456 uint32 fWhiteLevelData [kMaxColorPlanes]; 457 458 public: 459 460 dng_raw_preview_tag_set (dng_tiff_directory &directory, 461 const dng_raw_preview &preview, 462 const dng_ifd &ifd); 463 464 virtual ~dng_raw_preview_tag_set (); 465 466 }; 467 468 /*****************************************************************************/ 469 470 dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory, 471 const dng_raw_preview &preview, 472 const dng_ifd &ifd) 473 474 : dng_preview_tag_set (directory, preview, ifd) 475 476 , fOpcodeList2Tag (tcOpcodeList2, 477 ttUndefined, 478 0, 479 NULL) 480 481 , fWhiteLevelTag (tcWhiteLevel, 482 fWhiteLevelData, 483 preview.fImage->Planes ()) 484 485 { 486 487 if (preview.fOpcodeList2Data.Get ()) 488 { 489 490 fOpcodeList2Tag.SetData (preview.fOpcodeList2Data->Buffer ()); 491 fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ()); 492 493 directory.Add (&fOpcodeList2Tag); 494 495 } 496 497 if (preview.fImage->PixelType () == ttFloat) 498 { 499 500 for (uint32 j = 0; j < kMaxColorPlanes; j++) 501 { 502 fWhiteLevelData [j] = 32768; 503 } 504 505 directory.Add (&fWhiteLevelTag); 506 507 } 508 509 } 510 511 /*****************************************************************************/ 512 513 dng_raw_preview_tag_set::~dng_raw_preview_tag_set () 514 { 515 516 } 517 518 /*****************************************************************************/ 519 520 dng_raw_preview::dng_raw_preview () 521 522 : fImage () 523 , fOpcodeList2Data () 524 , fCompressionQuality (-1) 525 , fIFD () 526 527 { 528 529 } 530 531 /*****************************************************************************/ 532 533 dng_raw_preview::~dng_raw_preview () 534 { 535 536 } 537 538 /*****************************************************************************/ 539 540 dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const 541 { 542 543 fIFD.fNewSubFileType = sfPreviewImage; 544 545 fIFD.fImageWidth = fImage->Width (); 546 fIFD.fImageLength = fImage->Height (); 547 548 fIFD.fSamplesPerPixel = fImage->Planes (); 549 550 fIFD.fPhotometricInterpretation = piLinearRaw; 551 552 if (fImage->PixelType () == ttFloat) 553 { 554 555 fIFD.fCompression = ccDeflate; 556 557 fIFD.fCompressionQuality = fCompressionQuality; 558 559 fIFD.fPredictor = cpFloatingPoint; 560 561 for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++) 562 { 563 fIFD.fBitsPerSample [j] = 16; 564 fIFD.fSampleFormat [j] = sfFloatingPoint; 565 } 566 567 fIFD.FindTileSize (512 * 1024); 568 569 } 570 571 else 572 { 573 574 fIFD.fCompression = ccLossyJPEG; 575 576 fIFD.fCompressionQuality = fCompressionQuality; 577 578 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 579 580 for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) 581 { 582 fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; 583 } 584 585 fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); 586 587 } 588 589 return new dng_raw_preview_tag_set (directory, *this, fIFD); 590 591 } 592 593 /*****************************************************************************/ 594 595 void dng_raw_preview::WriteData (dng_host &host, 596 dng_image_writer &writer, 597 dng_basic_tag_set &basic, 598 dng_stream &stream) const 599 { 600 601 writer.WriteImage (host, 602 fIFD, 603 basic, 604 stream, 605 *fImage.Get ()); 606 607 } 608 609 /*****************************************************************************/ 610 611 dng_mask_preview::dng_mask_preview () 612 613 : fImage () 614 , fCompressionQuality (-1) 615 , fIFD () 616 617 { 618 619 } 620 621 /*****************************************************************************/ 622 623 dng_mask_preview::~dng_mask_preview () 624 { 625 626 } 627 628 /*****************************************************************************/ 629 630 dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const 631 { 632 633 fIFD.fNewSubFileType = sfPreviewMask; 634 635 fIFD.fImageWidth = fImage->Width (); 636 fIFD.fImageLength = fImage->Height (); 637 638 fIFD.fSamplesPerPixel = 1; 639 640 fIFD.fPhotometricInterpretation = piTransparencyMask; 641 642 fIFD.fCompression = ccDeflate; 643 fIFD.fPredictor = cpHorizontalDifference; 644 645 fIFD.fCompressionQuality = fCompressionQuality; 646 647 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 648 649 fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); 650 651 return new dng_basic_tag_set (directory, fIFD); 652 653 } 654 655 /*****************************************************************************/ 656 657 void dng_mask_preview::WriteData (dng_host &host, 658 dng_image_writer &writer, 659 dng_basic_tag_set &basic, 660 dng_stream &stream) const 661 { 662 663 writer.WriteImage (host, 664 fIFD, 665 basic, 666 stream, 667 *fImage.Get ()); 668 669 } 670 671 /*****************************************************************************/ 672 673 dng_preview_list::dng_preview_list () 674 675 : fCount (0) 676 677 { 678 679 } 680 681 /*****************************************************************************/ 682 683 dng_preview_list::~dng_preview_list () 684 { 685 686 } 687 688 /*****************************************************************************/ 689 690 void dng_preview_list::Append (AutoPtr<dng_preview> &preview) 691 { 692 693 if (preview.Get ()) 694 { 695 696 DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow"); 697 698 if (fCount < kMaxDNGPreviews) 699 { 700 701 fPreview [fCount++] . Reset (preview.Release ()); 702 703 } 704 705 } 706 707 } 708 709 /*****************************************************************************/ 710