1 /*****************************************************************************/ 2 // Copyright 2006-2012 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_image_writer.cpp#4 $ */ 10 /* $DateTime: 2012/06/14 20:24:41 $ */ 11 /* $Change: 835078 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_image_writer.h" 17 18 #include "dng_abort_sniffer.h" 19 #include "dng_area_task.h" 20 #include "dng_bottlenecks.h" 21 #include "dng_camera_profile.h" 22 #include "dng_color_space.h" 23 #include "dng_exif.h" 24 #include "dng_flags.h" 25 #include "dng_exceptions.h" 26 #include "dng_host.h" 27 #include "dng_ifd.h" 28 #include "dng_image.h" 29 #include "dng_jpeg_image.h" 30 #include "dng_lossless_jpeg.h" 31 #include "dng_memory.h" 32 #include "dng_memory_stream.h" 33 #include "dng_negative.h" 34 #include "dng_pixel_buffer.h" 35 #include "dng_preview.h" 36 #include "dng_read_image.h" 37 #include "dng_safe_arithmetic.h" 38 #include "dng_stream.h" 39 #include "dng_string_list.h" 40 #include "dng_tag_codes.h" 41 #include "dng_tag_values.h" 42 #include "dng_utils.h" 43 44 #if qDNGUseXMP 45 #include "dng_xmp.h" 46 #endif 47 48 #include "zlib.h" 49 50 #if qDNGUseLibJPEG 51 #include "dng_jpeglib.h" 52 #endif 53 54 /*****************************************************************************/ 55 56 // Defines for testing DNG 1.2 features. 57 58 //#define qTestRowInterleave 2 59 60 //#define qTestSubTileBlockRows 2 61 //#define qTestSubTileBlockCols 2 62 63 /*****************************************************************************/ 64 65 dng_resolution::dng_resolution () 66 67 : fXResolution () 68 , fYResolution () 69 70 , fResolutionUnit (0) 71 72 { 73 74 } 75 76 /******************************************************************************/ 77 78 static void SpoolAdobeData (dng_stream &stream, 79 const dng_metadata *metadata, 80 const dng_jpeg_preview *preview, 81 const dng_memory_block *imageResources) 82 { 83 84 TempBigEndian tempEndian (stream); 85 86 #if qDNGUseXMP 87 88 if (metadata && metadata->GetXMP ()) 89 { 90 91 bool marked = false; 92 93 if (metadata->GetXMP ()->GetBoolean (XMP_NS_XAP_RIGHTS, 94 "Marked", 95 marked)) 96 { 97 98 stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); 99 stream.Put_uint16 (1034); 100 stream.Put_uint16 (0); 101 102 stream.Put_uint32 (1); 103 104 stream.Put_uint8 (marked ? 1 : 0); 105 106 stream.Put_uint8 (0); 107 108 } 109 110 dng_string webStatement; 111 112 if (metadata->GetXMP ()->GetString (XMP_NS_XAP_RIGHTS, 113 "WebStatement", 114 webStatement)) 115 { 116 117 dng_memory_data buffer; 118 119 uint32 size = webStatement.Get_SystemEncoding (buffer); 120 121 if (size > 0) 122 { 123 124 stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); 125 stream.Put_uint16 (1035); 126 stream.Put_uint16 (0); 127 128 stream.Put_uint32 (size); 129 130 stream.Put (buffer.Buffer (), size); 131 132 if (size & 1) 133 stream.Put_uint8 (0); 134 135 } 136 137 } 138 139 } 140 141 #endif 142 143 if (preview) 144 { 145 146 preview->SpoolAdobeThumbnail (stream); 147 148 } 149 150 if (metadata && metadata->IPTCLength ()) 151 { 152 153 dng_fingerprint iptcDigest = metadata->IPTCDigest (); 154 155 if (iptcDigest.IsValid ()) 156 { 157 158 stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); 159 stream.Put_uint16 (1061); 160 stream.Put_uint16 (0); 161 162 stream.Put_uint32 (16); 163 164 stream.Put (iptcDigest.data, 16); 165 166 } 167 168 } 169 170 if (imageResources) 171 { 172 173 uint32 size = imageResources->LogicalSize (); 174 175 stream.Put (imageResources->Buffer (), size); 176 177 if (size & 1) 178 stream.Put_uint8 (0); 179 180 } 181 182 } 183 184 /******************************************************************************/ 185 186 static dng_memory_block * BuildAdobeData (dng_host &host, 187 const dng_metadata *metadata, 188 const dng_jpeg_preview *preview, 189 const dng_memory_block *imageResources) 190 { 191 192 dng_memory_stream stream (host.Allocator ()); 193 194 SpoolAdobeData (stream, 195 metadata, 196 preview, 197 imageResources); 198 199 return stream.AsMemoryBlock (host.Allocator ()); 200 201 } 202 203 /*****************************************************************************/ 204 205 tag_string::tag_string (uint16 code, 206 const dng_string &s, 207 bool forceASCII) 208 209 : tiff_tag (code, ttAscii, 0) 210 211 , fString (s) 212 213 { 214 215 if (forceASCII) 216 { 217 218 // Metadata working group recommendation - go ahead 219 // write UTF-8 into ASCII tag strings, rather than 220 // actually force the strings to ASCII. There is a matching 221 // change on the reading side to assume UTF-8 if the string 222 // contains a valid UTF-8 string. 223 // 224 // fString.ForceASCII (); 225 226 } 227 228 else if (!fString.IsASCII ()) 229 { 230 231 fType = ttByte; 232 233 } 234 235 fCount = fString.Length () + 1; 236 237 } 238 239 /*****************************************************************************/ 240 241 void tag_string::Put (dng_stream &stream) const 242 { 243 244 stream.Put (fString.Get (), Size ()); 245 246 } 247 248 /*****************************************************************************/ 249 250 tag_encoded_text::tag_encoded_text (uint16 code, 251 const dng_string &text) 252 253 : tiff_tag (code, ttUndefined, 0) 254 255 , fText (text) 256 257 , fUTF16 () 258 259 { 260 261 if (fText.IsASCII ()) 262 { 263 264 fCount = 8 + fText.Length (); 265 266 } 267 268 else 269 { 270 271 fCount = 8 + fText.Get_UTF16 (fUTF16) * 2; 272 273 } 274 275 } 276 277 /*****************************************************************************/ 278 279 void tag_encoded_text::Put (dng_stream &stream) const 280 { 281 282 if (fUTF16.Buffer ()) 283 { 284 285 stream.Put ("UNICODE\000", 8); 286 287 uint32 chars = (fCount - 8) >> 1; 288 289 const uint16 *buf = fUTF16.Buffer_uint16 (); 290 291 for (uint32 j = 0; j < chars; j++) 292 { 293 294 stream.Put_uint16 (buf [j]); 295 296 } 297 298 } 299 300 else 301 { 302 303 stream.Put ("ASCII\000\000\000", 8); 304 305 stream.Put (fText.Get (), fCount - 8); 306 307 } 308 309 } 310 311 /*****************************************************************************/ 312 313 void tag_data_ptr::Put (dng_stream &stream) const 314 { 315 316 // If we are swapping bytes, we need to swap with the right size 317 // entries. 318 319 if (stream.SwapBytes ()) 320 { 321 322 switch (Type ()) 323 { 324 325 // Two byte entries. 326 327 case ttShort: 328 case ttSShort: 329 case ttUnicode: 330 { 331 332 const uint16 *p = (const uint16 *) fData; 333 334 uint32 entries = (Size () >> 1); 335 336 for (uint32 j = 0; j < entries; j++) 337 { 338 339 stream.Put_uint16 (p [j]); 340 341 } 342 343 return; 344 345 } 346 347 // Four byte entries. 348 349 case ttLong: 350 case ttSLong: 351 case ttRational: 352 case ttSRational: 353 case ttIFD: 354 case ttFloat: 355 case ttComplex: 356 { 357 358 const uint32 *p = (const uint32 *) fData; 359 360 uint32 entries = (Size () >> 2); 361 362 for (uint32 j = 0; j < entries; j++) 363 { 364 365 stream.Put_uint32 (p [j]); 366 367 } 368 369 return; 370 371 } 372 373 // Eight byte entries. 374 375 case ttDouble: 376 { 377 378 const real64 *p = (const real64 *) fData; 379 380 uint32 entries = (Size () >> 3); 381 382 for (uint32 j = 0; j < entries; j++) 383 { 384 385 stream.Put_real64 (p [j]); 386 387 } 388 389 return; 390 391 } 392 393 // Entries don't need to be byte swapped. Fall through 394 // to non-byte swapped case. 395 396 default: 397 { 398 399 break; 400 401 } 402 403 } 404 405 } 406 407 // Non-byte swapped case. 408 409 stream.Put (fData, Size ()); 410 411 } 412 413 /******************************************************************************/ 414 415 tag_matrix::tag_matrix (uint16 code, 416 const dng_matrix &m) 417 418 : tag_srational_ptr (code, fEntry, m.Rows () * m.Cols ()) 419 420 { 421 422 uint32 index = 0; 423 424 for (uint32 r = 0; r < m.Rows (); r++) 425 for (uint32 c = 0; c < m.Cols (); c++) 426 { 427 428 fEntry [index].Set_real64 (m [r] [c], 10000); 429 430 index++; 431 432 } 433 434 } 435 436 /******************************************************************************/ 437 438 tag_icc_profile::tag_icc_profile (const void *profileData, 439 uint32 profileSize) 440 441 : tag_data_ptr (tcICCProfile, 442 ttUndefined, 443 0, 444 NULL) 445 446 { 447 448 if (profileData && profileSize) 449 { 450 451 SetCount (profileSize); 452 SetData (profileData); 453 454 } 455 456 } 457 458 /******************************************************************************/ 459 460 void tag_cfa_pattern::Put (dng_stream &stream) const 461 { 462 463 stream.Put_uint16 ((uint16) fCols); 464 stream.Put_uint16 ((uint16) fRows); 465 466 for (uint32 col = 0; col < fCols; col++) 467 for (uint32 row = 0; row < fRows; row++) 468 { 469 470 stream.Put_uint8 (fPattern [row * kMaxCFAPattern + col]); 471 472 } 473 474 } 475 476 /******************************************************************************/ 477 478 tag_exif_date_time::tag_exif_date_time (uint16 code, 479 const dng_date_time &dt) 480 481 : tag_data_ptr (code, ttAscii, 20, fData) 482 483 { 484 485 if (dt.IsValid ()) 486 { 487 488 sprintf (fData, 489 "%04d:%02d:%02d %02d:%02d:%02d", 490 (int) dt.fYear, 491 (int) dt.fMonth, 492 (int) dt.fDay, 493 (int) dt.fHour, 494 (int) dt.fMinute, 495 (int) dt.fSecond); 496 497 } 498 499 } 500 501 /******************************************************************************/ 502 503 tag_iptc::tag_iptc (const void *data, 504 uint32 length) 505 506 : tiff_tag (tcIPTC_NAA, ttLong, (length + 3) >> 2) 507 508 , fData (data ) 509 , fLength (length) 510 511 { 512 513 } 514 515 /******************************************************************************/ 516 517 void tag_iptc::Put (dng_stream &stream) const 518 { 519 520 // Note: For historical compatiblity reasons, the standard TIFF data 521 // type for IPTC data is ttLong, but without byte swapping. This really 522 // should be ttUndefined, but doing the right thing would break some 523 // existing readers. 524 525 stream.Put (fData, fLength); 526 527 // Pad with zeros to get to long word boundary. 528 529 uint32 extra = fCount * 4 - fLength; 530 531 while (extra--) 532 { 533 stream.Put_uint8 (0); 534 } 535 536 } 537 538 /******************************************************************************/ 539 540 tag_xmp::tag_xmp (const dng_xmp *xmp) 541 542 : tag_uint8_ptr (tcXMP, NULL, 0) 543 544 , fBuffer () 545 546 { 547 548 #if qDNGUseXMP 549 550 if (xmp) 551 { 552 553 fBuffer.Reset (xmp->Serialize (true)); 554 555 if (fBuffer.Get ()) 556 { 557 558 SetData (fBuffer->Buffer_uint8 ()); 559 560 SetCount (fBuffer->LogicalSize ()); 561 562 } 563 564 } 565 566 #endif 567 568 } 569 570 /******************************************************************************/ 571 572 void dng_tiff_directory::Add (const tiff_tag *tag) 573 { 574 575 if (fEntries >= kMaxEntries) 576 { 577 ThrowProgramError (); 578 } 579 580 // Tags must be sorted in increasing order of tag code. 581 582 uint32 index = fEntries; 583 584 for (uint32 j = 0; j < fEntries; j++) 585 { 586 587 if (tag->Code () < fTag [j]->Code ()) 588 { 589 index = j; 590 break; 591 } 592 593 } 594 595 for (uint32 k = fEntries; k > index; k--) 596 { 597 598 fTag [k] = fTag [k - 1]; 599 600 } 601 602 fTag [index] = tag; 603 604 fEntries++; 605 606 } 607 608 /******************************************************************************/ 609 610 uint32 dng_tiff_directory::Size () const 611 { 612 613 if (!fEntries) return 0; 614 615 uint32 size = fEntries * 12 + 6; 616 617 for (uint32 index = 0; index < fEntries; index++) 618 { 619 620 uint32 tagSize = fTag [index]->Size (); 621 622 if (tagSize > 4) 623 { 624 625 size += (tagSize + 1) & ~1; 626 627 } 628 629 } 630 631 return size; 632 633 } 634 635 /******************************************************************************/ 636 637 void dng_tiff_directory::Put (dng_stream &stream, 638 OffsetsBase offsetsBase, 639 uint32 explicitBase) const 640 { 641 642 if (!fEntries) return; 643 644 uint32 index; 645 646 uint32 bigData = fEntries * 12 + 6; 647 648 if (offsetsBase == offsetsRelativeToStream) 649 bigData += (uint32) stream.Position (); 650 651 else if (offsetsBase == offsetsRelativeToExplicitBase) 652 bigData += explicitBase; 653 654 stream.Put_uint16 ((uint16) fEntries); 655 656 for (index = 0; index < fEntries; index++) 657 { 658 659 const tiff_tag &tag = *fTag [index]; 660 661 stream.Put_uint16 (tag.Code ()); 662 stream.Put_uint16 (tag.Type ()); 663 stream.Put_uint32 (tag.Count ()); 664 665 uint32 size = tag.Size (); 666 667 if (size <= 4) 668 { 669 670 tag.Put (stream); 671 672 while (size < 4) 673 { 674 stream.Put_uint8 (0); 675 size++; 676 } 677 678 } 679 680 else 681 { 682 683 stream.Put_uint32 (bigData); 684 685 bigData += (size + 1) & ~1; 686 687 } 688 689 } 690 691 stream.Put_uint32 (fChained); // Next IFD offset 692 693 for (index = 0; index < fEntries; index++) 694 { 695 696 const tiff_tag &tag = *fTag [index]; 697 698 uint32 size = tag.Size (); 699 700 if (size > 4) 701 { 702 703 tag.Put (stream); 704 705 if (size & 1) 706 stream.Put_uint8 (0); 707 708 } 709 710 } 711 712 } 713 714 /******************************************************************************/ 715 716 dng_basic_tag_set::dng_basic_tag_set (dng_tiff_directory &directory, 717 const dng_ifd &info) 718 719 : fNewSubFileType (tcNewSubFileType, info.fNewSubFileType) 720 721 , fImageWidth (tcImageWidth , info.fImageWidth ) 722 , fImageLength (tcImageLength, info.fImageLength) 723 724 , fPhotoInterpretation (tcPhotometricInterpretation, 725 (uint16) info.fPhotometricInterpretation) 726 727 , fFillOrder (tcFillOrder, 1) 728 729 , fSamplesPerPixel (tcSamplesPerPixel, (uint16) info.fSamplesPerPixel) 730 731 , fBitsPerSample (tcBitsPerSample, 732 fBitsPerSampleData, 733 info.fSamplesPerPixel) 734 735 , fStrips (info.fUsesStrips) 736 737 , fTileWidth (tcTileWidth, info.fTileWidth) 738 739 , fTileLength (fStrips ? tcRowsPerStrip : tcTileLength, 740 info.fTileLength) 741 742 , fTileInfoBuffer (info.TilesPerImage (), 8) 743 744 , fTileOffsetData (fTileInfoBuffer.Buffer_uint32 ()) 745 746 , fTileOffsets (fStrips ? tcStripOffsets : tcTileOffsets, 747 fTileOffsetData, 748 info.TilesPerImage ()) 749 750 , fTileByteCountData (fTileOffsetData + info.TilesPerImage ()) 751 752 , fTileByteCounts (fStrips ? tcStripByteCounts : tcTileByteCounts, 753 fTileByteCountData, 754 info.TilesPerImage ()) 755 756 , fPlanarConfiguration (tcPlanarConfiguration, pcInterleaved) 757 758 , fCompression (tcCompression, (uint16) info.fCompression) 759 , fPredictor (tcPredictor , (uint16) info.fPredictor ) 760 761 , fExtraSamples (tcExtraSamples, 762 fExtraSamplesData, 763 info.fExtraSamplesCount) 764 765 , fSampleFormat (tcSampleFormat, 766 fSampleFormatData, 767 info.fSamplesPerPixel) 768 769 , fRowInterleaveFactor (tcRowInterleaveFactor, 770 (uint16) info.fRowInterleaveFactor) 771 772 , fSubTileBlockSize (tcSubTileBlockSize, 773 fSubTileBlockSizeData, 774 2) 775 776 { 777 778 uint32 j; 779 780 for (j = 0; j < info.fSamplesPerPixel; j++) 781 { 782 783 fBitsPerSampleData [j] = (uint16) info.fBitsPerSample [0]; 784 785 } 786 787 directory.Add (&fNewSubFileType); 788 789 directory.Add (&fImageWidth); 790 directory.Add (&fImageLength); 791 792 directory.Add (&fPhotoInterpretation); 793 794 directory.Add (&fSamplesPerPixel); 795 796 directory.Add (&fBitsPerSample); 797 798 if (info.fBitsPerSample [0] != 8 && 799 info.fBitsPerSample [0] != 16 && 800 info.fBitsPerSample [0] != 32) 801 { 802 803 directory.Add (&fFillOrder); 804 805 } 806 807 if (!fStrips) 808 { 809 810 directory.Add (&fTileWidth); 811 812 } 813 814 directory.Add (&fTileLength); 815 816 directory.Add (&fTileOffsets); 817 directory.Add (&fTileByteCounts); 818 819 directory.Add (&fPlanarConfiguration); 820 821 directory.Add (&fCompression); 822 823 if (info.fPredictor != cpNullPredictor) 824 { 825 826 directory.Add (&fPredictor); 827 828 } 829 830 if (info.fExtraSamplesCount != 0) 831 { 832 833 for (j = 0; j < info.fExtraSamplesCount; j++) 834 { 835 fExtraSamplesData [j] = (uint16) info.fExtraSamples [j]; 836 } 837 838 directory.Add (&fExtraSamples); 839 840 } 841 842 if (info.fSampleFormat [0] != sfUnsignedInteger) 843 { 844 845 for (j = 0; j < info.fSamplesPerPixel; j++) 846 { 847 fSampleFormatData [j] = (uint16) info.fSampleFormat [j]; 848 } 849 850 directory.Add (&fSampleFormat); 851 852 } 853 854 if (info.fRowInterleaveFactor != 1) 855 { 856 857 directory.Add (&fRowInterleaveFactor); 858 859 } 860 861 if (info.fSubTileBlockRows != 1 || 862 info.fSubTileBlockCols != 1) 863 { 864 865 fSubTileBlockSizeData [0] = (uint16) info.fSubTileBlockRows; 866 fSubTileBlockSizeData [1] = (uint16) info.fSubTileBlockCols; 867 868 directory.Add (&fSubTileBlockSize); 869 870 } 871 872 } 873 874 /******************************************************************************/ 875 876 exif_tag_set::exif_tag_set (dng_tiff_directory &directory, 877 const dng_exif &exif, 878 bool makerNoteSafe, 879 const void *makerNoteData, 880 uint32 makerNoteLength, 881 bool insideDNG) 882 883 : fExifIFD () 884 , fGPSIFD () 885 886 , fExifLink (tcExifIFD, 0) 887 , fGPSLink (tcGPSInfo, 0) 888 889 , fAddedExifLink (false) 890 , fAddedGPSLink (false) 891 892 , fExifVersion (tcExifVersion, ttUndefined, 4, fExifVersionData) 893 894 , fExposureTime (tcExposureTime , exif.fExposureTime ) 895 , fShutterSpeedValue (tcShutterSpeedValue, exif.fShutterSpeedValue) 896 897 , fFNumber (tcFNumber , exif.fFNumber ) 898 , fApertureValue (tcApertureValue, exif.fApertureValue) 899 900 , fBrightnessValue (tcBrightnessValue, exif.fBrightnessValue) 901 902 , fExposureBiasValue (tcExposureBiasValue, exif.fExposureBiasValue) 903 904 , fMaxApertureValue (tcMaxApertureValue , exif.fMaxApertureValue) 905 906 , fSubjectDistance (tcSubjectDistance, exif.fSubjectDistance) 907 908 , fFocalLength (tcFocalLength, exif.fFocalLength) 909 910 // Special case: the EXIF 2.2 standard represents ISO speed ratings with 2 bytes, 911 // which cannot hold ISO speed ratings above 65535 (e.g., 102400). In these 912 // cases, we write the maximum representable ISO speed rating value in the EXIF 913 // tag, i.e., 65535. 914 915 , fISOSpeedRatings (tcISOSpeedRatings, 916 (uint16) Min_uint32 (65535, 917 exif.fISOSpeedRatings [0])) 918 919 , fSensitivityType (tcSensitivityType, (uint16) exif.fSensitivityType) 920 921 , fStandardOutputSensitivity (tcStandardOutputSensitivity, exif.fStandardOutputSensitivity) 922 923 , fRecommendedExposureIndex (tcRecommendedExposureIndex, exif.fRecommendedExposureIndex) 924 925 , fISOSpeed (tcISOSpeed, exif.fISOSpeed) 926 927 , fISOSpeedLatitudeyyy (tcISOSpeedLatitudeyyy, exif.fISOSpeedLatitudeyyy) 928 929 , fISOSpeedLatitudezzz (tcISOSpeedLatitudezzz, exif.fISOSpeedLatitudezzz) 930 931 , fFlash (tcFlash, (uint16) exif.fFlash) 932 933 , fExposureProgram (tcExposureProgram, (uint16) exif.fExposureProgram) 934 935 , fMeteringMode (tcMeteringMode, (uint16) exif.fMeteringMode) 936 937 , fLightSource (tcLightSource, (uint16) exif.fLightSource) 938 939 , fSensingMethod (tcSensingMethodExif, (uint16) exif.fSensingMethod) 940 941 , fFocalLength35mm (tcFocalLengthIn35mmFilm, (uint16) exif.fFocalLengthIn35mmFilm) 942 943 , fFileSourceData ((uint8) exif.fFileSource) 944 , fFileSource (tcFileSource, ttUndefined, 1, &fFileSourceData) 945 946 , fSceneTypeData ((uint8) exif.fSceneType) 947 , fSceneType (tcSceneType, ttUndefined, 1, &fSceneTypeData) 948 949 , fCFAPattern (tcCFAPatternExif, 950 exif.fCFARepeatPatternRows, 951 exif.fCFARepeatPatternCols, 952 &exif.fCFAPattern [0] [0]) 953 954 , fCustomRendered (tcCustomRendered , (uint16) exif.fCustomRendered ) 955 , fExposureMode (tcExposureMode , (uint16) exif.fExposureMode ) 956 , fWhiteBalance (tcWhiteBalance , (uint16) exif.fWhiteBalance ) 957 , fSceneCaptureType (tcSceneCaptureType , (uint16) exif.fSceneCaptureType ) 958 , fGainControl (tcGainControl , (uint16) exif.fGainControl ) 959 , fContrast (tcContrast , (uint16) exif.fContrast ) 960 , fSaturation (tcSaturation , (uint16) exif.fSaturation ) 961 , fSharpness (tcSharpness , (uint16) exif.fSharpness ) 962 , fSubjectDistanceRange (tcSubjectDistanceRange, (uint16) exif.fSubjectDistanceRange) 963 964 , fDigitalZoomRatio (tcDigitalZoomRatio, exif.fDigitalZoomRatio) 965 966 , fExposureIndex (tcExposureIndexExif, exif.fExposureIndex) 967 968 , fImageNumber (tcImageNumber, exif.fImageNumber) 969 970 , fSelfTimerMode (tcSelfTimerMode, (uint16) exif.fSelfTimerMode) 971 972 , fBatteryLevelA (tcBatteryLevel, exif.fBatteryLevelA) 973 , fBatteryLevelR (tcBatteryLevel, exif.fBatteryLevelR) 974 975 , fFocalPlaneXResolution (tcFocalPlaneXResolutionExif, exif.fFocalPlaneXResolution) 976 , fFocalPlaneYResolution (tcFocalPlaneYResolutionExif, exif.fFocalPlaneYResolution) 977 978 , fFocalPlaneResolutionUnit (tcFocalPlaneResolutionUnitExif, (uint16) exif.fFocalPlaneResolutionUnit) 979 980 , fSubjectArea (tcSubjectArea, fSubjectAreaData, exif.fSubjectAreaCount) 981 982 , fLensInfo (tcLensInfo, fLensInfoData, 4) 983 984 , fDateTime (tcDateTime , exif.fDateTime .DateTime ()) 985 , fDateTimeOriginal (tcDateTimeOriginal , exif.fDateTimeOriginal .DateTime ()) 986 , fDateTimeDigitized (tcDateTimeDigitized, exif.fDateTimeDigitized.DateTime ()) 987 988 , fSubsecTime (tcSubsecTime, exif.fDateTime .Subseconds ()) 989 , fSubsecTimeOriginal (tcSubsecTimeOriginal, exif.fDateTimeOriginal .Subseconds ()) 990 , fSubsecTimeDigitized (tcSubsecTimeDigitized, exif.fDateTimeDigitized.Subseconds ()) 991 992 , fMake (tcMake, exif.fMake) 993 994 , fModel (tcModel, exif.fModel) 995 996 , fArtist (tcArtist, exif.fArtist) 997 998 , fSoftware (tcSoftware, exif.fSoftware) 999 1000 , fCopyright (tcCopyright, exif.fCopyright) 1001 1002 , fMakerNoteSafety (tcMakerNoteSafety, makerNoteSafe ? 1 : 0) 1003 1004 , fMakerNote (tcMakerNote, ttUndefined, makerNoteLength, makerNoteData) 1005 1006 , fImageDescription (tcImageDescription, exif.fImageDescription) 1007 1008 , fSerialNumber (tcCameraSerialNumber, exif.fCameraSerialNumber) 1009 1010 , fUserComment (tcUserComment, exif.fUserComment) 1011 1012 , fImageUniqueID (tcImageUniqueID, ttAscii, 33, fImageUniqueIDData) 1013 1014 // EXIF 2.3 tags. 1015 1016 , fCameraOwnerName (tcCameraOwnerNameExif, exif.fOwnerName ) 1017 , fBodySerialNumber (tcCameraSerialNumberExif, exif.fCameraSerialNumber) 1018 , fLensSpecification (tcLensSpecificationExif, fLensInfoData, 4 ) 1019 , fLensMake (tcLensMakeExif, exif.fLensMake ) 1020 , fLensModel (tcLensModelExif, exif.fLensName ) 1021 , fLensSerialNumber (tcLensSerialNumberExif, exif.fLensSerialNumber ) 1022 1023 , fGPSVersionID (tcGPSVersionID, fGPSVersionData, 4) 1024 1025 , fGPSLatitudeRef (tcGPSLatitudeRef, exif.fGPSLatitudeRef) 1026 , fGPSLatitude (tcGPSLatitude, exif.fGPSLatitude, 3) 1027 1028 , fGPSLongitudeRef (tcGPSLongitudeRef, exif.fGPSLongitudeRef) 1029 , fGPSLongitude (tcGPSLongitude, exif.fGPSLongitude, 3) 1030 1031 , fGPSAltitudeRef (tcGPSAltitudeRef, (uint8) exif.fGPSAltitudeRef) 1032 , fGPSAltitude (tcGPSAltitude, exif.fGPSAltitude ) 1033 1034 , fGPSTimeStamp (tcGPSTimeStamp, exif.fGPSTimeStamp, 3) 1035 1036 , fGPSSatellites (tcGPSSatellites , exif.fGPSSatellites ) 1037 , fGPSStatus (tcGPSStatus , exif.fGPSStatus ) 1038 , fGPSMeasureMode (tcGPSMeasureMode, exif.fGPSMeasureMode) 1039 1040 , fGPSDOP (tcGPSDOP, exif.fGPSDOP) 1041 1042 , fGPSSpeedRef (tcGPSSpeedRef, exif.fGPSSpeedRef) 1043 , fGPSSpeed (tcGPSSpeed , exif.fGPSSpeed ) 1044 1045 , fGPSTrackRef (tcGPSTrackRef, exif.fGPSTrackRef) 1046 , fGPSTrack (tcGPSTrack , exif.fGPSTrack ) 1047 1048 , fGPSImgDirectionRef (tcGPSImgDirectionRef, exif.fGPSImgDirectionRef) 1049 , fGPSImgDirection (tcGPSImgDirection , exif.fGPSImgDirection ) 1050 1051 , fGPSMapDatum (tcGPSMapDatum, exif.fGPSMapDatum) 1052 1053 , fGPSDestLatitudeRef (tcGPSDestLatitudeRef, exif.fGPSDestLatitudeRef) 1054 , fGPSDestLatitude (tcGPSDestLatitude, exif.fGPSDestLatitude, 3) 1055 1056 , fGPSDestLongitudeRef (tcGPSDestLongitudeRef, exif.fGPSDestLongitudeRef) 1057 , fGPSDestLongitude (tcGPSDestLongitude, exif.fGPSDestLongitude, 3) 1058 1059 , fGPSDestBearingRef (tcGPSDestBearingRef, exif.fGPSDestBearingRef) 1060 , fGPSDestBearing (tcGPSDestBearing , exif.fGPSDestBearing ) 1061 1062 , fGPSDestDistanceRef (tcGPSDestDistanceRef, exif.fGPSDestDistanceRef) 1063 , fGPSDestDistance (tcGPSDestDistance , exif.fGPSDestDistance ) 1064 1065 , fGPSProcessingMethod (tcGPSProcessingMethod, exif.fGPSProcessingMethod) 1066 , fGPSAreaInformation (tcGPSAreaInformation , exif.fGPSAreaInformation ) 1067 1068 , fGPSDateStamp (tcGPSDateStamp, exif.fGPSDateStamp) 1069 1070 , fGPSDifferential (tcGPSDifferential, (uint16) exif.fGPSDifferential) 1071 1072 , fGPSHPositioningError (tcGPSHPositioningError, exif.fGPSHPositioningError) 1073 1074 { 1075 1076 if (exif.fExifVersion) 1077 { 1078 1079 fExifVersionData [0] = (uint8) (exif.fExifVersion >> 24); 1080 fExifVersionData [1] = (uint8) (exif.fExifVersion >> 16); 1081 fExifVersionData [2] = (uint8) (exif.fExifVersion >> 8); 1082 fExifVersionData [3] = (uint8) (exif.fExifVersion ); 1083 1084 fExifIFD.Add (&fExifVersion); 1085 1086 } 1087 1088 if (exif.fExposureTime.IsValid ()) 1089 { 1090 fExifIFD.Add (&fExposureTime); 1091 } 1092 1093 if (exif.fShutterSpeedValue.IsValid ()) 1094 { 1095 fExifIFD.Add (&fShutterSpeedValue); 1096 } 1097 1098 if (exif.fFNumber.IsValid ()) 1099 { 1100 fExifIFD.Add (&fFNumber); 1101 } 1102 1103 if (exif.fApertureValue.IsValid ()) 1104 { 1105 fExifIFD.Add (&fApertureValue); 1106 } 1107 1108 if (exif.fBrightnessValue.IsValid ()) 1109 { 1110 fExifIFD.Add (&fBrightnessValue); 1111 } 1112 1113 if (exif.fExposureBiasValue.IsValid ()) 1114 { 1115 fExifIFD.Add (&fExposureBiasValue); 1116 } 1117 1118 if (exif.fMaxApertureValue.IsValid ()) 1119 { 1120 fExifIFD.Add (&fMaxApertureValue); 1121 } 1122 1123 if (exif.fSubjectDistance.IsValid ()) 1124 { 1125 fExifIFD.Add (&fSubjectDistance); 1126 } 1127 1128 if (exif.fFocalLength.IsValid ()) 1129 { 1130 fExifIFD.Add (&fFocalLength); 1131 } 1132 1133 if (exif.fISOSpeedRatings [0] != 0) 1134 { 1135 fExifIFD.Add (&fISOSpeedRatings); 1136 } 1137 1138 if (exif.fFlash <= 0x0FFFF) 1139 { 1140 fExifIFD.Add (&fFlash); 1141 } 1142 1143 if (exif.fExposureProgram <= 0x0FFFF) 1144 { 1145 fExifIFD.Add (&fExposureProgram); 1146 } 1147 1148 if (exif.fMeteringMode <= 0x0FFFF) 1149 { 1150 fExifIFD.Add (&fMeteringMode); 1151 } 1152 1153 if (exif.fLightSource <= 0x0FFFF) 1154 { 1155 fExifIFD.Add (&fLightSource); 1156 } 1157 1158 if (exif.fSensingMethod <= 0x0FFFF) 1159 { 1160 fExifIFD.Add (&fSensingMethod); 1161 } 1162 1163 if (exif.fFocalLengthIn35mmFilm != 0) 1164 { 1165 fExifIFD.Add (&fFocalLength35mm); 1166 } 1167 1168 if (exif.fFileSource <= 0x0FF) 1169 { 1170 fExifIFD.Add (&fFileSource); 1171 } 1172 1173 if (exif.fSceneType <= 0x0FF) 1174 { 1175 fExifIFD.Add (&fSceneType); 1176 } 1177 1178 if (exif.fCFARepeatPatternRows && 1179 exif.fCFARepeatPatternCols) 1180 { 1181 fExifIFD.Add (&fCFAPattern); 1182 } 1183 1184 if (exif.fCustomRendered <= 0x0FFFF) 1185 { 1186 fExifIFD.Add (&fCustomRendered); 1187 } 1188 1189 if (exif.fExposureMode <= 0x0FFFF) 1190 { 1191 fExifIFD.Add (&fExposureMode); 1192 } 1193 1194 if (exif.fWhiteBalance <= 0x0FFFF) 1195 { 1196 fExifIFD.Add (&fWhiteBalance); 1197 } 1198 1199 if (exif.fSceneCaptureType <= 0x0FFFF) 1200 { 1201 fExifIFD.Add (&fSceneCaptureType); 1202 } 1203 1204 if (exif.fGainControl <= 0x0FFFF) 1205 { 1206 fExifIFD.Add (&fGainControl); 1207 } 1208 1209 if (exif.fContrast <= 0x0FFFF) 1210 { 1211 fExifIFD.Add (&fContrast); 1212 } 1213 1214 if (exif.fSaturation <= 0x0FFFF) 1215 { 1216 fExifIFD.Add (&fSaturation); 1217 } 1218 1219 if (exif.fSharpness <= 0x0FFFF) 1220 { 1221 fExifIFD.Add (&fSharpness); 1222 } 1223 1224 if (exif.fSubjectDistanceRange <= 0x0FFFF) 1225 { 1226 fExifIFD.Add (&fSubjectDistanceRange); 1227 } 1228 1229 if (exif.fDigitalZoomRatio.IsValid ()) 1230 { 1231 fExifIFD.Add (&fDigitalZoomRatio); 1232 } 1233 1234 if (exif.fExposureIndex.IsValid ()) 1235 { 1236 fExifIFD.Add (&fExposureIndex); 1237 } 1238 1239 if (insideDNG) // TIFF-EP only tags 1240 { 1241 1242 if (exif.fImageNumber != 0xFFFFFFFF) 1243 { 1244 directory.Add (&fImageNumber); 1245 } 1246 1247 if (exif.fSelfTimerMode <= 0x0FFFF) 1248 { 1249 directory.Add (&fSelfTimerMode); 1250 } 1251 1252 if (exif.fBatteryLevelA.NotEmpty ()) 1253 { 1254 directory.Add (&fBatteryLevelA); 1255 } 1256 1257 else if (exif.fBatteryLevelR.IsValid ()) 1258 { 1259 directory.Add (&fBatteryLevelR); 1260 } 1261 1262 } 1263 1264 if (exif.fFocalPlaneXResolution.IsValid ()) 1265 { 1266 fExifIFD.Add (&fFocalPlaneXResolution); 1267 } 1268 1269 if (exif.fFocalPlaneYResolution.IsValid ()) 1270 { 1271 fExifIFD.Add (&fFocalPlaneYResolution); 1272 } 1273 1274 if (exif.fFocalPlaneResolutionUnit <= 0x0FFFF) 1275 { 1276 fExifIFD.Add (&fFocalPlaneResolutionUnit); 1277 } 1278 1279 if (exif.fSubjectAreaCount) 1280 { 1281 1282 fSubjectAreaData [0] = (uint16) exif.fSubjectArea [0]; 1283 fSubjectAreaData [1] = (uint16) exif.fSubjectArea [1]; 1284 fSubjectAreaData [2] = (uint16) exif.fSubjectArea [2]; 1285 fSubjectAreaData [3] = (uint16) exif.fSubjectArea [3]; 1286 1287 fExifIFD.Add (&fSubjectArea); 1288 1289 } 1290 1291 if (exif.fLensInfo [0].IsValid () && 1292 exif.fLensInfo [1].IsValid ()) 1293 { 1294 1295 fLensInfoData [0] = exif.fLensInfo [0]; 1296 fLensInfoData [1] = exif.fLensInfo [1]; 1297 fLensInfoData [2] = exif.fLensInfo [2]; 1298 fLensInfoData [3] = exif.fLensInfo [3]; 1299 1300 if (insideDNG) 1301 { 1302 directory.Add (&fLensInfo); 1303 } 1304 1305 } 1306 1307 if (exif.fDateTime.IsValid ()) 1308 { 1309 1310 directory.Add (&fDateTime); 1311 1312 if (exif.fDateTime.Subseconds ().NotEmpty ()) 1313 { 1314 fExifIFD.Add (&fSubsecTime); 1315 } 1316 1317 } 1318 1319 if (exif.fDateTimeOriginal.IsValid ()) 1320 { 1321 1322 fExifIFD.Add (&fDateTimeOriginal); 1323 1324 if (exif.fDateTimeOriginal.Subseconds ().NotEmpty ()) 1325 { 1326 fExifIFD.Add (&fSubsecTimeOriginal); 1327 } 1328 1329 } 1330 1331 if (exif.fDateTimeDigitized.IsValid ()) 1332 { 1333 1334 fExifIFD.Add (&fDateTimeDigitized); 1335 1336 if (exif.fDateTimeDigitized.Subseconds ().NotEmpty ()) 1337 { 1338 fExifIFD.Add (&fSubsecTimeDigitized); 1339 } 1340 1341 } 1342 1343 if (exif.fMake.NotEmpty ()) 1344 { 1345 directory.Add (&fMake); 1346 } 1347 1348 if (exif.fModel.NotEmpty ()) 1349 { 1350 directory.Add (&fModel); 1351 } 1352 1353 if (exif.fArtist.NotEmpty ()) 1354 { 1355 directory.Add (&fArtist); 1356 } 1357 1358 if (exif.fSoftware.NotEmpty ()) 1359 { 1360 directory.Add (&fSoftware); 1361 } 1362 1363 if (exif.fCopyright.NotEmpty ()) 1364 { 1365 directory.Add (&fCopyright); 1366 } 1367 1368 if (exif.fImageDescription.NotEmpty ()) 1369 { 1370 directory.Add (&fImageDescription); 1371 } 1372 1373 if (exif.fCameraSerialNumber.NotEmpty () && insideDNG) 1374 { 1375 directory.Add (&fSerialNumber); 1376 } 1377 1378 if (makerNoteSafe && makerNoteData) 1379 { 1380 1381 directory.Add (&fMakerNoteSafety); 1382 1383 fExifIFD.Add (&fMakerNote); 1384 1385 } 1386 1387 if (exif.fUserComment.NotEmpty ()) 1388 { 1389 fExifIFD.Add (&fUserComment); 1390 } 1391 1392 if (exif.fImageUniqueID.IsValid ()) 1393 { 1394 1395 for (uint32 j = 0; j < 16; j++) 1396 { 1397 1398 sprintf (fImageUniqueIDData + j * 2, 1399 "%02X", 1400 (unsigned) exif.fImageUniqueID.data [j]); 1401 1402 } 1403 1404 fExifIFD.Add (&fImageUniqueID); 1405 1406 } 1407 1408 if (exif.AtLeastVersion0230 ()) 1409 { 1410 1411 if (exif.fSensitivityType != 0) 1412 { 1413 1414 fExifIFD.Add (&fSensitivityType); 1415 1416 } 1417 1418 // Sensitivity tags. Do not write these extra tags unless the SensitivityType 1419 // and PhotographicSensitivity (i.e., ISOSpeedRatings) values are valid. 1420 1421 if (exif.fSensitivityType != 0 && 1422 exif.fISOSpeedRatings [0] != 0) 1423 { 1424 1425 // Standard Output Sensitivity (SOS). 1426 1427 if (exif.fStandardOutputSensitivity != 0) 1428 { 1429 fExifIFD.Add (&fStandardOutputSensitivity); 1430 } 1431 1432 // Recommended Exposure Index (REI). 1433 1434 if (exif.fRecommendedExposureIndex != 0) 1435 { 1436 fExifIFD.Add (&fRecommendedExposureIndex); 1437 } 1438 1439 // ISO Speed. 1440 1441 if (exif.fISOSpeed != 0) 1442 { 1443 1444 fExifIFD.Add (&fISOSpeed); 1445 1446 if (exif.fISOSpeedLatitudeyyy != 0 && 1447 exif.fISOSpeedLatitudezzz != 0) 1448 { 1449 1450 fExifIFD.Add (&fISOSpeedLatitudeyyy); 1451 fExifIFD.Add (&fISOSpeedLatitudezzz); 1452 1453 } 1454 1455 } 1456 1457 } 1458 1459 if (exif.fOwnerName.NotEmpty ()) 1460 { 1461 fExifIFD.Add (&fCameraOwnerName); 1462 } 1463 1464 if (exif.fCameraSerialNumber.NotEmpty ()) 1465 { 1466 fExifIFD.Add (&fBodySerialNumber); 1467 } 1468 1469 if (exif.fLensInfo [0].IsValid () && 1470 exif.fLensInfo [1].IsValid ()) 1471 { 1472 fExifIFD.Add (&fLensSpecification); 1473 } 1474 1475 if (exif.fLensMake.NotEmpty ()) 1476 { 1477 fExifIFD.Add (&fLensMake); 1478 } 1479 1480 if (exif.fLensName.NotEmpty ()) 1481 { 1482 fExifIFD.Add (&fLensModel); 1483 } 1484 1485 if (exif.fLensSerialNumber.NotEmpty ()) 1486 { 1487 fExifIFD.Add (&fLensSerialNumber); 1488 } 1489 1490 } 1491 1492 if (exif.fGPSVersionID) 1493 { 1494 1495 fGPSVersionData [0] = (uint8) (exif.fGPSVersionID >> 24); 1496 fGPSVersionData [1] = (uint8) (exif.fGPSVersionID >> 16); 1497 fGPSVersionData [2] = (uint8) (exif.fGPSVersionID >> 8); 1498 fGPSVersionData [3] = (uint8) (exif.fGPSVersionID ); 1499 1500 fGPSIFD.Add (&fGPSVersionID); 1501 1502 } 1503 1504 if (exif.fGPSLatitudeRef.NotEmpty () && 1505 exif.fGPSLatitude [0].IsValid ()) 1506 { 1507 fGPSIFD.Add (&fGPSLatitudeRef); 1508 fGPSIFD.Add (&fGPSLatitude ); 1509 } 1510 1511 if (exif.fGPSLongitudeRef.NotEmpty () && 1512 exif.fGPSLongitude [0].IsValid ()) 1513 { 1514 fGPSIFD.Add (&fGPSLongitudeRef); 1515 fGPSIFD.Add (&fGPSLongitude ); 1516 } 1517 1518 if (exif.fGPSAltitudeRef <= 0x0FF) 1519 { 1520 fGPSIFD.Add (&fGPSAltitudeRef); 1521 } 1522 1523 if (exif.fGPSAltitude.IsValid ()) 1524 { 1525 fGPSIFD.Add (&fGPSAltitude); 1526 } 1527 1528 if (exif.fGPSTimeStamp [0].IsValid ()) 1529 { 1530 fGPSIFD.Add (&fGPSTimeStamp); 1531 } 1532 1533 if (exif.fGPSSatellites.NotEmpty ()) 1534 { 1535 fGPSIFD.Add (&fGPSSatellites); 1536 } 1537 1538 if (exif.fGPSStatus.NotEmpty ()) 1539 { 1540 fGPSIFD.Add (&fGPSStatus); 1541 } 1542 1543 if (exif.fGPSMeasureMode.NotEmpty ()) 1544 { 1545 fGPSIFD.Add (&fGPSMeasureMode); 1546 } 1547 1548 if (exif.fGPSDOP.IsValid ()) 1549 { 1550 fGPSIFD.Add (&fGPSDOP); 1551 } 1552 1553 if (exif.fGPSSpeedRef.NotEmpty ()) 1554 { 1555 fGPSIFD.Add (&fGPSSpeedRef); 1556 } 1557 1558 if (exif.fGPSSpeed.IsValid ()) 1559 { 1560 fGPSIFD.Add (&fGPSSpeed); 1561 } 1562 1563 if (exif.fGPSTrackRef.NotEmpty ()) 1564 { 1565 fGPSIFD.Add (&fGPSTrackRef); 1566 } 1567 1568 if (exif.fGPSTrack.IsValid ()) 1569 { 1570 fGPSIFD.Add (&fGPSTrack); 1571 } 1572 1573 if (exif.fGPSImgDirectionRef.NotEmpty ()) 1574 { 1575 fGPSIFD.Add (&fGPSImgDirectionRef); 1576 } 1577 1578 if (exif.fGPSImgDirection.IsValid ()) 1579 { 1580 fGPSIFD.Add (&fGPSImgDirection); 1581 } 1582 1583 if (exif.fGPSMapDatum.NotEmpty ()) 1584 { 1585 fGPSIFD.Add (&fGPSMapDatum); 1586 } 1587 1588 if (exif.fGPSDestLatitudeRef.NotEmpty () && 1589 exif.fGPSDestLatitude [0].IsValid ()) 1590 { 1591 fGPSIFD.Add (&fGPSDestLatitudeRef); 1592 fGPSIFD.Add (&fGPSDestLatitude ); 1593 } 1594 1595 if (exif.fGPSDestLongitudeRef.NotEmpty () && 1596 exif.fGPSDestLongitude [0].IsValid ()) 1597 { 1598 fGPSIFD.Add (&fGPSDestLongitudeRef); 1599 fGPSIFD.Add (&fGPSDestLongitude ); 1600 } 1601 1602 if (exif.fGPSDestBearingRef.NotEmpty ()) 1603 { 1604 fGPSIFD.Add (&fGPSDestBearingRef); 1605 } 1606 1607 if (exif.fGPSDestBearing.IsValid ()) 1608 { 1609 fGPSIFD.Add (&fGPSDestBearing); 1610 } 1611 1612 if (exif.fGPSDestDistanceRef.NotEmpty ()) 1613 { 1614 fGPSIFD.Add (&fGPSDestDistanceRef); 1615 } 1616 1617 if (exif.fGPSDestDistance.IsValid ()) 1618 { 1619 fGPSIFD.Add (&fGPSDestDistance); 1620 } 1621 1622 if (exif.fGPSProcessingMethod.NotEmpty ()) 1623 { 1624 fGPSIFD.Add (&fGPSProcessingMethod); 1625 } 1626 1627 if (exif.fGPSAreaInformation.NotEmpty ()) 1628 { 1629 fGPSIFD.Add (&fGPSAreaInformation); 1630 } 1631 1632 if (exif.fGPSDateStamp.NotEmpty ()) 1633 { 1634 fGPSIFD.Add (&fGPSDateStamp); 1635 } 1636 1637 if (exif.fGPSDifferential <= 0x0FFFF) 1638 { 1639 fGPSIFD.Add (&fGPSDifferential); 1640 } 1641 1642 if (exif.AtLeastVersion0230 ()) 1643 { 1644 1645 if (exif.fGPSHPositioningError.IsValid ()) 1646 { 1647 fGPSIFD.Add (&fGPSHPositioningError); 1648 } 1649 1650 } 1651 1652 AddLinks (directory); 1653 1654 } 1655 1656 /******************************************************************************/ 1657 1658 void exif_tag_set::AddLinks (dng_tiff_directory &directory) 1659 { 1660 1661 if (fExifIFD.Size () != 0 && !fAddedExifLink) 1662 { 1663 1664 directory.Add (&fExifLink); 1665 1666 fAddedExifLink = true; 1667 1668 } 1669 1670 if (fGPSIFD.Size () != 0 && !fAddedGPSLink) 1671 { 1672 1673 directory.Add (&fGPSLink); 1674 1675 fAddedGPSLink = true; 1676 1677 } 1678 1679 } 1680 1681 /******************************************************************************/ 1682 1683 class range_tag_set 1684 { 1685 1686 private: 1687 1688 uint32 fActiveAreaData [4]; 1689 1690 tag_uint32_ptr fActiveArea; 1691 1692 uint32 fMaskedAreaData [kMaxMaskedAreas * 4]; 1693 1694 tag_uint32_ptr fMaskedAreas; 1695 1696 tag_uint16_ptr fLinearizationTable; 1697 1698 uint16 fBlackLevelRepeatDimData [2]; 1699 1700 tag_uint16_ptr fBlackLevelRepeatDim; 1701 1702 dng_urational fBlackLevelData [kMaxBlackPattern * 1703 kMaxBlackPattern * 1704 kMaxSamplesPerPixel]; 1705 1706 tag_urational_ptr fBlackLevel; 1707 1708 dng_memory_data fBlackLevelDeltaHData; 1709 dng_memory_data fBlackLevelDeltaVData; 1710 1711 tag_srational_ptr fBlackLevelDeltaH; 1712 tag_srational_ptr fBlackLevelDeltaV; 1713 1714 uint16 fWhiteLevelData16 [kMaxSamplesPerPixel]; 1715 uint32 fWhiteLevelData32 [kMaxSamplesPerPixel]; 1716 1717 tag_uint16_ptr fWhiteLevel16; 1718 tag_uint32_ptr fWhiteLevel32; 1719 1720 public: 1721 1722 range_tag_set (dng_tiff_directory &directory, 1723 const dng_negative &negative); 1724 1725 }; 1726 1727 /******************************************************************************/ 1728 1729 range_tag_set::range_tag_set (dng_tiff_directory &directory, 1730 const dng_negative &negative) 1731 1732 : fActiveArea (tcActiveArea, 1733 fActiveAreaData, 1734 4) 1735 1736 , fMaskedAreas (tcMaskedAreas, 1737 fMaskedAreaData, 1738 0) 1739 1740 , fLinearizationTable (tcLinearizationTable, 1741 NULL, 1742 0) 1743 1744 , fBlackLevelRepeatDim (tcBlackLevelRepeatDim, 1745 fBlackLevelRepeatDimData, 1746 2) 1747 1748 , fBlackLevel (tcBlackLevel, 1749 fBlackLevelData) 1750 1751 , fBlackLevelDeltaHData () 1752 , fBlackLevelDeltaVData () 1753 1754 , fBlackLevelDeltaH (tcBlackLevelDeltaH) 1755 , fBlackLevelDeltaV (tcBlackLevelDeltaV) 1756 1757 , fWhiteLevel16 (tcWhiteLevel, 1758 fWhiteLevelData16) 1759 1760 , fWhiteLevel32 (tcWhiteLevel, 1761 fWhiteLevelData32) 1762 1763 { 1764 1765 const dng_image &rawImage (negative.RawImage ()); 1766 1767 const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo (); 1768 1769 if (rangeInfo) 1770 { 1771 1772 // ActiveArea: 1773 1774 { 1775 1776 const dng_rect &r = rangeInfo->fActiveArea; 1777 1778 if (r.NotEmpty ()) 1779 { 1780 1781 fActiveAreaData [0] = r.t; 1782 fActiveAreaData [1] = r.l; 1783 fActiveAreaData [2] = r.b; 1784 fActiveAreaData [3] = r.r; 1785 1786 directory.Add (&fActiveArea); 1787 1788 } 1789 1790 } 1791 1792 // MaskedAreas: 1793 1794 if (rangeInfo->fMaskedAreaCount) 1795 { 1796 1797 fMaskedAreas.SetCount (rangeInfo->fMaskedAreaCount * 4); 1798 1799 for (uint32 index = 0; index < rangeInfo->fMaskedAreaCount; index++) 1800 { 1801 1802 const dng_rect &r = rangeInfo->fMaskedArea [index]; 1803 1804 fMaskedAreaData [index * 4 + 0] = r.t; 1805 fMaskedAreaData [index * 4 + 1] = r.l; 1806 fMaskedAreaData [index * 4 + 2] = r.b; 1807 fMaskedAreaData [index * 4 + 3] = r.r; 1808 1809 } 1810 1811 directory.Add (&fMaskedAreas); 1812 1813 } 1814 1815 // LinearizationTable: 1816 1817 if (rangeInfo->fLinearizationTable.Get ()) 1818 { 1819 1820 fLinearizationTable.SetData (rangeInfo->fLinearizationTable->Buffer_uint16 () ); 1821 fLinearizationTable.SetCount (rangeInfo->fLinearizationTable->LogicalSize () >> 1); 1822 1823 directory.Add (&fLinearizationTable); 1824 1825 } 1826 1827 // BlackLevelRepeatDim: 1828 1829 { 1830 1831 fBlackLevelRepeatDimData [0] = (uint16) rangeInfo->fBlackLevelRepeatRows; 1832 fBlackLevelRepeatDimData [1] = (uint16) rangeInfo->fBlackLevelRepeatCols; 1833 1834 directory.Add (&fBlackLevelRepeatDim); 1835 1836 } 1837 1838 // BlackLevel: 1839 1840 { 1841 1842 uint32 index = 0; 1843 1844 for (uint16 v = 0; v < rangeInfo->fBlackLevelRepeatRows; v++) 1845 { 1846 1847 for (uint32 h = 0; h < rangeInfo->fBlackLevelRepeatCols; h++) 1848 { 1849 1850 for (uint32 c = 0; c < rawImage.Planes (); c++) 1851 { 1852 1853 fBlackLevelData [index++] = rangeInfo->BlackLevel (v, h, c); 1854 1855 } 1856 1857 } 1858 1859 } 1860 1861 fBlackLevel.SetCount (rangeInfo->fBlackLevelRepeatRows * 1862 rangeInfo->fBlackLevelRepeatCols * rawImage.Planes ()); 1863 1864 directory.Add (&fBlackLevel); 1865 1866 } 1867 1868 // BlackLevelDeltaH: 1869 1870 if (rangeInfo->ColumnBlackCount ()) 1871 { 1872 1873 uint32 count = rangeInfo->ColumnBlackCount (); 1874 1875 fBlackLevelDeltaHData.Allocate (count, sizeof (dng_srational)); 1876 1877 dng_srational *blacks = (dng_srational *) fBlackLevelDeltaHData.Buffer (); 1878 1879 for (uint32 col = 0; col < count; col++) 1880 { 1881 1882 blacks [col] = rangeInfo->ColumnBlack (col); 1883 1884 } 1885 1886 fBlackLevelDeltaH.SetData (blacks); 1887 fBlackLevelDeltaH.SetCount (count ); 1888 1889 directory.Add (&fBlackLevelDeltaH); 1890 1891 } 1892 1893 // BlackLevelDeltaV: 1894 1895 if (rangeInfo->RowBlackCount ()) 1896 { 1897 1898 uint32 count = rangeInfo->RowBlackCount (); 1899 1900 fBlackLevelDeltaVData.Allocate (count, sizeof (dng_srational)); 1901 1902 dng_srational *blacks = (dng_srational *) fBlackLevelDeltaVData.Buffer (); 1903 1904 for (uint32 row = 0; row < count; row++) 1905 { 1906 1907 blacks [row] = rangeInfo->RowBlack (row); 1908 1909 } 1910 1911 fBlackLevelDeltaV.SetData (blacks); 1912 fBlackLevelDeltaV.SetCount (count ); 1913 1914 directory.Add (&fBlackLevelDeltaV); 1915 1916 } 1917 1918 } 1919 1920 // WhiteLevel: 1921 1922 // Only use the 32-bit data type if we must use it since there 1923 // are some lazy (non-Adobe) DNG readers out there. 1924 1925 bool needs32 = false; 1926 1927 fWhiteLevel16.SetCount (rawImage.Planes ()); 1928 fWhiteLevel32.SetCount (rawImage.Planes ()); 1929 1930 for (uint32 c = 0; c < fWhiteLevel16.Count (); c++) 1931 { 1932 1933 fWhiteLevelData32 [c] = negative.WhiteLevel (c); 1934 1935 if (fWhiteLevelData32 [c] > 0x0FFFF) 1936 { 1937 needs32 = true; 1938 } 1939 1940 fWhiteLevelData16 [c] = (uint16) fWhiteLevelData32 [c]; 1941 1942 } 1943 1944 if (needs32) 1945 { 1946 directory.Add (&fWhiteLevel32); 1947 } 1948 1949 else 1950 { 1951 directory.Add (&fWhiteLevel16); 1952 } 1953 1954 } 1955 1956 /******************************************************************************/ 1957 1958 class mosaic_tag_set 1959 { 1960 1961 private: 1962 1963 uint16 fCFARepeatPatternDimData [2]; 1964 1965 tag_uint16_ptr fCFARepeatPatternDim; 1966 1967 uint8 fCFAPatternData [kMaxCFAPattern * 1968 kMaxCFAPattern]; 1969 1970 tag_uint8_ptr fCFAPattern; 1971 1972 uint8 fCFAPlaneColorData [kMaxColorPlanes]; 1973 1974 tag_uint8_ptr fCFAPlaneColor; 1975 1976 tag_uint16 fCFALayout; 1977 1978 tag_uint32 fGreenSplit; 1979 1980 public: 1981 1982 mosaic_tag_set (dng_tiff_directory &directory, 1983 const dng_mosaic_info &info); 1984 1985 }; 1986 1987 /******************************************************************************/ 1988 1989 mosaic_tag_set::mosaic_tag_set (dng_tiff_directory &directory, 1990 const dng_mosaic_info &info) 1991 1992 : fCFARepeatPatternDim (tcCFARepeatPatternDim, 1993 fCFARepeatPatternDimData, 1994 2) 1995 1996 , fCFAPattern (tcCFAPattern, 1997 fCFAPatternData) 1998 1999 , fCFAPlaneColor (tcCFAPlaneColor, 2000 fCFAPlaneColorData) 2001 2002 , fCFALayout (tcCFALayout, 2003 (uint16) info.fCFALayout) 2004 2005 , fGreenSplit (tcBayerGreenSplit, 2006 info.fBayerGreenSplit) 2007 2008 { 2009 2010 if (info.IsColorFilterArray ()) 2011 { 2012 2013 // CFARepeatPatternDim: 2014 2015 fCFARepeatPatternDimData [0] = (uint16) info.fCFAPatternSize.v; 2016 fCFARepeatPatternDimData [1] = (uint16) info.fCFAPatternSize.h; 2017 2018 directory.Add (&fCFARepeatPatternDim); 2019 2020 // CFAPattern: 2021 2022 fCFAPattern.SetCount (info.fCFAPatternSize.v * 2023 info.fCFAPatternSize.h); 2024 2025 for (int32 r = 0; r < info.fCFAPatternSize.v; r++) 2026 { 2027 2028 for (int32 c = 0; c < info.fCFAPatternSize.h; c++) 2029 { 2030 2031 fCFAPatternData [r * info.fCFAPatternSize.h + c] = info.fCFAPattern [r] [c]; 2032 2033 } 2034 2035 } 2036 2037 directory.Add (&fCFAPattern); 2038 2039 // CFAPlaneColor: 2040 2041 fCFAPlaneColor.SetCount (info.fColorPlanes); 2042 2043 for (uint32 j = 0; j < info.fColorPlanes; j++) 2044 { 2045 2046 fCFAPlaneColorData [j] = info.fCFAPlaneColor [j]; 2047 2048 } 2049 2050 directory.Add (&fCFAPlaneColor); 2051 2052 // CFALayout: 2053 2054 fCFALayout.Set ((uint16) info.fCFALayout); 2055 2056 directory.Add (&fCFALayout); 2057 2058 // BayerGreenSplit: (only include if the pattern is a Bayer pattern) 2059 2060 if (info.fCFAPatternSize == dng_point (2, 2) && 2061 info.fColorPlanes == 3) 2062 { 2063 2064 directory.Add (&fGreenSplit); 2065 2066 } 2067 2068 } 2069 2070 } 2071 2072 /******************************************************************************/ 2073 2074 class color_tag_set 2075 { 2076 2077 private: 2078 2079 uint32 fColorChannels; 2080 2081 tag_matrix fCameraCalibration1; 2082 tag_matrix fCameraCalibration2; 2083 2084 tag_string fCameraCalibrationSignature; 2085 2086 tag_string fAsShotProfileName; 2087 2088 dng_urational fAnalogBalanceData [4]; 2089 2090 tag_urational_ptr fAnalogBalance; 2091 2092 dng_urational fAsShotNeutralData [4]; 2093 2094 tag_urational_ptr fAsShotNeutral; 2095 2096 dng_urational fAsShotWhiteXYData [2]; 2097 2098 tag_urational_ptr fAsShotWhiteXY; 2099 2100 tag_urational fLinearResponseLimit; 2101 2102 public: 2103 2104 color_tag_set (dng_tiff_directory &directory, 2105 const dng_negative &negative); 2106 2107 }; 2108 2109 /******************************************************************************/ 2110 2111 color_tag_set::color_tag_set (dng_tiff_directory &directory, 2112 const dng_negative &negative) 2113 2114 : fColorChannels (negative.ColorChannels ()) 2115 2116 , fCameraCalibration1 (tcCameraCalibration1, 2117 negative.CameraCalibration1 ()) 2118 2119 , fCameraCalibration2 (tcCameraCalibration2, 2120 negative.CameraCalibration2 ()) 2121 2122 , fCameraCalibrationSignature (tcCameraCalibrationSignature, 2123 negative.CameraCalibrationSignature ()) 2124 2125 , fAsShotProfileName (tcAsShotProfileName, 2126 negative.AsShotProfileName ()) 2127 2128 , fAnalogBalance (tcAnalogBalance, 2129 fAnalogBalanceData, 2130 fColorChannels) 2131 2132 , fAsShotNeutral (tcAsShotNeutral, 2133 fAsShotNeutralData, 2134 fColorChannels) 2135 2136 , fAsShotWhiteXY (tcAsShotWhiteXY, 2137 fAsShotWhiteXYData, 2138 2) 2139 2140 , fLinearResponseLimit (tcLinearResponseLimit, 2141 negative.LinearResponseLimitR ()) 2142 2143 { 2144 2145 if (fColorChannels > 1) 2146 { 2147 2148 uint32 channels2 = fColorChannels * fColorChannels; 2149 2150 if (fCameraCalibration1.Count () == channels2) 2151 { 2152 2153 directory.Add (&fCameraCalibration1); 2154 2155 } 2156 2157 if (fCameraCalibration2.Count () == channels2) 2158 { 2159 2160 directory.Add (&fCameraCalibration2); 2161 2162 } 2163 2164 if (fCameraCalibration1.Count () == channels2 || 2165 fCameraCalibration2.Count () == channels2) 2166 { 2167 2168 if (negative.CameraCalibrationSignature ().NotEmpty ()) 2169 { 2170 2171 directory.Add (&fCameraCalibrationSignature); 2172 2173 } 2174 2175 } 2176 2177 if (negative.AsShotProfileName ().NotEmpty ()) 2178 { 2179 2180 directory.Add (&fAsShotProfileName); 2181 2182 } 2183 2184 for (uint32 j = 0; j < fColorChannels; j++) 2185 { 2186 2187 fAnalogBalanceData [j] = negative.AnalogBalanceR (j); 2188 2189 } 2190 2191 directory.Add (&fAnalogBalance); 2192 2193 if (negative.HasCameraNeutral ()) 2194 { 2195 2196 for (uint32 k = 0; k < fColorChannels; k++) 2197 { 2198 2199 fAsShotNeutralData [k] = negative.CameraNeutralR (k); 2200 2201 } 2202 2203 directory.Add (&fAsShotNeutral); 2204 2205 } 2206 2207 else if (negative.HasCameraWhiteXY ()) 2208 { 2209 2210 negative.GetCameraWhiteXY (fAsShotWhiteXYData [0], 2211 fAsShotWhiteXYData [1]); 2212 2213 directory.Add (&fAsShotWhiteXY); 2214 2215 } 2216 2217 directory.Add (&fLinearResponseLimit); 2218 2219 } 2220 2221 } 2222 2223 /******************************************************************************/ 2224 2225 class profile_tag_set 2226 { 2227 2228 private: 2229 2230 tag_uint16 fCalibrationIlluminant1; 2231 tag_uint16 fCalibrationIlluminant2; 2232 2233 tag_matrix fColorMatrix1; 2234 tag_matrix fColorMatrix2; 2235 2236 tag_matrix fForwardMatrix1; 2237 tag_matrix fForwardMatrix2; 2238 2239 tag_matrix fReductionMatrix1; 2240 tag_matrix fReductionMatrix2; 2241 2242 tag_string fProfileName; 2243 2244 tag_string fProfileCalibrationSignature; 2245 2246 tag_uint32 fEmbedPolicyTag; 2247 2248 tag_string fCopyrightTag; 2249 2250 uint32 fHueSatMapDimData [3]; 2251 2252 tag_uint32_ptr fHueSatMapDims; 2253 2254 tag_data_ptr fHueSatData1; 2255 tag_data_ptr fHueSatData2; 2256 2257 tag_uint32 fHueSatMapEncodingTag; 2258 2259 uint32 fLookTableDimData [3]; 2260 2261 tag_uint32_ptr fLookTableDims; 2262 2263 tag_data_ptr fLookTableData; 2264 2265 tag_uint32 fLookTableEncodingTag; 2266 2267 tag_srational fBaselineExposureOffsetTag; 2268 2269 tag_uint32 fDefaultBlackRenderTag; 2270 2271 dng_memory_data fToneCurveBuffer; 2272 2273 tag_data_ptr fToneCurveTag; 2274 2275 public: 2276 2277 profile_tag_set (dng_tiff_directory &directory, 2278 const dng_camera_profile &profile); 2279 2280 }; 2281 2282 /******************************************************************************/ 2283 2284 profile_tag_set::profile_tag_set (dng_tiff_directory &directory, 2285 const dng_camera_profile &profile) 2286 2287 : fCalibrationIlluminant1 (tcCalibrationIlluminant1, 2288 (uint16) profile.CalibrationIlluminant1 ()) 2289 2290 , fCalibrationIlluminant2 (tcCalibrationIlluminant2, 2291 (uint16) profile.CalibrationIlluminant2 ()) 2292 2293 , fColorMatrix1 (tcColorMatrix1, 2294 profile.ColorMatrix1 ()) 2295 2296 , fColorMatrix2 (tcColorMatrix2, 2297 profile.ColorMatrix2 ()) 2298 2299 , fForwardMatrix1 (tcForwardMatrix1, 2300 profile.ForwardMatrix1 ()) 2301 2302 , fForwardMatrix2 (tcForwardMatrix2, 2303 profile.ForwardMatrix2 ()) 2304 2305 , fReductionMatrix1 (tcReductionMatrix1, 2306 profile.ReductionMatrix1 ()) 2307 2308 , fReductionMatrix2 (tcReductionMatrix2, 2309 profile.ReductionMatrix2 ()) 2310 2311 , fProfileName (tcProfileName, 2312 profile.Name (), 2313 false) 2314 2315 , fProfileCalibrationSignature (tcProfileCalibrationSignature, 2316 profile.ProfileCalibrationSignature (), 2317 false) 2318 2319 , fEmbedPolicyTag (tcProfileEmbedPolicy, 2320 profile.EmbedPolicy ()) 2321 2322 , fCopyrightTag (tcProfileCopyright, 2323 profile.Copyright (), 2324 false) 2325 2326 , fHueSatMapDims (tcProfileHueSatMapDims, 2327 fHueSatMapDimData, 2328 3) 2329 2330 , fHueSatData1 (tcProfileHueSatMapData1, 2331 ttFloat, 2332 profile.HueSatDeltas1 ().DeltasCount () * 3, 2333 profile.HueSatDeltas1 ().GetConstDeltas ()) 2334 2335 , fHueSatData2 (tcProfileHueSatMapData2, 2336 ttFloat, 2337 profile.HueSatDeltas2 ().DeltasCount () * 3, 2338 profile.HueSatDeltas2 ().GetConstDeltas ()) 2339 2340 , fHueSatMapEncodingTag (tcProfileHueSatMapEncoding, 2341 profile.HueSatMapEncoding ()) 2342 2343 , fLookTableDims (tcProfileLookTableDims, 2344 fLookTableDimData, 2345 3) 2346 2347 , fLookTableData (tcProfileLookTableData, 2348 ttFloat, 2349 profile.LookTable ().DeltasCount () * 3, 2350 profile.LookTable ().GetConstDeltas ()) 2351 2352 , fLookTableEncodingTag (tcProfileLookTableEncoding, 2353 profile.LookTableEncoding ()) 2354 2355 , fBaselineExposureOffsetTag (tcBaselineExposureOffset, 2356 profile.BaselineExposureOffset ()) 2357 2358 , fDefaultBlackRenderTag (tcDefaultBlackRender, 2359 profile.DefaultBlackRender ()) 2360 2361 , fToneCurveBuffer () 2362 2363 , fToneCurveTag (tcProfileToneCurve, 2364 ttFloat, 2365 0, 2366 NULL) 2367 2368 { 2369 2370 if (profile.HasColorMatrix1 ()) 2371 { 2372 2373 uint32 colorChannels = profile.ColorMatrix1 ().Rows (); 2374 2375 directory.Add (&fCalibrationIlluminant1); 2376 2377 directory.Add (&fColorMatrix1); 2378 2379 if (fForwardMatrix1.Count () == colorChannels * 3) 2380 { 2381 2382 directory.Add (&fForwardMatrix1); 2383 2384 } 2385 2386 if (colorChannels > 3 && fReductionMatrix1.Count () == colorChannels * 3) 2387 { 2388 2389 directory.Add (&fReductionMatrix1); 2390 2391 } 2392 2393 if (profile.HasColorMatrix2 ()) 2394 { 2395 2396 directory.Add (&fCalibrationIlluminant2); 2397 2398 directory.Add (&fColorMatrix2); 2399 2400 if (fForwardMatrix2.Count () == colorChannels * 3) 2401 { 2402 2403 directory.Add (&fForwardMatrix2); 2404 2405 } 2406 2407 if (colorChannels > 3 && fReductionMatrix2.Count () == colorChannels * 3) 2408 { 2409 2410 directory.Add (&fReductionMatrix2); 2411 2412 } 2413 2414 } 2415 2416 if (profile.Name ().NotEmpty ()) 2417 { 2418 2419 directory.Add (&fProfileName); 2420 2421 } 2422 2423 if (profile.ProfileCalibrationSignature ().NotEmpty ()) 2424 { 2425 2426 directory.Add (&fProfileCalibrationSignature); 2427 2428 } 2429 2430 directory.Add (&fEmbedPolicyTag); 2431 2432 if (profile.Copyright ().NotEmpty ()) 2433 { 2434 2435 directory.Add (&fCopyrightTag); 2436 2437 } 2438 2439 bool haveHueSat1 = profile.HueSatDeltas1 ().IsValid (); 2440 2441 bool haveHueSat2 = profile.HueSatDeltas2 ().IsValid () && 2442 profile.HasColorMatrix2 (); 2443 2444 if (haveHueSat1 || haveHueSat2) 2445 { 2446 2447 uint32 hueDivs = 0; 2448 uint32 satDivs = 0; 2449 uint32 valDivs = 0; 2450 2451 if (haveHueSat1) 2452 { 2453 2454 profile.HueSatDeltas1 ().GetDivisions (hueDivs, 2455 satDivs, 2456 valDivs); 2457 2458 } 2459 2460 else 2461 { 2462 2463 profile.HueSatDeltas2 ().GetDivisions (hueDivs, 2464 satDivs, 2465 valDivs); 2466 2467 } 2468 2469 fHueSatMapDimData [0] = hueDivs; 2470 fHueSatMapDimData [1] = satDivs; 2471 fHueSatMapDimData [2] = valDivs; 2472 2473 directory.Add (&fHueSatMapDims); 2474 2475 // Don't bother including the ProfileHueSatMapEncoding tag unless it's 2476 // non-linear. 2477 2478 if (profile.HueSatMapEncoding () != encoding_Linear) 2479 { 2480 2481 directory.Add (&fHueSatMapEncodingTag); 2482 2483 } 2484 2485 } 2486 2487 if (haveHueSat1) 2488 { 2489 2490 directory.Add (&fHueSatData1); 2491 2492 } 2493 2494 if (haveHueSat2) 2495 { 2496 2497 directory.Add (&fHueSatData2); 2498 2499 } 2500 2501 if (profile.HasLookTable ()) 2502 { 2503 2504 uint32 hueDivs = 0; 2505 uint32 satDivs = 0; 2506 uint32 valDivs = 0; 2507 2508 profile.LookTable ().GetDivisions (hueDivs, 2509 satDivs, 2510 valDivs); 2511 2512 fLookTableDimData [0] = hueDivs; 2513 fLookTableDimData [1] = satDivs; 2514 fLookTableDimData [2] = valDivs; 2515 2516 directory.Add (&fLookTableDims); 2517 2518 directory.Add (&fLookTableData); 2519 2520 // Don't bother including the ProfileLookTableEncoding tag unless it's 2521 // non-linear. 2522 2523 if (profile.LookTableEncoding () != encoding_Linear) 2524 { 2525 2526 directory.Add (&fLookTableEncodingTag); 2527 2528 } 2529 2530 } 2531 2532 // Don't bother including the BaselineExposureOffset tag unless it's both 2533 // valid and non-zero. 2534 2535 if (profile.BaselineExposureOffset ().IsValid ()) 2536 { 2537 2538 if (profile.BaselineExposureOffset ().As_real64 () != 0.0) 2539 { 2540 2541 directory.Add (&fBaselineExposureOffsetTag); 2542 2543 } 2544 2545 } 2546 2547 if (profile.DefaultBlackRender () != defaultBlackRender_Auto) 2548 { 2549 2550 directory.Add (&fDefaultBlackRenderTag); 2551 2552 } 2553 2554 if (profile.ToneCurve ().IsValid ()) 2555 { 2556 2557 // Tone curve stored as pairs of 32-bit coordinates. Probably could do with 2558 // 16-bits here, but should be small number of points so... 2559 2560 uint32 toneCurvePoints = (uint32) (profile.ToneCurve ().fCoord.size ()); 2561 2562 fToneCurveBuffer.Allocate (SafeUint32Mult(toneCurvePoints, 2), 2563 sizeof (real32)); 2564 2565 real32 *points = fToneCurveBuffer.Buffer_real32 (); 2566 2567 fToneCurveTag.SetCount (toneCurvePoints * 2); 2568 fToneCurveTag.SetData (points); 2569 2570 for (uint32 i = 0; i < toneCurvePoints; i++) 2571 { 2572 2573 // Transpose coordinates so they are in a more expected 2574 // order (domain -> range). 2575 2576 points [i * 2 ] = (real32) profile.ToneCurve ().fCoord [i].h; 2577 points [i * 2 + 1] = (real32) profile.ToneCurve ().fCoord [i].v; 2578 2579 } 2580 2581 directory.Add (&fToneCurveTag); 2582 2583 } 2584 2585 } 2586 2587 } 2588 2589 /******************************************************************************/ 2590 2591 tiff_dng_extended_color_profile::tiff_dng_extended_color_profile 2592 (const dng_camera_profile &profile) 2593 2594 : fProfile (profile) 2595 2596 { 2597 2598 } 2599 2600 /******************************************************************************/ 2601 2602 void tiff_dng_extended_color_profile::Put (dng_stream &stream, 2603 bool includeModelRestriction) 2604 { 2605 2606 // Profile header. 2607 2608 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII); 2609 2610 stream.Put_uint16 (magicExtendedProfile); 2611 2612 stream.Put_uint32 (8); 2613 2614 // Profile tags. 2615 2616 profile_tag_set tagSet (*this, fProfile); 2617 2618 // Camera this profile is for. 2619 2620 tag_string cameraModelTag (tcUniqueCameraModel, 2621 fProfile.UniqueCameraModelRestriction ()); 2622 2623 if (includeModelRestriction) 2624 { 2625 2626 if (fProfile.UniqueCameraModelRestriction ().NotEmpty ()) 2627 { 2628 2629 Add (&cameraModelTag); 2630 2631 } 2632 2633 } 2634 2635 // Write it all out. 2636 2637 dng_tiff_directory::Put (stream, offsetsRelativeToExplicitBase, 8); 2638 2639 } 2640 2641 /*****************************************************************************/ 2642 2643 tag_dng_noise_profile::tag_dng_noise_profile (const dng_noise_profile &profile) 2644 2645 : tag_data_ptr (tcNoiseProfile, 2646 ttDouble, 2647 2 * profile.NumFunctions (), 2648 fValues) 2649 2650 { 2651 2652 DNG_REQUIRE (profile.NumFunctions () <= kMaxColorPlanes, 2653 "Too many noise functions in tag_dng_noise_profile."); 2654 2655 for (uint32 i = 0; i < profile.NumFunctions (); i++) 2656 { 2657 2658 fValues [(2 * i) ] = profile.NoiseFunction (i).Scale (); 2659 fValues [(2 * i) + 1] = profile.NoiseFunction (i).Offset (); 2660 2661 } 2662 2663 } 2664 2665 /*****************************************************************************/ 2666 2667 dng_image_writer::dng_image_writer () 2668 { 2669 2670 } 2671 2672 /*****************************************************************************/ 2673 2674 dng_image_writer::~dng_image_writer () 2675 { 2676 2677 } 2678 2679 /*****************************************************************************/ 2680 2681 uint32 dng_image_writer::CompressedBufferSize (const dng_ifd &ifd, 2682 uint32 uncompressedSize) 2683 { 2684 2685 switch (ifd.fCompression) 2686 { 2687 2688 case ccLZW: 2689 { 2690 2691 // Add lots of slop for LZW to expand data. 2692 2693 return SafeUint32Add (SafeUint32Mult (uncompressedSize, 2), 1024); 2694 2695 } 2696 2697 case ccDeflate: 2698 { 2699 2700 // ZLib says maximum is source size + 0.1% + 12 bytes. 2701 2702 return SafeUint32Add (SafeUint32Add (uncompressedSize, 2703 uncompressedSize >> 8), 64); 2704 2705 } 2706 2707 case ccJPEG: 2708 { 2709 2710 // If we are saving lossless JPEG from an 8-bit image, reserve 2711 // space to pad the data out to 16-bits. 2712 2713 if (ifd.fBitsPerSample [0] <= 8) 2714 { 2715 2716 return SafeUint32Mult (uncompressedSize, 2); 2717 2718 } 2719 2720 break; 2721 2722 } 2723 2724 default: 2725 break; 2726 2727 } 2728 2729 return 0; 2730 2731 } 2732 2733 /******************************************************************************/ 2734 2735 static void EncodeDelta8 (uint8 *dPtr, 2736 uint32 rows, 2737 uint32 cols, 2738 uint32 channels) 2739 { 2740 2741 const uint32 dRowStep = cols * channels; 2742 2743 for (uint32 row = 0; row < rows; row++) 2744 { 2745 2746 for (uint32 col = cols - 1; col > 0; col--) 2747 { 2748 2749 for (uint32 channel = 0; channel < channels; channel++) 2750 { 2751 2752 dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel]; 2753 2754 } 2755 2756 } 2757 2758 dPtr += dRowStep; 2759 2760 } 2761 2762 } 2763 2764 /******************************************************************************/ 2765 2766 static void EncodeDelta16 (uint16 *dPtr, 2767 uint32 rows, 2768 uint32 cols, 2769 uint32 channels) 2770 { 2771 2772 const uint32 dRowStep = cols * channels; 2773 2774 for (uint32 row = 0; row < rows; row++) 2775 { 2776 2777 for (uint32 col = cols - 1; col > 0; col--) 2778 { 2779 2780 for (uint32 channel = 0; channel < channels; channel++) 2781 { 2782 2783 dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel]; 2784 2785 } 2786 2787 } 2788 2789 dPtr += dRowStep; 2790 2791 } 2792 2793 } 2794 2795 /******************************************************************************/ 2796 2797 static void EncodeDelta32 (uint32 *dPtr, 2798 uint32 rows, 2799 uint32 cols, 2800 uint32 channels) 2801 { 2802 2803 const uint32 dRowStep = cols * channels; 2804 2805 for (uint32 row = 0; row < rows; row++) 2806 { 2807 2808 for (uint32 col = cols - 1; col > 0; col--) 2809 { 2810 2811 for (uint32 channel = 0; channel < channels; channel++) 2812 { 2813 2814 dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel]; 2815 2816 } 2817 2818 } 2819 2820 dPtr += dRowStep; 2821 2822 } 2823 2824 } 2825 2826 /*****************************************************************************/ 2827 2828 inline void EncodeDeltaBytes (uint8 *bytePtr, int32 cols, int32 channels) 2829 { 2830 2831 if (channels == 1) 2832 { 2833 2834 bytePtr += (cols - 1); 2835 2836 uint8 this0 = bytePtr [0]; 2837 2838 for (int32 col = 1; col < cols; col++) 2839 { 2840 2841 uint8 prev0 = bytePtr [-1]; 2842 2843 this0 -= prev0; 2844 2845 bytePtr [0] = this0; 2846 2847 this0 = prev0; 2848 2849 bytePtr -= 1; 2850 2851 } 2852 2853 } 2854 2855 else if (channels == 3) 2856 { 2857 2858 bytePtr += (cols - 1) * 3; 2859 2860 uint8 this0 = bytePtr [0]; 2861 uint8 this1 = bytePtr [1]; 2862 uint8 this2 = bytePtr [2]; 2863 2864 for (int32 col = 1; col < cols; col++) 2865 { 2866 2867 uint8 prev0 = bytePtr [-3]; 2868 uint8 prev1 = bytePtr [-2]; 2869 uint8 prev2 = bytePtr [-1]; 2870 2871 this0 -= prev0; 2872 this1 -= prev1; 2873 this2 -= prev2; 2874 2875 bytePtr [0] = this0; 2876 bytePtr [1] = this1; 2877 bytePtr [2] = this2; 2878 2879 this0 = prev0; 2880 this1 = prev1; 2881 this2 = prev2; 2882 2883 bytePtr -= 3; 2884 2885 } 2886 2887 } 2888 2889 else 2890 { 2891 2892 uint32 rowBytes = cols * channels; 2893 2894 bytePtr += rowBytes - 1; 2895 2896 for (uint32 col = channels; col < rowBytes; col++) 2897 { 2898 2899 bytePtr [0] -= bytePtr [-channels]; 2900 2901 bytePtr--; 2902 2903 } 2904 2905 } 2906 2907 } 2908 2909 /*****************************************************************************/ 2910 2911 static void EncodeFPDelta (uint8 *buffer, 2912 uint8 *temp, 2913 int32 cols, 2914 int32 channels, 2915 int32 bytesPerSample) 2916 { 2917 2918 int32 rowIncrement = cols * channels; 2919 2920 if (bytesPerSample == 2) 2921 { 2922 2923 const uint8 *src = buffer; 2924 2925 #if qDNGBigEndian 2926 uint8 *dst0 = temp; 2927 uint8 *dst1 = temp + rowIncrement; 2928 #else 2929 uint8 *dst1 = temp; 2930 uint8 *dst0 = temp + rowIncrement; 2931 #endif 2932 2933 for (int32 col = 0; col < rowIncrement; ++col) 2934 { 2935 2936 dst0 [col] = src [0]; 2937 dst1 [col] = src [1]; 2938 2939 src += 2; 2940 2941 } 2942 2943 } 2944 2945 else if (bytesPerSample == 3) 2946 { 2947 2948 const uint8 *src = buffer; 2949 2950 uint8 *dst0 = temp; 2951 uint8 *dst1 = temp + rowIncrement; 2952 uint8 *dst2 = temp + rowIncrement * 2; 2953 2954 for (int32 col = 0; col < rowIncrement; ++col) 2955 { 2956 2957 dst0 [col] = src [0]; 2958 dst1 [col] = src [1]; 2959 dst2 [col] = src [2]; 2960 2961 src += 3; 2962 2963 } 2964 2965 } 2966 2967 else 2968 { 2969 2970 const uint8 *src = buffer; 2971 2972 #if qDNGBigEndian 2973 uint8 *dst0 = temp; 2974 uint8 *dst1 = temp + rowIncrement; 2975 uint8 *dst2 = temp + rowIncrement * 2; 2976 uint8 *dst3 = temp + rowIncrement * 3; 2977 #else 2978 uint8 *dst3 = temp; 2979 uint8 *dst2 = temp + rowIncrement; 2980 uint8 *dst1 = temp + rowIncrement * 2; 2981 uint8 *dst0 = temp + rowIncrement * 3; 2982 #endif 2983 2984 for (int32 col = 0; col < rowIncrement; ++col) 2985 { 2986 2987 dst0 [col] = src [0]; 2988 dst1 [col] = src [1]; 2989 dst2 [col] = src [2]; 2990 dst3 [col] = src [3]; 2991 2992 src += 4; 2993 2994 } 2995 2996 } 2997 2998 EncodeDeltaBytes (temp, cols*bytesPerSample, channels); 2999 3000 memcpy (buffer, temp, cols*bytesPerSample*channels); 3001 3002 } 3003 3004 /*****************************************************************************/ 3005 3006 void dng_image_writer::EncodePredictor (dng_host &host, 3007 const dng_ifd &ifd, 3008 dng_pixel_buffer &buffer, 3009 AutoPtr<dng_memory_block> &tempBuffer) 3010 { 3011 3012 switch (ifd.fPredictor) 3013 { 3014 3015 case cpHorizontalDifference: 3016 case cpHorizontalDifferenceX2: 3017 case cpHorizontalDifferenceX4: 3018 { 3019 3020 int32 xFactor = 1; 3021 3022 if (ifd.fPredictor == cpHorizontalDifferenceX2) 3023 { 3024 xFactor = 2; 3025 } 3026 3027 else if (ifd.fPredictor == cpHorizontalDifferenceX4) 3028 { 3029 xFactor = 4; 3030 } 3031 3032 switch (buffer.fPixelType) 3033 { 3034 3035 case ttByte: 3036 { 3037 3038 EncodeDelta8 ((uint8 *) buffer.fData, 3039 buffer.fArea.H (), 3040 buffer.fArea.W () / xFactor, 3041 buffer.fPlanes * xFactor); 3042 3043 return; 3044 3045 } 3046 3047 case ttShort: 3048 { 3049 3050 EncodeDelta16 ((uint16 *) buffer.fData, 3051 buffer.fArea.H (), 3052 buffer.fArea.W () / xFactor, 3053 buffer.fPlanes * xFactor); 3054 3055 return; 3056 3057 } 3058 3059 case ttLong: 3060 { 3061 3062 EncodeDelta32 ((uint32 *) buffer.fData, 3063 buffer.fArea.H (), 3064 buffer.fArea.W () / xFactor, 3065 buffer.fPlanes * xFactor); 3066 3067 return; 3068 3069 } 3070 3071 default: 3072 break; 3073 3074 } 3075 3076 break; 3077 3078 } 3079 3080 case cpFloatingPoint: 3081 case cpFloatingPointX2: 3082 case cpFloatingPointX4: 3083 { 3084 3085 int32 xFactor = 1; 3086 3087 if (ifd.fPredictor == cpFloatingPointX2) 3088 { 3089 xFactor = 2; 3090 } 3091 3092 else if (ifd.fPredictor == cpFloatingPointX4) 3093 { 3094 xFactor = 4; 3095 } 3096 3097 if (buffer.fRowStep < 0) 3098 { 3099 ThrowProgramError ("Row step may not be negative"); 3100 } 3101 uint32 tempBufferSize = SafeUint32Mult ( 3102 static_cast<uint32>(buffer.fRowStep), 3103 buffer.fPixelSize); 3104 3105 if (!tempBuffer.Get () || tempBuffer->LogicalSize () < tempBufferSize) 3106 { 3107 3108 tempBuffer.Reset (host.Allocate (tempBufferSize)); 3109 3110 } 3111 3112 for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++) 3113 { 3114 3115 EncodeFPDelta ((uint8 *) buffer.DirtyPixel (row, buffer.fArea.l, buffer.fPlane), 3116 tempBuffer->Buffer_uint8 (), 3117 buffer.fArea.W () / xFactor, 3118 buffer.fPlanes * xFactor, 3119 buffer.fPixelSize); 3120 3121 } 3122 3123 return; 3124 3125 } 3126 3127 default: 3128 break; 3129 3130 } 3131 3132 if (ifd.fPredictor != cpNullPredictor) 3133 { 3134 3135 ThrowProgramError (); 3136 3137 } 3138 3139 } 3140 3141 /*****************************************************************************/ 3142 3143 void dng_image_writer::ByteSwapBuffer (dng_host & /* host */, 3144 dng_pixel_buffer &buffer) 3145 { 3146 3147 uint32 pixels = buffer.fRowStep * buffer.fArea.H (); 3148 3149 switch (buffer.fPixelSize) 3150 { 3151 3152 case 2: 3153 { 3154 3155 DoSwapBytes16 ((uint16 *) buffer.fData, 3156 pixels); 3157 3158 break; 3159 3160 } 3161 3162 case 4: 3163 { 3164 3165 DoSwapBytes32 ((uint32 *) buffer.fData, 3166 pixels); 3167 3168 break; 3169 3170 } 3171 3172 default: 3173 break; 3174 3175 } 3176 3177 } 3178 3179 /*****************************************************************************/ 3180 3181 void dng_image_writer::ReorderSubTileBlocks (const dng_ifd &ifd, 3182 dng_pixel_buffer &buffer, 3183 AutoPtr<dng_memory_block> &uncompressedBuffer, 3184 AutoPtr<dng_memory_block> &subTileBlockBuffer) 3185 { 3186 3187 uint32 blockRows = ifd.fSubTileBlockRows; 3188 uint32 blockCols = ifd.fSubTileBlockCols; 3189 3190 uint32 rowBlocks = buffer.fArea.H () / blockRows; 3191 uint32 colBlocks = buffer.fArea.W () / blockCols; 3192 3193 int32 rowStep = buffer.fRowStep * buffer.fPixelSize; 3194 int32 colStep = buffer.fColStep * buffer.fPixelSize; 3195 3196 int32 rowBlockStep = rowStep * blockRows; 3197 int32 colBlockStep = colStep * blockCols; 3198 3199 uint32 blockColBytes = blockCols * buffer.fPlanes * buffer.fPixelSize; 3200 3201 const uint8 *s0 = uncompressedBuffer->Buffer_uint8 (); 3202 uint8 *d0 = subTileBlockBuffer->Buffer_uint8 (); 3203 3204 for (uint32 rowBlock = 0; rowBlock < rowBlocks; rowBlock++) 3205 { 3206 3207 const uint8 *s1 = s0; 3208 3209 for (uint32 colBlock = 0; colBlock < colBlocks; colBlock++) 3210 { 3211 3212 const uint8 *s2 = s1; 3213 3214 for (uint32 blockRow = 0; blockRow < blockRows; blockRow++) 3215 { 3216 3217 for (uint32 j = 0; j < blockColBytes; j++) 3218 { 3219 3220 d0 [j] = s2 [j]; 3221 3222 } 3223 3224 d0 += blockColBytes; 3225 3226 s2 += rowStep; 3227 3228 } 3229 3230 s1 += colBlockStep; 3231 3232 } 3233 3234 s0 += rowBlockStep; 3235 3236 } 3237 3238 // Copy back reordered pixels. 3239 3240 DoCopyBytes (subTileBlockBuffer->Buffer (), 3241 uncompressedBuffer->Buffer (), 3242 uncompressedBuffer->LogicalSize ()); 3243 3244 } 3245 3246 /******************************************************************************/ 3247 3248 class dng_lzw_compressor 3249 { 3250 3251 private: 3252 3253 enum 3254 { 3255 kResetCode = 256, 3256 kEndCode = 257, 3257 kTableSize = 4096 3258 }; 3259 3260 // Compressor nodes have two son pointers. The low order bit of 3261 // the next code determines which pointer is used. This cuts the 3262 // number of nodes searched for the next code by two on average. 3263 3264 struct LZWCompressorNode 3265 { 3266 int16 final; 3267 int16 son0; 3268 int16 son1; 3269 int16 brother; 3270 }; 3271 3272 dng_memory_data fBuffer; 3273 3274 LZWCompressorNode *fTable; 3275 3276 uint8 *fDstPtr; 3277 3278 int32 fDstCount; 3279 3280 int32 fBitOffset; 3281 3282 int32 fNextCode; 3283 3284 int32 fCodeSize; 3285 3286 public: 3287 3288 dng_lzw_compressor (); 3289 3290 void Compress (const uint8 *sPtr, 3291 uint8 *dPtr, 3292 uint32 sCount, 3293 uint32 &dCount); 3294 3295 private: 3296 3297 void InitTable (); 3298 3299 int32 SearchTable (int32 w, int32 k) const 3300 { 3301 3302 DNG_ASSERT ((w >= 0) && (w <= kTableSize), 3303 "Bad w value in dng_lzw_compressor::SearchTable"); 3304 3305 int32 son0 = fTable [w] . son0; 3306 int32 son1 = fTable [w] . son1; 3307 3308 // Branchless version of: 3309 // int32 code = (k & 1) ? son1 : son0; 3310 3311 int32 code = son0 + ((-((int32) (k & 1))) & (son1 - son0)); 3312 3313 while (code > 0 && fTable [code].final != k) 3314 { 3315 code = fTable [code].brother; 3316 } 3317 3318 return code; 3319 3320 } 3321 3322 void AddTable (int32 w, int32 k); 3323 3324 void PutCodeWord (int32 code); 3325 3326 // Hidden copy constructor and assignment operator. 3327 3328 dng_lzw_compressor (const dng_lzw_compressor &compressor); 3329 3330 dng_lzw_compressor & operator= (const dng_lzw_compressor &compressor); 3331 3332 }; 3333 3334 /******************************************************************************/ 3335 3336 dng_lzw_compressor::dng_lzw_compressor () 3337 3338 : fBuffer () 3339 , fTable (NULL) 3340 , fDstPtr (NULL) 3341 , fDstCount (0) 3342 , fBitOffset (0) 3343 , fNextCode (0) 3344 , fCodeSize (0) 3345 3346 { 3347 3348 fBuffer.Allocate (kTableSize, sizeof (LZWCompressorNode)); 3349 3350 fTable = (LZWCompressorNode *) fBuffer.Buffer (); 3351 3352 } 3353 3354 /******************************************************************************/ 3355 3356 void dng_lzw_compressor::InitTable () 3357 { 3358 3359 fCodeSize = 9; 3360 3361 fNextCode = 258; 3362 3363 LZWCompressorNode *node = &fTable [0]; 3364 3365 for (int32 code = 0; code < 256; ++code) 3366 { 3367 3368 node->final = (int16) code; 3369 node->son0 = -1; 3370 node->son1 = -1; 3371 node->brother = -1; 3372 3373 node++; 3374 3375 } 3376 3377 } 3378 3379 /******************************************************************************/ 3380 3381 void dng_lzw_compressor::AddTable (int32 w, int32 k) 3382 { 3383 3384 DNG_ASSERT ((w >= 0) && (w <= kTableSize), 3385 "Bad w value in dng_lzw_compressor::AddTable"); 3386 3387 LZWCompressorNode *node = &fTable [w]; 3388 3389 int32 nextCode = fNextCode; 3390 3391 DNG_ASSERT ((nextCode >= 0) && (nextCode <= kTableSize), 3392 "Bad fNextCode value in dng_lzw_compressor::AddTable"); 3393 3394 LZWCompressorNode *node2 = &fTable [nextCode]; 3395 3396 fNextCode++; 3397 3398 int32 oldSon; 3399 3400 if( k&1 ) 3401 { 3402 oldSon = node->son1; 3403 node->son1 = (int16) nextCode; 3404 } 3405 else 3406 { 3407 oldSon = node->son0; 3408 node->son0 = (int16) nextCode; 3409 } 3410 3411 node2->final = (int16) k; 3412 node2->son0 = -1; 3413 node2->son1 = -1; 3414 node2->brother = (int16) oldSon; 3415 3416 if (nextCode == (1 << fCodeSize) - 1) 3417 { 3418 if (fCodeSize != 12) 3419 fCodeSize++; 3420 } 3421 3422 } 3423 3424 /******************************************************************************/ 3425 3426 void dng_lzw_compressor::PutCodeWord (int32 code) 3427 { 3428 3429 int32 bit = (int32) (fBitOffset & 7); 3430 3431 int32 offset1 = fBitOffset >> 3; 3432 int32 offset2 = (fBitOffset + fCodeSize - 1) >> 3; 3433 3434 int32 shift1 = (fCodeSize + bit) - 8; 3435 int32 shift2 = (fCodeSize + bit) - 16; 3436 3437 uint8 byte1 = (uint8) (code >> shift1); 3438 3439 uint8 *dstPtr1 = fDstPtr + offset1; 3440 uint8 *dstPtr3 = fDstPtr + offset2; 3441 3442 if (offset1 + 1 == offset2) 3443 { 3444 3445 uint8 byte2 = (uint8) (code << (-shift2)); 3446 3447 if (bit) 3448 *dstPtr1 |= byte1; 3449 else 3450 *dstPtr1 = byte1; 3451 3452 *dstPtr3 = byte2; 3453 3454 } 3455 3456 else 3457 { 3458 3459 int32 shift3 = (fCodeSize + bit) - 24; 3460 3461 uint8 byte2 = (uint8) (code >> shift2); 3462 uint8 byte3 = (uint8) (code << (-shift3)); 3463 3464 uint8 *dstPtr2 = fDstPtr + (offset1 + 1); 3465 3466 if (bit) 3467 *dstPtr1 |= byte1; 3468 else 3469 *dstPtr1 = byte1; 3470 3471 *dstPtr2 = byte2; 3472 3473 *dstPtr3 = byte3; 3474 3475 } 3476 3477 fBitOffset += fCodeSize; 3478 3479 } 3480 3481 /******************************************************************************/ 3482 3483 void dng_lzw_compressor::Compress (const uint8 *sPtr, 3484 uint8 *dPtr, 3485 uint32 sCount, 3486 uint32 &dCount) 3487 { 3488 3489 fDstPtr = dPtr; 3490 3491 fBitOffset = 0; 3492 3493 InitTable (); 3494 3495 PutCodeWord (kResetCode); 3496 3497 int32 code = -1; 3498 3499 int32 pixel; 3500 3501 if (sCount > 0) 3502 { 3503 3504 pixel = *sPtr; 3505 sPtr = sPtr + 1; 3506 code = pixel; 3507 3508 sCount--; 3509 3510 while (sCount--) 3511 { 3512 3513 pixel = *sPtr; 3514 sPtr = sPtr + 1; 3515 3516 int32 newCode = SearchTable (code, pixel); 3517 3518 if (newCode == -1) 3519 { 3520 3521 PutCodeWord (code); 3522 3523 if (fNextCode < 4093) 3524 { 3525 AddTable (code, pixel); 3526 } 3527 else 3528 { 3529 PutCodeWord (kResetCode); 3530 InitTable (); 3531 } 3532 3533 code = pixel; 3534 3535 } 3536 3537 else 3538 code = newCode; 3539 3540 } 3541 3542 } 3543 3544 if (code != -1) 3545 { 3546 PutCodeWord (code); 3547 AddTable (code, 0); 3548 } 3549 3550 PutCodeWord (kEndCode); 3551 3552 dCount = (fBitOffset + 7) >> 3; 3553 3554 } 3555 3556 /*****************************************************************************/ 3557 3558 #if qDNGUseLibJPEG 3559 3560 /*****************************************************************************/ 3561 3562 static void dng_error_exit (j_common_ptr cinfo) 3563 { 3564 3565 // Output message. 3566 3567 (*cinfo->err->output_message) (cinfo); 3568 3569 // Convert to a dng_exception. 3570 3571 switch (cinfo->err->msg_code) 3572 { 3573 3574 case JERR_OUT_OF_MEMORY: 3575 { 3576 ThrowMemoryFull (); 3577 break; 3578 } 3579 3580 default: 3581 { 3582 ThrowBadFormat (); 3583 } 3584 3585 } 3586 3587 } 3588 3589 /*****************************************************************************/ 3590 3591 static void dng_output_message (j_common_ptr cinfo) 3592 { 3593 3594 // Format message to string. 3595 3596 char buffer [JMSG_LENGTH_MAX]; 3597 3598 (*cinfo->err->format_message) (cinfo, buffer); 3599 3600 // Report the libjpeg message as a warning. 3601 3602 ReportWarning ("libjpeg", buffer); 3603 3604 } 3605 3606 /*****************************************************************************/ 3607 3608 struct dng_jpeg_stream_dest 3609 { 3610 3611 struct jpeg_destination_mgr pub; 3612 3613 dng_stream *fStream; 3614 3615 uint8 fBuffer [4096]; 3616 3617 }; 3618 3619 /*****************************************************************************/ 3620 3621 static void dng_init_destination (j_compress_ptr cinfo) 3622 { 3623 3624 dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest; 3625 3626 dest->pub.next_output_byte = dest->fBuffer; 3627 dest->pub.free_in_buffer = sizeof (dest->fBuffer); 3628 3629 } 3630 3631 /*****************************************************************************/ 3632 3633 static boolean dng_empty_output_buffer (j_compress_ptr cinfo) 3634 { 3635 3636 dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest; 3637 3638 dest->fStream->Put (dest->fBuffer, sizeof (dest->fBuffer)); 3639 3640 dest->pub.next_output_byte = dest->fBuffer; 3641 dest->pub.free_in_buffer = sizeof (dest->fBuffer); 3642 3643 return TRUE; 3644 3645 } 3646 3647 /*****************************************************************************/ 3648 3649 static void dng_term_destination (j_compress_ptr cinfo) 3650 { 3651 3652 dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest; 3653 3654 uint32 datacount = sizeof (dest->fBuffer) - 3655 (uint32) dest->pub.free_in_buffer; 3656 3657 if (datacount) 3658 { 3659 dest->fStream->Put (dest->fBuffer, datacount); 3660 } 3661 3662 } 3663 3664 /*****************************************************************************/ 3665 3666 static void jpeg_set_adobe_quality (struct jpeg_compress_struct *cinfo, 3667 int32 quality) 3668 { 3669 3670 // If out of range, map to default. 3671 3672 if (quality < 0 || quality > 12) 3673 { 3674 quality = 10; 3675 } 3676 3677 // Adobe turns off chroma downsampling at high quality levels. 3678 3679 bool useChromaDownsampling = (quality <= 6); 3680 3681 // Approximate mapping from Adobe quality levels to LibJPEG levels. 3682 3683 const int kLibJPEGQuality [13] = 3684 { 3685 5, 11, 23, 34, 46, 63, 76, 77, 86, 90, 94, 97, 99 3686 }; 3687 3688 quality = kLibJPEGQuality [quality]; 3689 3690 jpeg_set_quality (cinfo, quality, TRUE); 3691 3692 // LibJPEG defaults to always using chroma downsampling. Turn if off 3693 // if we need it off to match Adobe. 3694 3695 if (!useChromaDownsampling) 3696 { 3697 3698 cinfo->comp_info [0].h_samp_factor = 1; 3699 cinfo->comp_info [0].h_samp_factor = 1; 3700 3701 } 3702 3703 } 3704 3705 /*****************************************************************************/ 3706 3707 #endif 3708 3709 /*****************************************************************************/ 3710 3711 void dng_image_writer::WriteData (dng_host &host, 3712 const dng_ifd &ifd, 3713 dng_stream &stream, 3714 dng_pixel_buffer &buffer, 3715 AutoPtr<dng_memory_block> &compressedBuffer) 3716 { 3717 3718 switch (ifd.fCompression) 3719 { 3720 3721 case ccUncompressed: 3722 { 3723 3724 // Special case support for when we save to 8-bits from 3725 // 16-bit data. 3726 3727 if (ifd.fBitsPerSample [0] == 8 && buffer.fPixelType == ttShort) 3728 { 3729 3730 uint32 count = buffer.fRowStep * 3731 buffer.fArea.H (); 3732 3733 const uint16 *sPtr = (const uint16 *) buffer.fData; 3734 3735 for (uint32 j = 0; j < count; j++) 3736 { 3737 3738 stream.Put_uint8 ((uint8) sPtr [j]); 3739 3740 } 3741 3742 } 3743 3744 else 3745 { 3746 3747 // Swap bytes if required. 3748 3749 if (stream.SwapBytes ()) 3750 { 3751 3752 ByteSwapBuffer (host, buffer); 3753 3754 } 3755 3756 // Write the bytes. 3757 3758 stream.Put (buffer.fData, buffer.fRowStep * 3759 buffer.fArea.H () * 3760 buffer.fPixelSize); 3761 3762 } 3763 3764 break; 3765 3766 } 3767 3768 case ccLZW: 3769 case ccDeflate: 3770 { 3771 3772 // Both these compression algorithms are byte based. The floating 3773 // point predictor already does byte ordering, so don't ever swap 3774 // when using it. 3775 3776 if (stream.SwapBytes () && ifd.fPredictor != cpFloatingPoint) 3777 { 3778 3779 ByteSwapBuffer (host, 3780 buffer); 3781 3782 } 3783 3784 // Run the compression algorithm. 3785 3786 uint32 sBytes = buffer.fRowStep * 3787 buffer.fArea.H () * 3788 buffer.fPixelSize; 3789 3790 uint8 *sBuffer = (uint8 *) buffer.fData; 3791 3792 uint32 dBytes = 0; 3793 3794 uint8 *dBuffer = compressedBuffer->Buffer_uint8 (); 3795 3796 if (ifd.fCompression == ccLZW) 3797 { 3798 3799 dng_lzw_compressor lzwCompressor; 3800 3801 lzwCompressor.Compress (sBuffer, 3802 dBuffer, 3803 sBytes, 3804 dBytes); 3805 3806 } 3807 3808 else 3809 { 3810 3811 uLongf dCount = compressedBuffer->LogicalSize (); 3812 3813 int32 level = Z_DEFAULT_COMPRESSION; 3814 3815 if (ifd.fCompressionQuality >= Z_BEST_SPEED && 3816 ifd.fCompressionQuality <= Z_BEST_COMPRESSION) 3817 { 3818 3819 level = ifd.fCompressionQuality; 3820 3821 } 3822 3823 int zResult = ::compress2 (dBuffer, 3824 &dCount, 3825 sBuffer, 3826 sBytes, 3827 level); 3828 3829 if (zResult != Z_OK) 3830 { 3831 3832 ThrowMemoryFull (); 3833 3834 } 3835 3836 dBytes = (uint32) dCount; 3837 3838 } 3839 3840 if (dBytes > compressedBuffer->LogicalSize ()) 3841 { 3842 3843 DNG_REPORT ("Compression output buffer overflow"); 3844 3845 ThrowProgramError (); 3846 3847 } 3848 3849 stream.Put (dBuffer, dBytes); 3850 3851 return; 3852 3853 } 3854 3855 case ccJPEG: 3856 { 3857 3858 dng_pixel_buffer temp (buffer); 3859 3860 if (buffer.fPixelType == ttByte) 3861 { 3862 3863 // The lossless JPEG encoder needs 16-bit data, so if we are 3864 // are saving 8 bit data, we need to pad it out to 16-bits. 3865 3866 temp.fData = compressedBuffer->Buffer (); 3867 3868 temp.fPixelType = ttShort; 3869 temp.fPixelSize = 2; 3870 3871 temp.CopyArea (buffer, 3872 buffer.fArea, 3873 buffer.fPlane, 3874 buffer.fPlanes); 3875 3876 } 3877 3878 EncodeLosslessJPEG ((const uint16 *) temp.fData, 3879 temp.fArea.H (), 3880 temp.fArea.W (), 3881 temp.fPlanes, 3882 ifd.fBitsPerSample [0], 3883 temp.fRowStep, 3884 temp.fColStep, 3885 stream); 3886 3887 break; 3888 3889 } 3890 3891 #if qDNGUseLibJPEG 3892 3893 case ccLossyJPEG: 3894 { 3895 3896 struct jpeg_compress_struct cinfo; 3897 3898 // Setup the error manager. 3899 3900 struct jpeg_error_mgr jerr; 3901 3902 cinfo.err = jpeg_std_error (&jerr); 3903 3904 jerr.error_exit = dng_error_exit; 3905 jerr.output_message = dng_output_message; 3906 3907 try 3908 { 3909 3910 // Create the compression context. 3911 3912 jpeg_create_compress (&cinfo); 3913 3914 // Setup the destination manager to write to stream. 3915 3916 dng_jpeg_stream_dest dest; 3917 3918 dest.fStream = &stream; 3919 3920 dest.pub.init_destination = dng_init_destination; 3921 dest.pub.empty_output_buffer = dng_empty_output_buffer; 3922 dest.pub.term_destination = dng_term_destination; 3923 3924 cinfo.dest = &dest.pub; 3925 3926 // Setup basic image info. 3927 3928 cinfo.image_width = buffer.fArea.W (); 3929 cinfo.image_height = buffer.fArea.H (); 3930 cinfo.input_components = buffer.fPlanes; 3931 3932 switch (buffer.fPlanes) 3933 { 3934 3935 case 1: 3936 cinfo.in_color_space = JCS_GRAYSCALE; 3937 break; 3938 3939 case 3: 3940 cinfo.in_color_space = JCS_RGB; 3941 break; 3942 3943 case 4: 3944 cinfo.in_color_space = JCS_CMYK; 3945 break; 3946 3947 default: 3948 ThrowProgramError (); 3949 3950 } 3951 3952 // Setup the compression parameters. 3953 3954 jpeg_set_defaults (&cinfo); 3955 3956 jpeg_set_adobe_quality (&cinfo, ifd.fCompressionQuality); 3957 3958 // Write the JPEG header. 3959 3960 jpeg_start_compress (&cinfo, TRUE); 3961 3962 // Write the scanlines. 3963 3964 for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++) 3965 { 3966 3967 uint8 *sampArray [1]; 3968 3969 sampArray [0] = buffer.DirtyPixel_uint8 (row, 3970 buffer.fArea.l, 3971 0); 3972 3973 jpeg_write_scanlines (&cinfo, sampArray, 1); 3974 3975 } 3976 3977 // Cleanup. 3978 3979 jpeg_finish_compress (&cinfo); 3980 3981 jpeg_destroy_compress (&cinfo); 3982 3983 } 3984 3985 catch (...) 3986 { 3987 3988 jpeg_destroy_compress (&cinfo); 3989 3990 throw; 3991 3992 } 3993 3994 return; 3995 3996 } 3997 3998 #endif 3999 4000 default: 4001 { 4002 4003 ThrowProgramError (); 4004 4005 } 4006 4007 } 4008 4009 } 4010 4011 /******************************************************************************/ 4012 4013 void dng_image_writer::EncodeJPEGPreview (dng_host &host, 4014 const dng_image &image, 4015 dng_jpeg_preview &preview, 4016 int32 quality) 4017 { 4018 4019 #if qDNGUseLibJPEG 4020 4021 dng_memory_stream stream (host.Allocator ()); 4022 4023 struct jpeg_compress_struct cinfo; 4024 4025 // Setup the error manager. 4026 4027 struct jpeg_error_mgr jerr; 4028 4029 cinfo.err = jpeg_std_error (&jerr); 4030 4031 jerr.error_exit = dng_error_exit; 4032 jerr.output_message = dng_output_message; 4033 4034 try 4035 { 4036 4037 // Create the compression context. 4038 4039 jpeg_create_compress (&cinfo); 4040 4041 // Setup the destination manager to write to stream. 4042 4043 dng_jpeg_stream_dest dest; 4044 4045 dest.fStream = &stream; 4046 4047 dest.pub.init_destination = dng_init_destination; 4048 dest.pub.empty_output_buffer = dng_empty_output_buffer; 4049 dest.pub.term_destination = dng_term_destination; 4050 4051 cinfo.dest = &dest.pub; 4052 4053 // Setup basic image info. 4054 4055 cinfo.image_width = image.Bounds ().W (); 4056 cinfo.image_height = image.Bounds ().H (); 4057 cinfo.input_components = image.Planes (); 4058 4059 switch (image.Planes ()) 4060 { 4061 4062 case 1: 4063 cinfo.in_color_space = JCS_GRAYSCALE; 4064 break; 4065 4066 case 3: 4067 cinfo.in_color_space = JCS_RGB; 4068 break; 4069 4070 default: 4071 ThrowProgramError (); 4072 4073 } 4074 4075 // Setup the compression parameters. 4076 4077 jpeg_set_defaults (&cinfo); 4078 4079 jpeg_set_adobe_quality (&cinfo, quality); 4080 4081 // Find some preview information based on the compression settings. 4082 4083 preview.fPreviewSize = image.Size (); 4084 4085 if (image.Planes () == 1) 4086 { 4087 4088 preview.fPhotometricInterpretation = piBlackIsZero; 4089 4090 } 4091 4092 else 4093 { 4094 4095 preview.fPhotometricInterpretation = piYCbCr; 4096 4097 preview.fYCbCrSubSampling.h = cinfo.comp_info [0].h_samp_factor; 4098 preview.fYCbCrSubSampling.v = cinfo.comp_info [0].v_samp_factor; 4099 4100 } 4101 4102 // Write the JPEG header. 4103 4104 jpeg_start_compress (&cinfo, TRUE); 4105 4106 // Write the scanlines. 4107 4108 dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (), ttByte, 4109 pcInterleaved, NULL); 4110 4111 AutoPtr<dng_memory_block> bufferData (host.Allocate (buffer.fRowStep)); 4112 4113 buffer.fData = bufferData->Buffer (); 4114 4115 for (uint32 row = 0; row < cinfo.image_height; row++) 4116 { 4117 4118 buffer.fArea.t = row; 4119 buffer.fArea.b = row + 1; 4120 4121 image.Get (buffer); 4122 4123 uint8 *sampArray [1]; 4124 4125 sampArray [0] = buffer.DirtyPixel_uint8 (row, 4126 buffer.fArea.l, 4127 0); 4128 4129 jpeg_write_scanlines (&cinfo, sampArray, 1); 4130 4131 } 4132 4133 // Cleanup. 4134 4135 jpeg_finish_compress (&cinfo); 4136 4137 jpeg_destroy_compress (&cinfo); 4138 4139 } 4140 4141 catch (...) 4142 { 4143 4144 jpeg_destroy_compress (&cinfo); 4145 4146 throw; 4147 4148 } 4149 4150 preview.fCompressedData.Reset (stream.AsMemoryBlock (host.Allocator ())); 4151 4152 #else 4153 4154 (void) host; 4155 (void) image; 4156 (void) preview; 4157 (void) quality; 4158 4159 ThrowProgramError ("No JPEG encoder"); 4160 4161 #endif 4162 4163 } 4164 4165 /*****************************************************************************/ 4166 4167 void dng_image_writer::WriteTile (dng_host &host, 4168 const dng_ifd &ifd, 4169 dng_stream &stream, 4170 const dng_image &image, 4171 const dng_rect &tileArea, 4172 uint32 fakeChannels, 4173 AutoPtr<dng_memory_block> &compressedBuffer, 4174 AutoPtr<dng_memory_block> &uncompressedBuffer, 4175 AutoPtr<dng_memory_block> &subTileBlockBuffer, 4176 AutoPtr<dng_memory_block> &tempBuffer) 4177 { 4178 4179 // Create pixel buffer to hold uncompressed tile. 4180 4181 dng_pixel_buffer buffer (tileArea, 0, ifd.fSamplesPerPixel, 4182 image.PixelType(), pcInterleaved, uncompressedBuffer->Buffer()); 4183 4184 // Get the uncompressed data. 4185 4186 image.Get (buffer, dng_image::edge_zero); 4187 4188 // Deal with sub-tile blocks. 4189 4190 if (ifd.fSubTileBlockRows > 1) 4191 { 4192 4193 ReorderSubTileBlocks (ifd, 4194 buffer, 4195 uncompressedBuffer, 4196 subTileBlockBuffer); 4197 4198 } 4199 4200 // Floating point depth conversion. 4201 4202 if (ifd.fSampleFormat [0] == sfFloatingPoint) 4203 { 4204 4205 if (ifd.fBitsPerSample [0] == 16) 4206 { 4207 4208 uint32 *srcPtr = (uint32 *) buffer.fData; 4209 uint16 *dstPtr = (uint16 *) buffer.fData; 4210 4211 uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes; 4212 4213 for (uint32 j = 0; j < pixels; j++) 4214 { 4215 4216 dstPtr [j] = DNG_FloatToHalf (srcPtr [j]); 4217 4218 } 4219 4220 buffer.fPixelSize = 2; 4221 4222 } 4223 4224 if (ifd.fBitsPerSample [0] == 24) 4225 { 4226 4227 uint32 *srcPtr = (uint32 *) buffer.fData; 4228 uint8 *dstPtr = (uint8 *) buffer.fData; 4229 4230 uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes; 4231 4232 if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint || 4233 ifd.fPredictor == cpFloatingPointX2 || 4234 ifd.fPredictor == cpFloatingPointX4) 4235 { 4236 4237 for (uint32 j = 0; j < pixels; j++) 4238 { 4239 4240 DNG_FloatToFP24 (srcPtr [j], dstPtr); 4241 4242 dstPtr += 3; 4243 4244 } 4245 4246 } 4247 4248 else 4249 { 4250 4251 for (uint32 j = 0; j < pixels; j++) 4252 { 4253 4254 uint8 output [3]; 4255 4256 DNG_FloatToFP24 (srcPtr [j], output); 4257 4258 dstPtr [0] = output [2]; 4259 dstPtr [1] = output [1]; 4260 dstPtr [2] = output [0]; 4261 4262 dstPtr += 3; 4263 4264 } 4265 4266 } 4267 4268 buffer.fPixelSize = 3; 4269 4270 } 4271 4272 } 4273 4274 // Run predictor. 4275 4276 EncodePredictor (host, 4277 ifd, 4278 buffer, 4279 tempBuffer); 4280 4281 // Adjust pixel buffer for fake channels. 4282 4283 if (fakeChannels > 1) 4284 { 4285 4286 buffer.fPlanes *= fakeChannels; 4287 buffer.fColStep *= fakeChannels; 4288 4289 buffer.fArea.r = buffer.fArea.l + (buffer.fArea.W () / fakeChannels); 4290 4291 } 4292 4293 // Compress (if required) and write out the data. 4294 4295 WriteData (host, 4296 ifd, 4297 stream, 4298 buffer, 4299 compressedBuffer); 4300 4301 } 4302 4303 /*****************************************************************************/ 4304 4305 class dng_write_tiles_task : public dng_area_task 4306 { 4307 4308 private: 4309 4310 dng_image_writer &fImageWriter; 4311 4312 dng_host &fHost; 4313 4314 const dng_ifd &fIFD; 4315 4316 dng_basic_tag_set &fBasic; 4317 4318 dng_stream &fStream; 4319 4320 const dng_image &fImage; 4321 4322 uint32 fFakeChannels; 4323 4324 uint32 fTilesDown; 4325 4326 uint32 fTilesAcross; 4327 4328 uint32 fCompressedSize; 4329 4330 uint32 fUncompressedSize; 4331 4332 dng_mutex fMutex1; 4333 4334 uint32 fNextTileIndex; 4335 4336 dng_mutex fMutex2; 4337 4338 dng_condition fCondition; 4339 4340 bool fTaskFailed; 4341 4342 uint32 fWriteTileIndex; 4343 4344 public: 4345 4346 dng_write_tiles_task (dng_image_writer &imageWriter, 4347 dng_host &host, 4348 const dng_ifd &ifd, 4349 dng_basic_tag_set &basic, 4350 dng_stream &stream, 4351 const dng_image &image, 4352 uint32 fakeChannels, 4353 uint32 tilesDown, 4354 uint32 tilesAcross, 4355 uint32 compressedSize, 4356 uint32 uncompressedSize) 4357 4358 : fImageWriter (imageWriter) 4359 , fHost (host) 4360 , fIFD (ifd) 4361 , fBasic (basic) 4362 , fStream (stream) 4363 , fImage (image) 4364 , fFakeChannels (fakeChannels) 4365 , fTilesDown (tilesDown) 4366 , fTilesAcross (tilesAcross) 4367 , fCompressedSize (compressedSize) 4368 , fUncompressedSize (uncompressedSize) 4369 , fMutex1 ("dng_write_tiles_task_1") 4370 , fNextTileIndex (0) 4371 , fMutex2 ("dng_write_tiles_task_2") 4372 , fCondition () 4373 , fTaskFailed (false) 4374 , fWriteTileIndex (0) 4375 4376 { 4377 4378 fMinTaskArea = 16 * 16; 4379 fUnitCell = dng_point (16, 16); 4380 fMaxTileSize = dng_point (16, 16); 4381 4382 } 4383 4384 void Process (uint32 /* threadIndex */, 4385 const dng_rect & /* tile */, 4386 dng_abort_sniffer *sniffer) 4387 { 4388 4389 try 4390 { 4391 4392 AutoPtr<dng_memory_block> compressedBuffer; 4393 AutoPtr<dng_memory_block> uncompressedBuffer; 4394 AutoPtr<dng_memory_block> subTileBlockBuffer; 4395 AutoPtr<dng_memory_block> tempBuffer; 4396 4397 if (fCompressedSize) 4398 { 4399 compressedBuffer.Reset (fHost.Allocate (fCompressedSize)); 4400 } 4401 4402 if (fUncompressedSize) 4403 { 4404 uncompressedBuffer.Reset (fHost.Allocate (fUncompressedSize)); 4405 } 4406 4407 if (fIFD.fSubTileBlockRows > 1 && fUncompressedSize) 4408 { 4409 subTileBlockBuffer.Reset (fHost.Allocate (fUncompressedSize)); 4410 } 4411 4412 while (true) 4413 { 4414 4415 // Find tile index to compress. 4416 4417 uint32 tileIndex; 4418 4419 { 4420 4421 dng_lock_mutex lock (&fMutex1); 4422 4423 if (fNextTileIndex == fTilesDown * fTilesAcross) 4424 { 4425 return; 4426 } 4427 4428 tileIndex = fNextTileIndex++; 4429 4430 } 4431 4432 dng_abort_sniffer::SniffForAbort (sniffer); 4433 4434 // Compress tile. 4435 4436 uint32 rowIndex = tileIndex / fTilesAcross; 4437 4438 uint32 colIndex = tileIndex - rowIndex * fTilesAcross; 4439 4440 dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex); 4441 4442 dng_memory_stream tileStream (fHost.Allocator ()); 4443 4444 tileStream.SetLittleEndian (fStream.LittleEndian ()); 4445 4446 dng_host host (&fHost.Allocator (), 4447 sniffer); 4448 4449 fImageWriter.WriteTile (host, 4450 fIFD, 4451 tileStream, 4452 fImage, 4453 tileArea, 4454 fFakeChannels, 4455 compressedBuffer, 4456 uncompressedBuffer, 4457 subTileBlockBuffer, 4458 tempBuffer); 4459 4460 tileStream.Flush (); 4461 4462 uint32 tileByteCount = (uint32) tileStream.Length (); 4463 4464 tileStream.SetReadPosition (0); 4465 4466 // Wait until it is our turn to write tile. 4467 4468 { 4469 4470 dng_lock_mutex lock (&fMutex2); 4471 4472 while (!fTaskFailed && 4473 fWriteTileIndex != tileIndex) 4474 { 4475 4476 fCondition.Wait (fMutex2); 4477 4478 } 4479 4480 // If the task failed in another thread, that thread already threw an exception. 4481 4482 if (fTaskFailed) 4483 return; 4484 4485 } 4486 4487 dng_abort_sniffer::SniffForAbort (sniffer); 4488 4489 // Remember this offset. 4490 4491 uint32 tileOffset = (uint32) fStream.Position (); 4492 4493 fBasic.SetTileOffset (tileIndex, tileOffset); 4494 4495 // Copy tile stream for tile into main stream. 4496 4497 tileStream.CopyToStream (fStream, tileByteCount); 4498 4499 // Update tile count. 4500 4501 fBasic.SetTileByteCount (tileIndex, tileByteCount); 4502 4503 // Keep the tiles on even byte offsets. 4504 4505 if (tileByteCount & 1) 4506 { 4507 fStream.Put_uint8 (0); 4508 } 4509 4510 // Let other threads know it is safe to write to stream. 4511 4512 { 4513 4514 dng_lock_mutex lock (&fMutex2); 4515 4516 // If the task failed in another thread, that thread already threw an exception. 4517 4518 if (fTaskFailed) 4519 return; 4520 4521 fWriteTileIndex++; 4522 4523 fCondition.Broadcast (); 4524 4525 } 4526 4527 } 4528 4529 } 4530 4531 catch (...) 4532 { 4533 4534 // If first to fail, wake up any threads waiting on condition. 4535 4536 bool needBroadcast = false; 4537 4538 { 4539 4540 dng_lock_mutex lock (&fMutex2); 4541 4542 needBroadcast = !fTaskFailed; 4543 fTaskFailed = true; 4544 4545 } 4546 4547 if (needBroadcast) 4548 fCondition.Broadcast (); 4549 4550 throw; 4551 4552 } 4553 4554 } 4555 4556 private: 4557 4558 // Hidden copy constructor and assignment operator. 4559 4560 dng_write_tiles_task (const dng_write_tiles_task &); 4561 4562 dng_write_tiles_task & operator= (const dng_write_tiles_task &); 4563 4564 }; 4565 4566 /*****************************************************************************/ 4567 4568 void dng_image_writer::WriteImage (dng_host &host, 4569 const dng_ifd &ifd, 4570 dng_basic_tag_set &basic, 4571 dng_stream &stream, 4572 const dng_image &image, 4573 uint32 fakeChannels) 4574 { 4575 4576 // Deal with row interleaved images. 4577 4578 if (ifd.fRowInterleaveFactor > 1 && 4579 ifd.fRowInterleaveFactor < ifd.fImageLength) 4580 { 4581 4582 dng_ifd tempIFD (ifd); 4583 4584 tempIFD.fRowInterleaveFactor = 1; 4585 4586 dng_row_interleaved_image tempImage (*((dng_image *) &image), 4587 ifd.fRowInterleaveFactor); 4588 4589 WriteImage (host, 4590 tempIFD, 4591 basic, 4592 stream, 4593 tempImage, 4594 fakeChannels); 4595 4596 return; 4597 4598 } 4599 4600 // Compute basic information. 4601 4602 uint32 bytesPerSample = TagTypeSize (image.PixelType ()); 4603 4604 uint32 bytesPerPixel = SafeUint32Mult (ifd.fSamplesPerPixel, 4605 bytesPerSample); 4606 4607 uint32 tileRowBytes = SafeUint32Mult (ifd.fTileWidth, bytesPerPixel); 4608 4609 // If we can compute the number of bytes needed to store the 4610 // data, we can split the write for each tile into sub-tiles. 4611 4612 uint32 subTileLength = ifd.fTileLength; 4613 4614 if (ifd.TileByteCount (ifd.TileArea (0, 0)) != 0) 4615 { 4616 4617 subTileLength = Pin_uint32 (ifd.fSubTileBlockRows, 4618 kImageBufferSize / tileRowBytes, 4619 ifd.fTileLength); 4620 4621 // Don't split sub-tiles across subTileBlocks. 4622 4623 subTileLength = subTileLength / ifd.fSubTileBlockRows 4624 * ifd.fSubTileBlockRows; 4625 4626 } 4627 4628 // Find size of uncompressed buffer. 4629 4630 uint32 uncompressedSize = SafeUint32Mult(subTileLength, tileRowBytes); 4631 4632 // Find size of compressed buffer, if required. 4633 4634 uint32 compressedSize = CompressedBufferSize (ifd, uncompressedSize); 4635 4636 // See if we can do this write using multiple threads. 4637 4638 uint32 tilesAcross = ifd.TilesAcross (); 4639 uint32 tilesDown = ifd.TilesDown (); 4640 4641 bool useMultipleThreads = (tilesDown * tilesAcross >= 2) && 4642 (host.PerformAreaTaskThreads () > 1) && 4643 (subTileLength == ifd.fTileLength) && 4644 (ifd.fCompression != ccUncompressed); 4645 4646 4647 #if qImagecore 4648 useMultipleThreads = false; 4649 #endif 4650 4651 if (useMultipleThreads) 4652 { 4653 4654 uint32 threadCount = Min_uint32 (tilesDown * tilesAcross, 4655 host.PerformAreaTaskThreads ()); 4656 4657 dng_write_tiles_task task (*this, 4658 host, 4659 ifd, 4660 basic, 4661 stream, 4662 image, 4663 fakeChannels, 4664 tilesDown, 4665 tilesAcross, 4666 compressedSize, 4667 uncompressedSize); 4668 4669 host.PerformAreaTask (task, 4670 dng_rect (0, 0, 16, 16 * threadCount)); 4671 4672 } 4673 4674 else 4675 { 4676 4677 AutoPtr<dng_memory_block> compressedBuffer; 4678 AutoPtr<dng_memory_block> uncompressedBuffer; 4679 AutoPtr<dng_memory_block> subTileBlockBuffer; 4680 AutoPtr<dng_memory_block> tempBuffer; 4681 4682 if (compressedSize) 4683 { 4684 compressedBuffer.Reset (host.Allocate (compressedSize)); 4685 } 4686 4687 if (uncompressedSize) 4688 { 4689 uncompressedBuffer.Reset (host.Allocate (uncompressedSize)); 4690 } 4691 4692 if (ifd.fSubTileBlockRows > 1 && uncompressedSize) 4693 { 4694 subTileBlockBuffer.Reset (host.Allocate (uncompressedSize)); 4695 } 4696 4697 // Write out each tile. 4698 4699 uint32 tileIndex = 0; 4700 4701 for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++) 4702 { 4703 4704 for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++) 4705 { 4706 4707 // Remember this offset. 4708 4709 uint32 tileOffset = (uint32) stream.Position (); 4710 4711 basic.SetTileOffset (tileIndex, tileOffset); 4712 4713 // Split tile into sub-tiles if possible. 4714 4715 dng_rect tileArea = ifd.TileArea (rowIndex, colIndex); 4716 4717 uint32 subTileCount = (tileArea.H () + subTileLength - 1) / 4718 subTileLength; 4719 4720 for (uint32 subIndex = 0; subIndex < subTileCount; subIndex++) 4721 { 4722 4723 host.SniffForAbort (); 4724 4725 dng_rect subArea (tileArea); 4726 4727 subArea.t = tileArea.t + subIndex * subTileLength; 4728 4729 subArea.b = Min_int32 (subArea.t + subTileLength, 4730 tileArea.b); 4731 4732 // Write the sub-tile. 4733 4734 WriteTile (host, 4735 ifd, 4736 stream, 4737 image, 4738 subArea, 4739 fakeChannels, 4740 compressedBuffer, 4741 uncompressedBuffer, 4742 subTileBlockBuffer, 4743 tempBuffer); 4744 4745 } 4746 4747 // Update tile count. 4748 4749 uint32 tileByteCount = (uint32) stream.Position () - tileOffset; 4750 4751 basic.SetTileByteCount (tileIndex, tileByteCount); 4752 4753 tileIndex++; 4754 4755 // Keep the tiles on even byte offsets. 4756 4757 if (tileByteCount & 1) 4758 { 4759 stream.Put_uint8 (0); 4760 } 4761 4762 } 4763 4764 } 4765 4766 } 4767 4768 } 4769 4770 /*****************************************************************************/ 4771 4772 #if qDNGUseXMP 4773 4774 static void CopyString (const dng_xmp &oldXMP, 4775 dng_xmp &newXMP, 4776 const char *ns, 4777 const char *path, 4778 dng_string *exif = NULL) 4779 { 4780 4781 dng_string s; 4782 4783 if (oldXMP.GetString (ns, path, s)) 4784 { 4785 4786 if (s.NotEmpty ()) 4787 { 4788 4789 newXMP.SetString (ns, path, s); 4790 4791 if (exif) 4792 { 4793 4794 *exif = s; 4795 4796 } 4797 4798 } 4799 4800 } 4801 4802 } 4803 4804 /*****************************************************************************/ 4805 4806 static void CopyStringList (const dng_xmp &oldXMP, 4807 dng_xmp &newXMP, 4808 const char *ns, 4809 const char *path, 4810 bool isBag) 4811 { 4812 4813 dng_string_list list; 4814 4815 if (oldXMP.GetStringList (ns, path, list)) 4816 { 4817 4818 if (list.Count ()) 4819 { 4820 4821 newXMP.SetStringList (ns, path, list, isBag); 4822 4823 } 4824 4825 } 4826 4827 } 4828 4829 /*****************************************************************************/ 4830 4831 static void CopyAltLangDefault (const dng_xmp &oldXMP, 4832 dng_xmp &newXMP, 4833 const char *ns, 4834 const char *path, 4835 dng_string *exif = NULL) 4836 { 4837 4838 dng_string s; 4839 4840 if (oldXMP.GetAltLangDefault (ns, path, s)) 4841 { 4842 4843 if (s.NotEmpty ()) 4844 { 4845 4846 newXMP.SetAltLangDefault (ns, path, s); 4847 4848 if (exif) 4849 { 4850 4851 *exif = s; 4852 4853 } 4854 4855 } 4856 4857 } 4858 4859 } 4860 4861 /*****************************************************************************/ 4862 4863 static void CopyStructField (const dng_xmp &oldXMP, 4864 dng_xmp &newXMP, 4865 const char *ns, 4866 const char *path, 4867 const char *field) 4868 { 4869 4870 dng_string s; 4871 4872 if (oldXMP.GetStructField (ns, path, ns, field, s)) 4873 { 4874 4875 if (s.NotEmpty ()) 4876 { 4877 4878 newXMP.SetStructField (ns, path, ns, field, s); 4879 4880 } 4881 4882 } 4883 4884 } 4885 4886 /*****************************************************************************/ 4887 4888 static void CopyBoolean (const dng_xmp &oldXMP, 4889 dng_xmp &newXMP, 4890 const char *ns, 4891 const char *path) 4892 { 4893 4894 bool b; 4895 4896 if (oldXMP.GetBoolean (ns, path, b)) 4897 { 4898 4899 newXMP.SetBoolean (ns, path, b); 4900 4901 } 4902 4903 } 4904 4905 #endif 4906 4907 /*****************************************************************************/ 4908 4909 void dng_image_writer::CleanUpMetadata (dng_host &host, 4910 dng_metadata &metadata, 4911 dng_metadata_subset metadataSubset, 4912 const char *dstMIMI, 4913 const char *software) 4914 { 4915 4916 #if qDNGUseXMP 4917 4918 if (metadata.GetXMP () && metadata.GetExif ()) 4919 { 4920 4921 dng_xmp &newXMP (*metadata.GetXMP ()); 4922 dng_exif &newEXIF (*metadata.GetExif ()); 4923 4924 // Update software tag. 4925 4926 if (software) 4927 { 4928 4929 newEXIF.fSoftware.Set (software); 4930 4931 newXMP.Set (XMP_NS_XAP, 4932 "CreatorTool", 4933 software); 4934 4935 } 4936 4937 #if qDNGXMPDocOps 4938 4939 newXMP.DocOpsPrepareForSave (metadata.SourceMIMI ().Get (), 4940 dstMIMI); 4941 4942 #else 4943 4944 metadata.UpdateDateTimeToNow (); 4945 4946 #endif 4947 4948 // Update EXIF version to at least 2.3 so all the exif tags 4949 // can be written. 4950 4951 if (newEXIF.fExifVersion < DNG_CHAR4 ('0','2','3','0')) 4952 { 4953 4954 newEXIF.fExifVersion = DNG_CHAR4 ('0','2','3','0'); 4955 4956 newXMP.Set (XMP_NS_EXIF, "ExifVersion", "0230"); 4957 4958 } 4959 4960 // Resync EXIF, remove EXIF tags from XMP. 4961 4962 newXMP.SyncExif (newEXIF, 4963 metadata.GetOriginalExif (), 4964 false, 4965 true); 4966 4967 // Deal with ImageIngesterPro bug. This program is adding lots of 4968 // empty metadata strings into the XMP, which is screwing up Adobe CS4. 4969 // We are saving a new file, so this is a chance to clean up this mess. 4970 4971 newXMP.RemoveEmptyStringsAndArrays (XMP_NS_DC); 4972 newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP); 4973 newXMP.RemoveEmptyStringsAndArrays (XMP_NS_PHOTOSHOP); 4974 newXMP.RemoveEmptyStringsAndArrays (XMP_NS_IPTC); 4975 newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP_RIGHTS); 4976 newXMP.RemoveEmptyStringsAndArrays ("http://ns.iview-multimedia.com/mediapro/1.0/"); 4977 4978 // Process metadata subset. 4979 4980 if (metadataSubset == kMetadataSubset_CopyrightOnly || 4981 metadataSubset == kMetadataSubset_CopyrightAndContact) 4982 { 4983 4984 dng_xmp oldXMP (newXMP ); 4985 dng_exif oldEXIF (newEXIF); 4986 4987 // For these options, we start from nothing, and only fill in the 4988 // fields that we absolutely need. 4989 4990 newXMP.RemoveProperties (NULL); 4991 4992 newEXIF.SetEmpty (); 4993 4994 metadata.ClearMakerNote (); 4995 4996 // Move copyright related fields over. 4997 4998 CopyAltLangDefault (oldXMP, 4999 newXMP, 5000 XMP_NS_DC, 5001 "rights", 5002 &newEXIF.fCopyright); 5003 5004 CopyAltLangDefault (oldXMP, 5005 newXMP, 5006 XMP_NS_XAP_RIGHTS, 5007 "UsageTerms"); 5008 5009 CopyString (oldXMP, 5010 newXMP, 5011 XMP_NS_XAP_RIGHTS, 5012 "WebStatement"); 5013 5014 CopyBoolean (oldXMP, 5015 newXMP, 5016 XMP_NS_XAP_RIGHTS, 5017 "Marked"); 5018 5019 #if qDNGXMPDocOps 5020 5021 // Include basic DocOps fields, but not the full history. 5022 5023 CopyString (oldXMP, 5024 newXMP, 5025 XMP_NS_MM, 5026 "OriginalDocumentID"); 5027 5028 CopyString (oldXMP, 5029 newXMP, 5030 XMP_NS_MM, 5031 "DocumentID"); 5032 5033 CopyString (oldXMP, 5034 newXMP, 5035 XMP_NS_MM, 5036 "InstanceID"); 5037 5038 CopyString (oldXMP, 5039 newXMP, 5040 XMP_NS_XAP, 5041 "MetadataDate"); 5042 5043 #endif 5044 5045 // Copyright and Contact adds the contact info fields. 5046 5047 if (metadataSubset == kMetadataSubset_CopyrightAndContact) 5048 { 5049 5050 // Note: Save for Web is not including the dc:creator list, but it 5051 // is part of the IPTC contract info metadata panel, so I 5052 // think it should be copied as part of the contact info. 5053 5054 CopyStringList (oldXMP, 5055 newXMP, 5056 XMP_NS_DC, 5057 "creator", 5058 false); 5059 5060 // The first string dc:creator list is mirrored to the 5061 // the exif artist tag, so copy that also. 5062 5063 newEXIF.fArtist = oldEXIF.fArtist; 5064 5065 // Copy other contact fields. 5066 5067 CopyString (oldXMP, 5068 newXMP, 5069 XMP_NS_PHOTOSHOP, 5070 "AuthorsPosition"); 5071 5072 CopyStructField (oldXMP, 5073 newXMP, 5074 XMP_NS_IPTC, 5075 "CreatorContactInfo", 5076 "CiEmailWork"); 5077 5078 CopyStructField (oldXMP, 5079 newXMP, 5080 XMP_NS_IPTC, 5081 "CreatorContactInfo", 5082 "CiAdrExtadr"); 5083 5084 CopyStructField (oldXMP, 5085 newXMP, 5086 XMP_NS_IPTC, 5087 "CreatorContactInfo", 5088 "CiAdrCity"); 5089 5090 CopyStructField (oldXMP, 5091 newXMP, 5092 XMP_NS_IPTC, 5093 "CreatorContactInfo", 5094 "CiAdrRegion"); 5095 5096 CopyStructField (oldXMP, 5097 newXMP, 5098 XMP_NS_IPTC, 5099 "CreatorContactInfo", 5100 "CiAdrPcode"); 5101 5102 CopyStructField (oldXMP, 5103 newXMP, 5104 XMP_NS_IPTC, 5105 "CreatorContactInfo", 5106 "CiAdrCtry"); 5107 5108 CopyStructField (oldXMP, 5109 newXMP, 5110 XMP_NS_IPTC, 5111 "CreatorContactInfo", 5112 "CiTelWork"); 5113 5114 CopyStructField (oldXMP, 5115 newXMP, 5116 XMP_NS_IPTC, 5117 "CreatorContactInfo", 5118 "CiUrlWork"); 5119 5120 CopyAltLangDefault (oldXMP, 5121 newXMP, 5122 XMP_NS_DC, 5123 "title"); 5124 5125 } 5126 5127 } 5128 5129 else if (metadataSubset == kMetadataSubset_AllExceptCameraInfo || 5130 metadataSubset == kMetadataSubset_AllExceptCameraAndLocation || 5131 metadataSubset == kMetadataSubset_AllExceptLocationInfo) 5132 { 5133 5134 dng_xmp oldXMP (newXMP ); 5135 dng_exif oldEXIF (newEXIF); 5136 5137 if (metadataSubset == kMetadataSubset_AllExceptCameraInfo || 5138 metadataSubset == kMetadataSubset_AllExceptCameraAndLocation) 5139 { 5140 5141 // This removes most of the EXIF info, so just copy the fields 5142 // we are not deleting. 5143 5144 newEXIF.SetEmpty (); 5145 5146 newEXIF.fImageDescription = oldEXIF.fImageDescription; // Note: Differs from SFW 5147 newEXIF.fSoftware = oldEXIF.fSoftware; 5148 newEXIF.fArtist = oldEXIF.fArtist; 5149 newEXIF.fCopyright = oldEXIF.fCopyright; 5150 newEXIF.fCopyright2 = oldEXIF.fCopyright2; 5151 newEXIF.fDateTime = oldEXIF.fDateTime; 5152 newEXIF.fDateTimeOriginal = oldEXIF.fDateTimeOriginal; 5153 newEXIF.fDateTimeDigitized = oldEXIF.fDateTimeDigitized; 5154 newEXIF.fExifVersion = oldEXIF.fExifVersion; 5155 newEXIF.fImageUniqueID = oldEXIF.fImageUniqueID; 5156 5157 newEXIF.CopyGPSFrom (oldEXIF); 5158 5159 // Remove exif info from XMP. 5160 5161 newXMP.RemoveProperties (XMP_NS_EXIF); 5162 newXMP.RemoveProperties (XMP_NS_AUX); 5163 5164 // Remove Camera Raw info 5165 5166 newXMP.RemoveProperties (XMP_NS_CRS); 5167 newXMP.RemoveProperties (XMP_NS_CRSS); 5168 newXMP.RemoveProperties (XMP_NS_CRX); 5169 5170 // Remove DocOps history, since it contains the original 5171 // camera format. 5172 5173 newXMP.Remove (XMP_NS_MM, "History"); 5174 5175 // MakerNote contains camera info. 5176 5177 metadata.ClearMakerNote (); 5178 5179 } 5180 5181 if (metadataSubset == kMetadataSubset_AllExceptLocationInfo || 5182 metadataSubset == kMetadataSubset_AllExceptCameraAndLocation) 5183 { 5184 5185 // Remove GPS fields. 5186 5187 dng_exif blankExif; 5188 5189 newEXIF.CopyGPSFrom (blankExif); 5190 5191 // Remove MakerNote just in case, because we don't know 5192 // all of what is in it. 5193 5194 metadata.ClearMakerNote (); 5195 5196 // Remove XMP & IPTC location fields. 5197 5198 newXMP.Remove (XMP_NS_PHOTOSHOP, "City"); 5199 newXMP.Remove (XMP_NS_PHOTOSHOP, "State"); 5200 newXMP.Remove (XMP_NS_PHOTOSHOP, "Country"); 5201 newXMP.Remove (XMP_NS_IPTC, "Location"); 5202 newXMP.Remove (XMP_NS_IPTC, "CountryCode"); 5203 newXMP.Remove (XMP_NS_IPTC_EXT, "LocationCreated"); 5204 newXMP.Remove (XMP_NS_IPTC_EXT, "LocationShown"); 5205 5206 } 5207 5208 } 5209 5210 // Rebuild the legacy IPTC block, if needed. 5211 5212 bool isTIFF = (strcmp (dstMIMI, "image/tiff") == 0); 5213 bool isDNG = (strcmp (dstMIMI, "image/dng" ) == 0); 5214 5215 if (!isDNG) 5216 { 5217 5218 metadata.RebuildIPTC (host.Allocator (), 5219 isTIFF); 5220 5221 } 5222 5223 else 5224 { 5225 5226 metadata.ClearIPTC (); 5227 5228 } 5229 5230 // Clear format related XMP. 5231 5232 newXMP.ClearOrientation (); 5233 5234 newXMP.ClearImageInfo (); 5235 5236 newXMP.RemoveProperties (XMP_NS_DNG); 5237 5238 // All the formats we care about already keep the IPTC digest 5239 // elsewhere, do we don't need to write it to the XMP. 5240 5241 newXMP.ClearIPTCDigest (); 5242 5243 // Make sure that sidecar specific tags never get written to files. 5244 5245 newXMP.Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension"); 5246 newXMP.Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest"); 5247 5248 } 5249 5250 #endif 5251 5252 } 5253 5254 /*****************************************************************************/ 5255 5256 void dng_image_writer::WriteTIFF (dng_host &host, 5257 dng_stream &stream, 5258 const dng_image &image, 5259 uint32 photometricInterpretation, 5260 uint32 compression, 5261 dng_negative *negative, 5262 const dng_color_space *space, 5263 const dng_resolution *resolution, 5264 const dng_jpeg_preview *thumbnail, 5265 const dng_memory_block *imageResources, 5266 dng_metadata_subset metadataSubset) 5267 { 5268 5269 WriteTIFF (host, 5270 stream, 5271 image, 5272 photometricInterpretation, 5273 compression, 5274 negative ? &(negative->Metadata ()) : NULL, 5275 space, 5276 resolution, 5277 thumbnail, 5278 imageResources, 5279 metadataSubset); 5280 5281 } 5282 5283 /*****************************************************************************/ 5284 5285 void dng_image_writer::WriteTIFF (dng_host &host, 5286 dng_stream &stream, 5287 const dng_image &image, 5288 uint32 photometricInterpretation, 5289 uint32 compression, 5290 const dng_metadata *metadata, 5291 const dng_color_space *space, 5292 const dng_resolution *resolution, 5293 const dng_jpeg_preview *thumbnail, 5294 const dng_memory_block *imageResources, 5295 dng_metadata_subset metadataSubset) 5296 { 5297 5298 const void *profileData = NULL; 5299 uint32 profileSize = 0; 5300 5301 const uint8 *data = NULL; 5302 uint32 size = 0; 5303 5304 if (space && space->ICCProfile (size, data)) 5305 { 5306 5307 profileData = data; 5308 profileSize = size; 5309 5310 } 5311 5312 WriteTIFFWithProfile (host, 5313 stream, 5314 image, 5315 photometricInterpretation, 5316 compression, 5317 metadata, 5318 profileData, 5319 profileSize, 5320 resolution, 5321 thumbnail, 5322 imageResources, 5323 metadataSubset); 5324 5325 } 5326 5327 /*****************************************************************************/ 5328 5329 void dng_image_writer::WriteTIFFWithProfile (dng_host &host, 5330 dng_stream &stream, 5331 const dng_image &image, 5332 uint32 photometricInterpretation, 5333 uint32 compression, 5334 dng_negative *negative, 5335 const void *profileData, 5336 uint32 profileSize, 5337 const dng_resolution *resolution, 5338 const dng_jpeg_preview *thumbnail, 5339 const dng_memory_block *imageResources, 5340 dng_metadata_subset metadataSubset) 5341 { 5342 5343 WriteTIFFWithProfile (host, 5344 stream, 5345 image, 5346 photometricInterpretation, 5347 compression, 5348 negative ? &(negative->Metadata ()) : NULL, 5349 profileData, 5350 profileSize, 5351 resolution, 5352 thumbnail, 5353 imageResources, 5354 metadataSubset); 5355 5356 } 5357 5358 /*****************************************************************************/ 5359 5360 void dng_image_writer::WriteTIFFWithProfile (dng_host &host, 5361 dng_stream &stream, 5362 const dng_image &image, 5363 uint32 photometricInterpretation, 5364 uint32 compression, 5365 const dng_metadata *constMetadata, 5366 const void *profileData, 5367 uint32 profileSize, 5368 const dng_resolution *resolution, 5369 const dng_jpeg_preview *thumbnail, 5370 const dng_memory_block *imageResources, 5371 dng_metadata_subset metadataSubset) 5372 { 5373 5374 uint32 j; 5375 5376 AutoPtr<dng_metadata> metadata; 5377 5378 if (constMetadata) 5379 { 5380 5381 metadata.Reset (constMetadata->Clone (host.Allocator ())); 5382 5383 CleanUpMetadata (host, 5384 *metadata, 5385 metadataSubset, 5386 "image/tiff"); 5387 5388 } 5389 5390 dng_ifd ifd; 5391 5392 ifd.fNewSubFileType = sfMainImage; 5393 5394 ifd.fImageWidth = image.Bounds ().W (); 5395 ifd.fImageLength = image.Bounds ().H (); 5396 5397 ifd.fSamplesPerPixel = image.Planes (); 5398 5399 ifd.fBitsPerSample [0] = TagTypeSize (image.PixelType ()) * 8; 5400 5401 for (j = 1; j < ifd.fSamplesPerPixel; j++) 5402 { 5403 ifd.fBitsPerSample [j] = ifd.fBitsPerSample [0]; 5404 } 5405 5406 ifd.fPhotometricInterpretation = photometricInterpretation; 5407 5408 ifd.fCompression = compression; 5409 5410 if (ifd.fCompression == ccUncompressed) 5411 { 5412 5413 ifd.SetSingleStrip (); 5414 5415 } 5416 5417 else 5418 { 5419 5420 ifd.FindStripSize (128 * 1024); 5421 5422 ifd.fPredictor = cpHorizontalDifference; 5423 5424 } 5425 5426 uint32 extraSamples = 0; 5427 5428 switch (photometricInterpretation) 5429 { 5430 5431 case piBlackIsZero: 5432 { 5433 extraSamples = image.Planes () - 1; 5434 break; 5435 } 5436 5437 case piRGB: 5438 { 5439 extraSamples = image.Planes () - 3; 5440 break; 5441 } 5442 5443 default: 5444 break; 5445 5446 } 5447 5448 ifd.fExtraSamplesCount = extraSamples; 5449 5450 if (image.PixelType () == ttFloat) 5451 { 5452 5453 for (j = 0; j < ifd.fSamplesPerPixel; j++) 5454 { 5455 ifd.fSampleFormat [j] = sfFloatingPoint; 5456 } 5457 5458 } 5459 5460 dng_tiff_directory mainIFD; 5461 5462 dng_basic_tag_set basic (mainIFD, ifd); 5463 5464 // Resolution. 5465 5466 dng_resolution res; 5467 5468 if (resolution) 5469 { 5470 res = *resolution; 5471 } 5472 5473 tag_urational tagXResolution (tcXResolution, res.fXResolution); 5474 tag_urational tagYResolution (tcYResolution, res.fYResolution); 5475 5476 tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit); 5477 5478 if (resolution) 5479 { 5480 mainIFD.Add (&tagXResolution ); 5481 mainIFD.Add (&tagYResolution ); 5482 mainIFD.Add (&tagResolutionUnit); 5483 } 5484 5485 // ICC Profile. 5486 5487 tag_icc_profile iccProfileTag (profileData, profileSize); 5488 5489 if (iccProfileTag.Count ()) 5490 { 5491 mainIFD.Add (&iccProfileTag); 5492 } 5493 5494 // XMP metadata. 5495 5496 #if qDNGUseXMP 5497 5498 tag_xmp tagXMP (metadata.Get () ? metadata->GetXMP () : NULL); 5499 5500 if (tagXMP.Count ()) 5501 { 5502 mainIFD.Add (&tagXMP); 5503 } 5504 5505 #endif 5506 5507 // IPTC metadata. 5508 5509 tag_iptc tagIPTC (metadata.Get () ? metadata->IPTCData () : NULL, 5510 metadata.Get () ? metadata->IPTCLength () : 0); 5511 5512 if (tagIPTC.Count ()) 5513 { 5514 mainIFD.Add (&tagIPTC); 5515 } 5516 5517 // Adobe data (thumbnail and IPTC digest) 5518 5519 AutoPtr<dng_memory_block> adobeData (BuildAdobeData (host, 5520 metadata.Get (), 5521 thumbnail, 5522 imageResources)); 5523 5524 tag_uint8_ptr tagAdobe (tcAdobeData, 5525 adobeData->Buffer_uint8 (), 5526 adobeData->LogicalSize ()); 5527 5528 if (tagAdobe.Count ()) 5529 { 5530 mainIFD.Add (&tagAdobe); 5531 } 5532 5533 // Exif metadata. 5534 5535 exif_tag_set exifSet (mainIFD, 5536 metadata.Get () && metadata->GetExif () ? *metadata->GetExif () 5537 : dng_exif (), 5538 metadata.Get () ? metadata->IsMakerNoteSafe () : false, 5539 metadata.Get () ? metadata->MakerNoteData () : NULL, 5540 metadata.Get () ? metadata->MakerNoteLength () : 0, 5541 false); 5542 5543 // Find offset to main image data. 5544 5545 uint32 offsetMainIFD = 8; 5546 5547 uint32 offsetExifData = offsetMainIFD + mainIFD.Size (); 5548 5549 exifSet.Locate (offsetExifData); 5550 5551 uint32 offsetMainData = offsetExifData + exifSet.Size (); 5552 5553 stream.SetWritePosition (offsetMainData); 5554 5555 // Write the main image data. 5556 5557 WriteImage (host, 5558 ifd, 5559 basic, 5560 stream, 5561 image); 5562 5563 // Trim the file to this length. 5564 5565 stream.SetLength (stream.Position ()); 5566 5567 // TIFF has a 4G size limit. 5568 5569 if (stream.Length () > 0x0FFFFFFFFL) 5570 { 5571 ThrowImageTooBigTIFF (); 5572 } 5573 5574 // Write TIFF Header. 5575 5576 stream.SetWritePosition (0); 5577 5578 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII); 5579 5580 stream.Put_uint16 (42); 5581 5582 stream.Put_uint32 (offsetMainIFD); 5583 5584 // Write the IFDs. 5585 5586 mainIFD.Put (stream); 5587 5588 exifSet.Put (stream); 5589 5590 stream.Flush (); 5591 5592 } 5593 5594 /*****************************************************************************/ 5595 5596 void dng_image_writer::WriteDNG (dng_host &host, 5597 dng_stream &stream, 5598 dng_negative &negative, 5599 const dng_preview_list *previewList, 5600 uint32 maxBackwardVersion, 5601 bool uncompressed) 5602 { 5603 5604 WriteDNG (host, 5605 stream, 5606 negative, 5607 negative.Metadata (), 5608 previewList, 5609 maxBackwardVersion, 5610 uncompressed); 5611 5612 } 5613 5614 /*****************************************************************************/ 5615 5616 void dng_image_writer::WriteDNG (dng_host &host, 5617 dng_stream &stream, 5618 const dng_negative &negative, 5619 const dng_metadata &constMetadata, 5620 const dng_preview_list *previewList, 5621 uint32 maxBackwardVersion, 5622 bool uncompressed) 5623 { 5624 5625 uint32 j; 5626 5627 // Clean up metadata per MWG recommendations. 5628 5629 AutoPtr<dng_metadata> metadata (constMetadata.Clone (host.Allocator ())); 5630 5631 CleanUpMetadata (host, 5632 *metadata, 5633 kMetadataSubset_All, 5634 "image/dng"); 5635 5636 // Figure out the compression to use. Most of the time this is lossless 5637 // JPEG. 5638 5639 uint32 compression = uncompressed ? ccUncompressed : ccJPEG; 5640 5641 // Was the the original file lossy JPEG compressed? 5642 5643 const dng_jpeg_image *rawJPEGImage = negative.RawJPEGImage (); 5644 5645 // If so, can we save it using the requested compression and DNG version? 5646 5647 if (uncompressed || maxBackwardVersion < dngVersion_1_4_0_0) 5648 { 5649 5650 if (rawJPEGImage || negative.RawJPEGImageDigest ().IsValid ()) 5651 { 5652 5653 rawJPEGImage = NULL; 5654 5655 negative.ClearRawJPEGImageDigest (); 5656 5657 negative.ClearRawImageDigest (); 5658 5659 } 5660 5661 } 5662 5663 else if (rawJPEGImage) 5664 { 5665 5666 compression = ccLossyJPEG; 5667 5668 } 5669 5670 // Are we saving the original size tags? 5671 5672 bool saveOriginalDefaultFinalSize = false; 5673 bool saveOriginalBestQualityFinalSize = false; 5674 bool saveOriginalDefaultCropSize = false; 5675 5676 { 5677 5678 // See if we are saving a proxy image. 5679 5680 dng_point defaultFinalSize (negative.DefaultFinalHeight (), 5681 negative.DefaultFinalWidth ()); 5682 5683 saveOriginalDefaultFinalSize = (negative.OriginalDefaultFinalSize () != 5684 defaultFinalSize); 5685 5686 if (saveOriginalDefaultFinalSize) 5687 { 5688 5689 // If the save OriginalDefaultFinalSize tag, this changes the defaults 5690 // for the OriginalBestQualityFinalSize and OriginalDefaultCropSize tags. 5691 5692 saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () != 5693 defaultFinalSize); 5694 5695 saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () != 5696 dng_urational (defaultFinalSize.v, 1)) || 5697 (negative.OriginalDefaultCropSizeH () != 5698 dng_urational (defaultFinalSize.h, 1)); 5699 5700 } 5701 5702 else 5703 { 5704 5705 // Else these two tags default to the normal non-proxy size image values. 5706 5707 dng_point bestQualityFinalSize (negative.BestQualityFinalHeight (), 5708 negative.BestQualityFinalWidth ()); 5709 5710 saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () != 5711 bestQualityFinalSize); 5712 5713 saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () != 5714 negative.DefaultCropSizeV ()) || 5715 (negative.OriginalDefaultCropSizeH () != 5716 negative.DefaultCropSizeH ()); 5717 5718 } 5719 5720 } 5721 5722 // Is this a floating point image that we are saving? 5723 5724 bool isFloatingPoint = (negative.RawImage ().PixelType () == ttFloat); 5725 5726 // Does this image have a transparency mask? 5727 5728 bool hasTransparencyMask = (negative.RawTransparencyMask () != NULL); 5729 5730 // Should we save a compressed 32-bit integer file? 5731 5732 bool isCompressed32BitInteger = (negative.RawImage ().PixelType () == ttLong) && 5733 (maxBackwardVersion >= dngVersion_1_4_0_0) && 5734 (!uncompressed); 5735 5736 // Figure out what main version to use. 5737 5738 uint32 dngVersion = dngVersion_Current; 5739 5740 // Don't write version 1.4 files unless we actually use some feature of the 1.4 spec. 5741 5742 if (dngVersion == dngVersion_1_4_0_0) 5743 { 5744 5745 if (!rawJPEGImage && 5746 !isFloatingPoint && 5747 !hasTransparencyMask && 5748 !isCompressed32BitInteger && 5749 !saveOriginalDefaultFinalSize && 5750 !saveOriginalBestQualityFinalSize && 5751 !saveOriginalDefaultCropSize ) 5752 { 5753 5754 dngVersion = dngVersion_1_3_0_0; 5755 5756 } 5757 5758 } 5759 5760 // Figure out what backward version to use. 5761 5762 uint32 dngBackwardVersion = dngVersion_1_1_0_0; 5763 5764 #if defined(qTestRowInterleave) || defined(qTestSubTileBlockRows) || defined(qTestSubTileBlockCols) 5765 dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_2_0_0); 5766 #endif 5767 5768 dngBackwardVersion = Max_uint32 (dngBackwardVersion, 5769 negative.OpcodeList1 ().MinVersion (false)); 5770 5771 dngBackwardVersion = Max_uint32 (dngBackwardVersion, 5772 negative.OpcodeList2 ().MinVersion (false)); 5773 5774 dngBackwardVersion = Max_uint32 (dngBackwardVersion, 5775 negative.OpcodeList3 ().MinVersion (false)); 5776 5777 if (negative.GetMosaicInfo () && 5778 negative.GetMosaicInfo ()->fCFALayout >= 6) 5779 { 5780 dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_3_0_0); 5781 } 5782 5783 if (rawJPEGImage || isFloatingPoint || hasTransparencyMask || isCompressed32BitInteger) 5784 { 5785 dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_4_0_0); 5786 } 5787 5788 if (dngBackwardVersion > dngVersion) 5789 { 5790 ThrowProgramError (); 5791 } 5792 5793 // Find best thumbnail from preview list, if any. 5794 5795 const dng_preview *thumbnail = NULL; 5796 5797 if (previewList) 5798 { 5799 5800 uint32 thumbArea = 0; 5801 5802 for (j = 0; j < previewList->Count (); j++) 5803 { 5804 5805 const dng_image_preview *imagePreview = dynamic_cast<const dng_image_preview *>(&previewList->Preview (j)); 5806 5807 if (imagePreview) 5808 { 5809 5810 uint32 thisArea = imagePreview->fImage->Bounds ().W () * 5811 imagePreview->fImage->Bounds ().H (); 5812 5813 if (!thumbnail || thisArea < thumbArea) 5814 { 5815 5816 thumbnail = &previewList->Preview (j); 5817 5818 thumbArea = thisArea; 5819 5820 } 5821 5822 } 5823 5824 const dng_jpeg_preview *jpegPreview = dynamic_cast<const dng_jpeg_preview *>(&previewList->Preview (j)); 5825 5826 if (jpegPreview) 5827 { 5828 5829 uint32 thisArea = jpegPreview->fPreviewSize.h * 5830 jpegPreview->fPreviewSize.v; 5831 5832 if (!thumbnail || thisArea < thumbArea) 5833 { 5834 5835 thumbnail = &previewList->Preview (j); 5836 5837 thumbArea = thisArea; 5838 5839 } 5840 5841 } 5842 5843 } 5844 5845 } 5846 5847 // Create the main IFD 5848 5849 dng_tiff_directory mainIFD; 5850 5851 // Create the IFD for the raw data. If there is no thumnail, this is 5852 // just a reference the main IFD. Otherwise allocate a new one. 5853 5854 AutoPtr<dng_tiff_directory> rawIFD_IfNotMain; 5855 5856 if (thumbnail) 5857 { 5858 rawIFD_IfNotMain.Reset (new dng_tiff_directory); 5859 } 5860 5861 dng_tiff_directory &rawIFD (thumbnail ? *rawIFD_IfNotMain : mainIFD); 5862 5863 // Include DNG version tags. 5864 5865 uint8 dngVersionData [4]; 5866 5867 dngVersionData [0] = (uint8) (dngVersion >> 24); 5868 dngVersionData [1] = (uint8) (dngVersion >> 16); 5869 dngVersionData [2] = (uint8) (dngVersion >> 8); 5870 dngVersionData [3] = (uint8) (dngVersion ); 5871 5872 tag_uint8_ptr tagDNGVersion (tcDNGVersion, dngVersionData, 4); 5873 5874 mainIFD.Add (&tagDNGVersion); 5875 5876 uint8 dngBackwardVersionData [4]; 5877 5878 dngBackwardVersionData [0] = (uint8) (dngBackwardVersion >> 24); 5879 dngBackwardVersionData [1] = (uint8) (dngBackwardVersion >> 16); 5880 dngBackwardVersionData [2] = (uint8) (dngBackwardVersion >> 8); 5881 dngBackwardVersionData [3] = (uint8) (dngBackwardVersion ); 5882 5883 tag_uint8_ptr tagDNGBackwardVersion (tcDNGBackwardVersion, dngBackwardVersionData, 4); 5884 5885 mainIFD.Add (&tagDNGBackwardVersion); 5886 5887 // The main IFD contains the thumbnail, if there is a thumbnail. 5888 5889 AutoPtr<dng_basic_tag_set> thmBasic; 5890 5891 if (thumbnail) 5892 { 5893 thmBasic.Reset (thumbnail->AddTagSet (mainIFD)); 5894 } 5895 5896 // Get the raw image we are writing. 5897 5898 const dng_image &rawImage (negative.RawImage ()); 5899 5900 // For floating point, we only support ZIP compression. 5901 5902 if (isFloatingPoint && !uncompressed) 5903 { 5904 5905 compression = ccDeflate; 5906 5907 } 5908 5909 // For 32-bit integer images, we only support ZIP and uncompressed. 5910 5911 if (rawImage.PixelType () == ttLong) 5912 { 5913 5914 if (isCompressed32BitInteger) 5915 { 5916 compression = ccDeflate; 5917 } 5918 5919 else 5920 { 5921 compression = ccUncompressed; 5922 } 5923 5924 } 5925 5926 // Get a copy of the mosaic info. 5927 5928 dng_mosaic_info mosaicInfo; 5929 5930 if (negative.GetMosaicInfo ()) 5931 { 5932 mosaicInfo = *(negative.GetMosaicInfo ()); 5933 } 5934 5935 // Create a dng_ifd record for the raw image. 5936 5937 dng_ifd info; 5938 5939 info.fImageWidth = rawImage.Width (); 5940 info.fImageLength = rawImage.Height (); 5941 5942 info.fSamplesPerPixel = rawImage.Planes (); 5943 5944 info.fPhotometricInterpretation = mosaicInfo.IsColorFilterArray () ? piCFA 5945 : piLinearRaw; 5946 5947 info.fCompression = compression; 5948 5949 if (isFloatingPoint && compression == ccDeflate) 5950 { 5951 5952 info.fPredictor = cpFloatingPoint; 5953 5954 if (mosaicInfo.IsColorFilterArray ()) 5955 { 5956 5957 if (mosaicInfo.fCFAPatternSize.h == 2) 5958 { 5959 info.fPredictor = cpFloatingPointX2; 5960 } 5961 5962 else if (mosaicInfo.fCFAPatternSize.h == 4) 5963 { 5964 info.fPredictor = cpFloatingPointX4; 5965 } 5966 5967 } 5968 5969 } 5970 5971 if (isCompressed32BitInteger) 5972 { 5973 5974 info.fPredictor = cpHorizontalDifference; 5975 5976 if (mosaicInfo.IsColorFilterArray ()) 5977 { 5978 5979 if (mosaicInfo.fCFAPatternSize.h == 2) 5980 { 5981 info.fPredictor = cpHorizontalDifferenceX2; 5982 } 5983 5984 else if (mosaicInfo.fCFAPatternSize.h == 4) 5985 { 5986 info.fPredictor = cpHorizontalDifferenceX4; 5987 } 5988 5989 } 5990 5991 } 5992 5993 uint32 rawPixelType = rawImage.PixelType (); 5994 5995 if (rawPixelType == ttShort) 5996 { 5997 5998 // See if we are using a linearization table with <= 256 entries, in which 5999 // case the useful data will all fit within 8-bits. 6000 6001 const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo (); 6002 6003 if (rangeInfo) 6004 { 6005 6006 if (rangeInfo->fLinearizationTable.Get ()) 6007 { 6008 6009 uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1; 6010 6011 if (entries <= 256) 6012 { 6013 6014 rawPixelType = ttByte; 6015 6016 } 6017 6018 } 6019 6020 } 6021 6022 } 6023 6024 switch (rawPixelType) 6025 { 6026 6027 case ttByte: 6028 { 6029 info.fBitsPerSample [0] = 8; 6030 break; 6031 } 6032 6033 case ttShort: 6034 { 6035 info.fBitsPerSample [0] = 16; 6036 break; 6037 } 6038 6039 case ttLong: 6040 { 6041 info.fBitsPerSample [0] = 32; 6042 break; 6043 } 6044 6045 case ttFloat: 6046 { 6047 6048 if (negative.RawFloatBitDepth () == 16) 6049 { 6050 info.fBitsPerSample [0] = 16; 6051 } 6052 6053 else if (negative.RawFloatBitDepth () == 24) 6054 { 6055 info.fBitsPerSample [0] = 24; 6056 } 6057 6058 else 6059 { 6060 info.fBitsPerSample [0] = 32; 6061 } 6062 6063 for (j = 0; j < info.fSamplesPerPixel; j++) 6064 { 6065 info.fSampleFormat [j] = sfFloatingPoint; 6066 } 6067 6068 break; 6069 6070 } 6071 6072 default: 6073 { 6074 ThrowProgramError (); 6075 } 6076 6077 } 6078 6079 // For lossless JPEG compression, we often lie about the 6080 // actual channel count to get the predictors to work across 6081 // same color mosaic pixels. 6082 6083 uint32 fakeChannels = 1; 6084 6085 if (info.fCompression == ccJPEG) 6086 { 6087 6088 if (mosaicInfo.IsColorFilterArray ()) 6089 { 6090 6091 if (mosaicInfo.fCFAPatternSize.h == 4) 6092 { 6093 fakeChannels = 4; 6094 } 6095 6096 else if (mosaicInfo.fCFAPatternSize.h == 2) 6097 { 6098 fakeChannels = 2; 6099 } 6100 6101 // However, lossless JEPG is limited to four channels, 6102 // so compromise might be required. 6103 6104 while (fakeChannels * info.fSamplesPerPixel > 4 && 6105 fakeChannels > 1) 6106 { 6107 6108 fakeChannels >>= 1; 6109 6110 } 6111 6112 } 6113 6114 } 6115 6116 // Figure out tile sizes. 6117 6118 if (rawJPEGImage) 6119 { 6120 6121 DNG_ASSERT (rawPixelType == ttByte, 6122 "Unexpected jpeg pixel type"); 6123 6124 DNG_ASSERT (info.fImageWidth == (uint32) rawJPEGImage->fImageSize.h && 6125 info.fImageLength == (uint32) rawJPEGImage->fImageSize.v, 6126 "Unexpected jpeg image size"); 6127 6128 info.fTileWidth = rawJPEGImage->fTileSize.h; 6129 info.fTileLength = rawJPEGImage->fTileSize.v; 6130 6131 info.fUsesStrips = rawJPEGImage->fUsesStrips; 6132 6133 info.fUsesTiles = !info.fUsesStrips; 6134 6135 } 6136 6137 else if (info.fCompression == ccJPEG) 6138 { 6139 6140 info.FindTileSize (128 * 1024); 6141 6142 } 6143 6144 else if (info.fCompression == ccDeflate) 6145 { 6146 6147 info.FindTileSize (512 * 1024); 6148 6149 } 6150 6151 else if (info.fCompression == ccLossyJPEG) 6152 { 6153 6154 ThrowProgramError ("No JPEG compressed image"); 6155 6156 } 6157 6158 // Don't use tiles for uncompressed images. 6159 6160 else 6161 { 6162 6163 info.SetSingleStrip (); 6164 6165 } 6166 6167 #ifdef qTestRowInterleave 6168 6169 info.fRowInterleaveFactor = qTestRowInterleave; 6170 6171 #endif 6172 6173 #if defined(qTestSubTileBlockRows) && defined(qTestSubTileBlockCols) 6174 6175 info.fSubTileBlockRows = qTestSubTileBlockRows; 6176 info.fSubTileBlockCols = qTestSubTileBlockCols; 6177 6178 if (fakeChannels == 2) 6179 fakeChannels = 4; 6180 6181 #endif 6182 6183 // Basic information. 6184 6185 dng_basic_tag_set rawBasic (rawIFD, info); 6186 6187 // JPEG tables, if any. 6188 6189 tag_data_ptr tagJPEGTables (tcJPEGTables, 6190 ttUndefined, 6191 0, 6192 NULL); 6193 6194 if (rawJPEGImage && rawJPEGImage->fJPEGTables.Get ()) 6195 { 6196 6197 tagJPEGTables.SetData (rawJPEGImage->fJPEGTables->Buffer ()); 6198 6199 tagJPEGTables.SetCount (rawJPEGImage->fJPEGTables->LogicalSize ()); 6200 6201 rawIFD.Add (&tagJPEGTables); 6202 6203 } 6204 6205 // DefaultScale tag. 6206 6207 dng_urational defaultScaleData [2]; 6208 6209 defaultScaleData [0] = negative.DefaultScaleH (); 6210 defaultScaleData [1] = negative.DefaultScaleV (); 6211 6212 tag_urational_ptr tagDefaultScale (tcDefaultScale, 6213 defaultScaleData, 6214 2); 6215 6216 rawIFD.Add (&tagDefaultScale); 6217 6218 // Best quality scale tag. 6219 6220 tag_urational tagBestQualityScale (tcBestQualityScale, 6221 negative.BestQualityScale ()); 6222 6223 rawIFD.Add (&tagBestQualityScale); 6224 6225 // DefaultCropOrigin tag. 6226 6227 dng_urational defaultCropOriginData [2]; 6228 6229 defaultCropOriginData [0] = negative.DefaultCropOriginH (); 6230 defaultCropOriginData [1] = negative.DefaultCropOriginV (); 6231 6232 tag_urational_ptr tagDefaultCropOrigin (tcDefaultCropOrigin, 6233 defaultCropOriginData, 6234 2); 6235 6236 rawIFD.Add (&tagDefaultCropOrigin); 6237 6238 // DefaultCropSize tag. 6239 6240 dng_urational defaultCropSizeData [2]; 6241 6242 defaultCropSizeData [0] = negative.DefaultCropSizeH (); 6243 defaultCropSizeData [1] = negative.DefaultCropSizeV (); 6244 6245 tag_urational_ptr tagDefaultCropSize (tcDefaultCropSize, 6246 defaultCropSizeData, 6247 2); 6248 6249 rawIFD.Add (&tagDefaultCropSize); 6250 6251 // DefaultUserCrop tag. 6252 6253 dng_urational defaultUserCropData [4]; 6254 6255 defaultUserCropData [0] = negative.DefaultUserCropT (); 6256 defaultUserCropData [1] = negative.DefaultUserCropL (); 6257 defaultUserCropData [2] = negative.DefaultUserCropB (); 6258 defaultUserCropData [3] = negative.DefaultUserCropR (); 6259 6260 tag_urational_ptr tagDefaultUserCrop (tcDefaultUserCrop, 6261 defaultUserCropData, 6262 4); 6263 6264 rawIFD.Add (&tagDefaultUserCrop); 6265 6266 // Range mapping tag set. 6267 6268 range_tag_set rangeSet (rawIFD, negative); 6269 6270 // Mosaic pattern information. 6271 6272 mosaic_tag_set mosaicSet (rawIFD, mosaicInfo); 6273 6274 // Chroma blur radius. 6275 6276 tag_urational tagChromaBlurRadius (tcChromaBlurRadius, 6277 negative.ChromaBlurRadius ()); 6278 6279 if (negative.ChromaBlurRadius ().IsValid ()) 6280 { 6281 6282 rawIFD.Add (&tagChromaBlurRadius); 6283 6284 } 6285 6286 // Anti-alias filter strength. 6287 6288 tag_urational tagAntiAliasStrength (tcAntiAliasStrength, 6289 negative.AntiAliasStrength ()); 6290 6291 if (negative.AntiAliasStrength ().IsValid ()) 6292 { 6293 6294 rawIFD.Add (&tagAntiAliasStrength); 6295 6296 } 6297 6298 // Profile and other color related tags. 6299 6300 AutoPtr<profile_tag_set> profileSet; 6301 6302 AutoPtr<color_tag_set> colorSet; 6303 6304 dng_std_vector<uint32> extraProfileIndex; 6305 6306 if (!negative.IsMonochrome ()) 6307 { 6308 6309 const dng_camera_profile &mainProfile (*negative.ComputeCameraProfileToEmbed (constMetadata)); 6310 6311 profileSet.Reset (new profile_tag_set (mainIFD, 6312 mainProfile)); 6313 6314 colorSet.Reset (new color_tag_set (mainIFD, 6315 negative)); 6316 6317 // Build list of profile indices to include in extra profiles tag. 6318 6319 uint32 profileCount = negative.ProfileCount (); 6320 6321 for (uint32 index = 0; index < profileCount; index++) 6322 { 6323 6324 const dng_camera_profile &profile (negative.ProfileByIndex (index)); 6325 6326 if (&profile != &mainProfile) 6327 { 6328 6329 if (profile.WasReadFromDNG ()) 6330 { 6331 6332 extraProfileIndex.push_back (index); 6333 6334 } 6335 6336 } 6337 6338 } 6339 6340 } 6341 6342 // Extra camera profiles tag. 6343 6344 uint32 extraProfileCount = (uint32) extraProfileIndex.size (); 6345 6346 dng_memory_data extraProfileOffsets (extraProfileCount, sizeof (uint32)); 6347 6348 tag_uint32_ptr extraProfileTag (tcExtraCameraProfiles, 6349 extraProfileOffsets.Buffer_uint32 (), 6350 extraProfileCount); 6351 6352 if (extraProfileCount) 6353 { 6354 6355 mainIFD.Add (&extraProfileTag); 6356 6357 } 6358 6359 // Other tags. 6360 6361 tag_uint16 tagOrientation (tcOrientation, 6362 (uint16) negative.ComputeOrientation (constMetadata).GetTIFF ()); 6363 6364 mainIFD.Add (&tagOrientation); 6365 6366 tag_srational tagBaselineExposure (tcBaselineExposure, 6367 negative.BaselineExposureR ()); 6368 6369 mainIFD.Add (&tagBaselineExposure); 6370 6371 tag_urational tagBaselineNoise (tcBaselineNoise, 6372 negative.BaselineNoiseR ()); 6373 6374 mainIFD.Add (&tagBaselineNoise); 6375 6376 tag_urational tagNoiseReductionApplied (tcNoiseReductionApplied, 6377 negative.NoiseReductionApplied ()); 6378 6379 if (negative.NoiseReductionApplied ().IsValid ()) 6380 { 6381 6382 mainIFD.Add (&tagNoiseReductionApplied); 6383 6384 } 6385 6386 tag_dng_noise_profile tagNoiseProfile (negative.NoiseProfile ()); 6387 6388 if (negative.NoiseProfile ().IsValidForNegative (negative)) 6389 { 6390 6391 mainIFD.Add (&tagNoiseProfile); 6392 6393 } 6394 6395 tag_urational tagBaselineSharpness (tcBaselineSharpness, 6396 negative.BaselineSharpnessR ()); 6397 6398 mainIFD.Add (&tagBaselineSharpness); 6399 6400 tag_string tagUniqueName (tcUniqueCameraModel, 6401 negative.ModelName (), 6402 true); 6403 6404 mainIFD.Add (&tagUniqueName); 6405 6406 tag_string tagLocalName (tcLocalizedCameraModel, 6407 negative.LocalName (), 6408 false); 6409 6410 if (negative.LocalName ().NotEmpty ()) 6411 { 6412 6413 mainIFD.Add (&tagLocalName); 6414 6415 } 6416 6417 tag_urational tagShadowScale (tcShadowScale, 6418 negative.ShadowScaleR ()); 6419 6420 mainIFD.Add (&tagShadowScale); 6421 6422 tag_uint16 tagColorimetricReference (tcColorimetricReference, 6423 (uint16) negative.ColorimetricReference ()); 6424 6425 if (negative.ColorimetricReference () != crSceneReferred) 6426 { 6427 6428 mainIFD.Add (&tagColorimetricReference); 6429 6430 } 6431 6432 bool useNewDigest = (maxBackwardVersion >= dngVersion_1_4_0_0); 6433 6434 if (compression == ccLossyJPEG) 6435 { 6436 6437 negative.FindRawJPEGImageDigest (host); 6438 6439 } 6440 6441 else 6442 { 6443 6444 if (useNewDigest) 6445 { 6446 negative.FindNewRawImageDigest (host); 6447 } 6448 else 6449 { 6450 negative.FindRawImageDigest (host); 6451 } 6452 6453 } 6454 6455 tag_uint8_ptr tagRawImageDigest (useNewDigest ? tcNewRawImageDigest : tcRawImageDigest, 6456 compression == ccLossyJPEG ? 6457 negative.RawJPEGImageDigest ().data : 6458 (useNewDigest ? negative.NewRawImageDigest ().data 6459 : negative.RawImageDigest ().data), 6460 16); 6461 6462 mainIFD.Add (&tagRawImageDigest); 6463 6464 negative.FindRawDataUniqueID (host); 6465 6466 tag_uint8_ptr tagRawDataUniqueID (tcRawDataUniqueID, 6467 negative.RawDataUniqueID ().data, 6468 16); 6469 6470 if (negative.RawDataUniqueID ().IsValid ()) 6471 { 6472 6473 mainIFD.Add (&tagRawDataUniqueID); 6474 6475 } 6476 6477 tag_string tagOriginalRawFileName (tcOriginalRawFileName, 6478 negative.OriginalRawFileName (), 6479 false); 6480 6481 if (negative.HasOriginalRawFileName ()) 6482 { 6483 6484 mainIFD.Add (&tagOriginalRawFileName); 6485 6486 } 6487 6488 negative.FindOriginalRawFileDigest (); 6489 6490 tag_data_ptr tagOriginalRawFileData (tcOriginalRawFileData, 6491 ttUndefined, 6492 negative.OriginalRawFileDataLength (), 6493 negative.OriginalRawFileData ()); 6494 6495 tag_uint8_ptr tagOriginalRawFileDigest (tcOriginalRawFileDigest, 6496 negative.OriginalRawFileDigest ().data, 6497 16); 6498 6499 if (negative.OriginalRawFileData ()) 6500 { 6501 6502 mainIFD.Add (&tagOriginalRawFileData); 6503 6504 mainIFD.Add (&tagOriginalRawFileDigest); 6505 6506 } 6507 6508 // XMP metadata. 6509 6510 #if qDNGUseXMP 6511 6512 tag_xmp tagXMP (metadata->GetXMP ()); 6513 6514 if (tagXMP.Count ()) 6515 { 6516 6517 mainIFD.Add (&tagXMP); 6518 6519 } 6520 6521 #endif 6522 6523 // Exif tags. 6524 6525 exif_tag_set exifSet (mainIFD, 6526 *metadata->GetExif (), 6527 metadata->IsMakerNoteSafe (), 6528 metadata->MakerNoteData (), 6529 metadata->MakerNoteLength (), 6530 true); 6531 6532 // Private data. 6533 6534 tag_uint8_ptr tagPrivateData (tcDNGPrivateData, 6535 negative.PrivateData (), 6536 negative.PrivateLength ()); 6537 6538 if (negative.PrivateLength ()) 6539 { 6540 6541 mainIFD.Add (&tagPrivateData); 6542 6543 } 6544 6545 // Proxy size tags. 6546 6547 uint32 originalDefaultFinalSizeData [2]; 6548 6549 originalDefaultFinalSizeData [0] = negative.OriginalDefaultFinalSize ().h; 6550 originalDefaultFinalSizeData [1] = negative.OriginalDefaultFinalSize ().v; 6551 6552 tag_uint32_ptr tagOriginalDefaultFinalSize (tcOriginalDefaultFinalSize, 6553 originalDefaultFinalSizeData, 6554 2); 6555 6556 if (saveOriginalDefaultFinalSize) 6557 { 6558 6559 mainIFD.Add (&tagOriginalDefaultFinalSize); 6560 6561 } 6562 6563 uint32 originalBestQualityFinalSizeData [2]; 6564 6565 originalBestQualityFinalSizeData [0] = negative.OriginalBestQualityFinalSize ().h; 6566 originalBestQualityFinalSizeData [1] = negative.OriginalBestQualityFinalSize ().v; 6567 6568 tag_uint32_ptr tagOriginalBestQualityFinalSize (tcOriginalBestQualityFinalSize, 6569 originalBestQualityFinalSizeData, 6570 2); 6571 6572 if (saveOriginalBestQualityFinalSize) 6573 { 6574 6575 mainIFD.Add (&tagOriginalBestQualityFinalSize); 6576 6577 } 6578 6579 dng_urational originalDefaultCropSizeData [2]; 6580 6581 originalDefaultCropSizeData [0] = negative.OriginalDefaultCropSizeH (); 6582 originalDefaultCropSizeData [1] = negative.OriginalDefaultCropSizeV (); 6583 6584 tag_urational_ptr tagOriginalDefaultCropSize (tcOriginalDefaultCropSize, 6585 originalDefaultCropSizeData, 6586 2); 6587 6588 if (saveOriginalDefaultCropSize) 6589 { 6590 6591 mainIFD.Add (&tagOriginalDefaultCropSize); 6592 6593 } 6594 6595 // Opcode list 1. 6596 6597 AutoPtr<dng_memory_block> opcodeList1Data (negative.OpcodeList1 ().Spool (host)); 6598 6599 tag_data_ptr tagOpcodeList1 (tcOpcodeList1, 6600 ttUndefined, 6601 opcodeList1Data.Get () ? opcodeList1Data->LogicalSize () : 0, 6602 opcodeList1Data.Get () ? opcodeList1Data->Buffer () : NULL); 6603 6604 if (opcodeList1Data.Get ()) 6605 { 6606 6607 rawIFD.Add (&tagOpcodeList1); 6608 6609 } 6610 6611 // Opcode list 2. 6612 6613 AutoPtr<dng_memory_block> opcodeList2Data (negative.OpcodeList2 ().Spool (host)); 6614 6615 tag_data_ptr tagOpcodeList2 (tcOpcodeList2, 6616 ttUndefined, 6617 opcodeList2Data.Get () ? opcodeList2Data->LogicalSize () : 0, 6618 opcodeList2Data.Get () ? opcodeList2Data->Buffer () : NULL); 6619 6620 if (opcodeList2Data.Get ()) 6621 { 6622 6623 rawIFD.Add (&tagOpcodeList2); 6624 6625 } 6626 6627 // Opcode list 3. 6628 6629 AutoPtr<dng_memory_block> opcodeList3Data (negative.OpcodeList3 ().Spool (host)); 6630 6631 tag_data_ptr tagOpcodeList3 (tcOpcodeList3, 6632 ttUndefined, 6633 opcodeList3Data.Get () ? opcodeList3Data->LogicalSize () : 0, 6634 opcodeList3Data.Get () ? opcodeList3Data->Buffer () : NULL); 6635 6636 if (opcodeList3Data.Get ()) 6637 { 6638 6639 rawIFD.Add (&tagOpcodeList3); 6640 6641 } 6642 6643 // Transparency mask, if any. 6644 6645 AutoPtr<dng_ifd> maskInfo; 6646 6647 AutoPtr<dng_tiff_directory> maskIFD; 6648 6649 AutoPtr<dng_basic_tag_set> maskBasic; 6650 6651 if (hasTransparencyMask) 6652 { 6653 6654 // Create mask IFD. 6655 6656 maskInfo.Reset (new dng_ifd); 6657 6658 maskInfo->fNewSubFileType = sfTransparencyMask; 6659 6660 maskInfo->fImageWidth = negative.RawTransparencyMask ()->Bounds ().W (); 6661 maskInfo->fImageLength = negative.RawTransparencyMask ()->Bounds ().H (); 6662 6663 maskInfo->fSamplesPerPixel = 1; 6664 6665 maskInfo->fBitsPerSample [0] = negative.RawTransparencyMaskBitDepth (); 6666 6667 maskInfo->fPhotometricInterpretation = piTransparencyMask; 6668 6669 maskInfo->fCompression = uncompressed ? ccUncompressed : ccDeflate; 6670 maskInfo->fPredictor = uncompressed ? cpNullPredictor : cpHorizontalDifference; 6671 6672 if (negative.RawTransparencyMask ()->PixelType () == ttFloat) 6673 { 6674 6675 maskInfo->fSampleFormat [0] = sfFloatingPoint; 6676 6677 if (maskInfo->fCompression == ccDeflate) 6678 { 6679 maskInfo->fPredictor = cpFloatingPoint; 6680 } 6681 6682 } 6683 6684 if (maskInfo->fCompression == ccDeflate) 6685 { 6686 maskInfo->FindTileSize (512 * 1024); 6687 } 6688 else 6689 { 6690 maskInfo->SetSingleStrip (); 6691 } 6692 6693 // Create mask tiff directory. 6694 6695 maskIFD.Reset (new dng_tiff_directory); 6696 6697 // Add mask basic tag set. 6698 6699 maskBasic.Reset (new dng_basic_tag_set (*maskIFD, *maskInfo)); 6700 6701 } 6702 6703 // Add other subfiles. 6704 6705 uint32 subFileCount = thumbnail ? 1 : 0; 6706 6707 if (hasTransparencyMask) 6708 { 6709 subFileCount++; 6710 } 6711 6712 // Add previews. 6713 6714 uint32 previewCount = previewList ? previewList->Count () : 0; 6715 6716 AutoPtr<dng_tiff_directory> previewIFD [kMaxDNGPreviews]; 6717 6718 AutoPtr<dng_basic_tag_set> previewBasic [kMaxDNGPreviews]; 6719 6720 for (j = 0; j < previewCount; j++) 6721 { 6722 6723 if (thumbnail != &previewList->Preview (j)) 6724 { 6725 6726 previewIFD [j] . Reset (new dng_tiff_directory); 6727 6728 previewBasic [j] . Reset (previewList->Preview (j).AddTagSet (*previewIFD [j])); 6729 6730 subFileCount++; 6731 6732 } 6733 6734 } 6735 6736 // And a link to the raw and JPEG image IFDs. 6737 6738 uint32 subFileData [kMaxDNGPreviews + 2]; 6739 6740 tag_uint32_ptr tagSubFile (tcSubIFDs, 6741 subFileData, 6742 subFileCount); 6743 6744 if (subFileCount) 6745 { 6746 6747 mainIFD.Add (&tagSubFile); 6748 6749 } 6750 6751 // Skip past the header and IFDs for now. 6752 6753 uint32 currentOffset = 8; 6754 6755 currentOffset += mainIFD.Size (); 6756 6757 uint32 subFileIndex = 0; 6758 6759 if (thumbnail) 6760 { 6761 6762 subFileData [subFileIndex++] = currentOffset; 6763 6764 currentOffset += rawIFD.Size (); 6765 6766 } 6767 6768 if (hasTransparencyMask) 6769 { 6770 6771 subFileData [subFileIndex++] = currentOffset; 6772 6773 currentOffset += maskIFD->Size (); 6774 6775 } 6776 6777 for (j = 0; j < previewCount; j++) 6778 { 6779 6780 if (thumbnail != &previewList->Preview (j)) 6781 { 6782 6783 subFileData [subFileIndex++] = currentOffset; 6784 6785 currentOffset += previewIFD [j]->Size (); 6786 6787 } 6788 6789 } 6790 6791 exifSet.Locate (currentOffset); 6792 6793 currentOffset += exifSet.Size (); 6794 6795 stream.SetWritePosition (currentOffset); 6796 6797 // Write the extra profiles. 6798 6799 if (extraProfileCount) 6800 { 6801 6802 for (j = 0; j < extraProfileCount; j++) 6803 { 6804 6805 extraProfileOffsets.Buffer_uint32 () [j] = (uint32) stream.Position (); 6806 6807 uint32 index = extraProfileIndex [j]; 6808 6809 const dng_camera_profile &profile (negative.ProfileByIndex (index)); 6810 6811 tiff_dng_extended_color_profile extraWriter (profile); 6812 6813 extraWriter.Put (stream, false); 6814 6815 } 6816 6817 } 6818 6819 // Write the thumbnail data. 6820 6821 if (thumbnail) 6822 { 6823 6824 thumbnail->WriteData (host, 6825 *this, 6826 *thmBasic, 6827 stream); 6828 6829 } 6830 6831 // Write the preview data. 6832 6833 for (j = 0; j < previewCount; j++) 6834 { 6835 6836 if (thumbnail != &previewList->Preview (j)) 6837 { 6838 6839 previewList->Preview (j).WriteData (host, 6840 *this, 6841 *previewBasic [j], 6842 stream); 6843 6844 } 6845 6846 } 6847 6848 // Write the raw data. 6849 6850 if (rawJPEGImage) 6851 { 6852 6853 uint32 tileCount = info.TilesAcross () * 6854 info.TilesDown (); 6855 6856 for (uint32 tileIndex = 0; tileIndex < tileCount; tileIndex++) 6857 { 6858 6859 // Remember this offset. 6860 6861 uint32 tileOffset = (uint32) stream.Position (); 6862 6863 rawBasic.SetTileOffset (tileIndex, tileOffset); 6864 6865 // Write JPEG data. 6866 6867 stream.Put (rawJPEGImage->fJPEGData [tileIndex]->Buffer (), 6868 rawJPEGImage->fJPEGData [tileIndex]->LogicalSize ()); 6869 6870 // Update tile count. 6871 6872 uint32 tileByteCount = (uint32) stream.Position () - tileOffset; 6873 6874 rawBasic.SetTileByteCount (tileIndex, tileByteCount); 6875 6876 // Keep the tiles on even byte offsets. 6877 6878 if (tileByteCount & 1) 6879 { 6880 stream.Put_uint8 (0); 6881 } 6882 6883 } 6884 6885 } 6886 6887 else 6888 { 6889 6890 #if qDNGValidate 6891 dng_timer timer ("Write raw image time"); 6892 #endif 6893 6894 WriteImage (host, 6895 info, 6896 rawBasic, 6897 stream, 6898 rawImage, 6899 fakeChannels); 6900 6901 } 6902 6903 // Write transparency mask image. 6904 6905 if (hasTransparencyMask) 6906 { 6907 6908 #if qDNGValidate 6909 dng_timer timer ("Write transparency mask time"); 6910 #endif 6911 6912 WriteImage (host, 6913 *maskInfo, 6914 *maskBasic, 6915 stream, 6916 *negative.RawTransparencyMask ()); 6917 6918 } 6919 6920 // Trim the file to this length. 6921 6922 stream.SetLength (stream.Position ()); 6923 6924 // DNG has a 4G size limit. 6925 6926 if (stream.Length () > 0x0FFFFFFFFL) 6927 { 6928 ThrowImageTooBigDNG (); 6929 } 6930 6931 // Write TIFF Header. 6932 6933 stream.SetWritePosition (0); 6934 6935 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII); 6936 6937 stream.Put_uint16 (42); 6938 6939 stream.Put_uint32 (8); 6940 6941 // Write the IFDs. 6942 6943 mainIFD.Put (stream); 6944 6945 if (thumbnail) 6946 { 6947 6948 rawIFD.Put (stream); 6949 6950 } 6951 6952 if (hasTransparencyMask) 6953 { 6954 6955 maskIFD->Put (stream); 6956 6957 } 6958 6959 for (j = 0; j < previewCount; j++) 6960 { 6961 6962 if (thumbnail != &previewList->Preview (j)) 6963 { 6964 6965 previewIFD [j]->Put (stream); 6966 6967 } 6968 6969 } 6970 6971 exifSet.Put (stream); 6972 6973 stream.Flush (); 6974 6975 } 6976 6977 /*****************************************************************************/ 6978