1 /*****************************************************************************/ 2 // Copyright 2006-2009 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_mosaic_info.cpp#1 $ */ 10 /* $DateTime: 2012/05/30 13:28:51 $ */ 11 /* $Change: 832332 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_mosaic_info.h" 17 18 #include "dng_area_task.h" 19 #include "dng_assertions.h" 20 #include "dng_bottlenecks.h" 21 #include "dng_exceptions.h" 22 #include "dng_filter_task.h" 23 #include "dng_host.h" 24 #include "dng_ifd.h" 25 #include "dng_image.h" 26 #include "dng_info.h" 27 #include "dng_negative.h" 28 #include "dng_pixel_buffer.h" 29 #include "dng_tag_types.h" 30 #include "dng_tag_values.h" 31 #include "dng_tile_iterator.h" 32 #include "dng_utils.h" 33 34 /*****************************************************************************/ 35 36 // A interpolation kernel for a single pixel of a single plane. 37 38 class dng_bilinear_kernel 39 { 40 41 public: 42 43 enum 44 { 45 kMaxCount = 8 46 }; 47 48 uint32 fCount; 49 50 dng_point fDelta [kMaxCount]; 51 52 real32 fWeight32 [kMaxCount]; 53 uint16 fWeight16 [kMaxCount]; 54 55 int32 fOffset [kMaxCount]; 56 57 public: 58 59 dng_bilinear_kernel () 60 : fCount (0) 61 { 62 } 63 64 void Add (const dng_point &delta, 65 real32 weight); 66 67 void Finalize (const dng_point &scale, 68 uint32 patRow, 69 uint32 patCol, 70 int32 rowStep, 71 int32 colStep); 72 73 }; 74 75 /*****************************************************************************/ 76 77 void dng_bilinear_kernel::Add (const dng_point &delta, 78 real32 weight) 79 { 80 81 // Don't add zero weight elements. 82 83 if (weight <= 0.0f) 84 { 85 return; 86 } 87 88 // If the delta already matches an existing element, just combine the 89 // weights. 90 91 for (uint32 j = 0; j < fCount; j++) 92 { 93 94 if (fDelta [j] == delta) 95 { 96 97 fWeight32 [j] += weight; 98 99 return; 100 101 } 102 103 } 104 105 // Add element to list. 106 107 DNG_ASSERT (fCount < kMaxCount, "Too many kernel entries") 108 109 fDelta [fCount] = delta; 110 fWeight32 [fCount] = weight; 111 112 fCount++; 113 114 } 115 116 /*****************************************************************************/ 117 118 void dng_bilinear_kernel::Finalize (const dng_point &scale, 119 uint32 patRow, 120 uint32 patCol, 121 int32 rowStep, 122 int32 colStep) 123 { 124 125 uint32 j; 126 127 // Adjust deltas to compensate for interpolation upscaling. 128 129 for (j = 0; j < fCount; j++) 130 { 131 132 dng_point &delta = fDelta [j]; 133 134 if (scale.v == 2) 135 { 136 137 delta.v = (delta.v + (int32) (patRow & 1)) >> 1; 138 139 } 140 141 if (scale.h == 2) 142 { 143 144 delta.h = (delta.h + (int32) (patCol & 1)) >> 1; 145 146 } 147 148 } 149 150 // Sort entries into row-column scan order. 151 152 while (true) 153 { 154 155 bool didSwap = false; 156 157 for (j = 1; j < fCount; j++) 158 { 159 160 dng_point &delta0 = fDelta [j - 1]; 161 dng_point &delta1 = fDelta [j ]; 162 163 if (delta0.v > delta1.v || 164 (delta0.v == delta1.v && 165 delta0.h > delta1.h)) 166 { 167 168 didSwap = true; 169 170 dng_point tempDelta = delta0; 171 172 delta0 = delta1; 173 delta1 = tempDelta; 174 175 real32 tempWeight = fWeight32 [j - 1]; 176 177 fWeight32 [j - 1] = fWeight32 [j]; 178 fWeight32 [j ] = tempWeight; 179 180 } 181 182 } 183 184 if (!didSwap) 185 { 186 break; 187 } 188 189 } 190 191 // Calculate offsets. 192 193 for (j = 0; j < fCount; j++) 194 { 195 196 fOffset [j] = rowStep * fDelta [j].v + 197 colStep * fDelta [j].h; 198 199 } 200 201 // Calculate 16-bit weights. 202 203 uint16 total = 0; 204 uint32 biggest = 0; 205 206 for (j = 0; j < fCount; j++) 207 { 208 209 // Round weights to 8 fractional bits. 210 211 fWeight16 [j] = (uint16) Round_uint32 (fWeight32 [j] * 256.0); 212 213 // Keep track of total of weights. 214 215 total += fWeight16 [j]; 216 217 // Keep track of which weight is biggest. 218 219 if (fWeight16 [biggest] < fWeight16 [j]) 220 { 221 222 biggest = j; 223 224 } 225 226 } 227 228 // Adjust largest entry so total of weights is exactly 256. 229 230 fWeight16 [biggest] += (256 - total); 231 232 // Recompute the floating point weights from the rounded integer weights 233 // so results match more closely. 234 235 for (j = 0; j < fCount; j++) 236 { 237 238 fWeight32 [j] = fWeight16 [j] * (1.0f / 256.0f); 239 240 } 241 242 } 243 244 /*****************************************************************************/ 245 246 class dng_bilinear_pattern 247 { 248 249 public: 250 251 enum 252 { 253 kMaxPattern = kMaxCFAPattern * 2 254 }; 255 256 dng_point fScale; 257 258 uint32 fPatRows; 259 uint32 fPatCols; 260 261 dng_bilinear_kernel fKernel [kMaxPattern] 262 [kMaxPattern]; 263 264 uint32 fCounts [kMaxPattern] 265 [kMaxPattern]; 266 267 int32 *fOffsets [kMaxPattern] 268 [kMaxPattern]; 269 270 uint16 *fWeights16 [kMaxPattern] 271 [kMaxPattern]; 272 273 real32 *fWeights32 [kMaxPattern] 274 [kMaxPattern]; 275 276 public: 277 278 dng_bilinear_pattern () 279 280 : fScale () 281 , fPatRows (0) 282 , fPatCols (0) 283 284 { 285 } 286 287 private: 288 289 #if defined(__clang__) && defined(__has_attribute) 290 #if __has_attribute(no_sanitize) 291 __attribute__((no_sanitize("unsigned-integer-overflow"))) 292 #endif 293 #endif 294 uint32 DeltaRow (uint32 row, int32 delta) 295 { 296 // Potential overflow in the conversion from delta to a uint32 as 297 // well as in the subsequent addition is intentional. 298 return (SafeUint32Add(row, fPatRows) + (uint32) delta) % fPatRows; 299 } 300 301 #if defined(__clang__) && defined(__has_attribute) 302 #if __has_attribute(no_sanitize) 303 __attribute__((no_sanitize("unsigned-integer-overflow"))) 304 #endif 305 #endif 306 uint32 DeltaCol (uint32 col, int32 delta) 307 { 308 // Potential overflow in the conversion from delta to a uint32 as 309 // well as in the subsequent addition is intentional. 310 return (SafeUint32Add(col, fPatCols) + (uint32) delta) % fPatCols; 311 } 312 313 real32 LinearWeight1 (int32 d1, int32 d2) 314 { 315 if (d1 == d2) 316 return 1.0f; 317 else 318 return d2 / (real32) (d2 - d1); 319 } 320 321 real32 LinearWeight2 (int32 d1, int32 d2) 322 { 323 if (d1 == d2) 324 return 0.0f; 325 else 326 return -d1 / (real32) (d2 - d1); 327 } 328 329 public: 330 331 void Calculate (const dng_mosaic_info &info, 332 uint32 dstPlane, 333 int32 rowStep, 334 int32 colStep); 335 336 }; 337 338 /*****************************************************************************/ 339 340 void dng_bilinear_pattern::Calculate (const dng_mosaic_info &info, 341 uint32 dstPlane, 342 int32 rowStep, 343 int32 colStep) 344 { 345 346 uint32 j; 347 uint32 k; 348 uint32 patRow; 349 uint32 patCol; 350 351 // Find destination pattern size. 352 353 fScale = info.FullScale (); 354 355 fPatRows = info.fCFAPatternSize.v * fScale.v; 356 fPatCols = info.fCFAPatternSize.h * fScale.h; 357 358 // See if we need to scale up just while computing the kernels. 359 360 dng_point tempScale (1, 1); 361 362 if (info.fCFALayout >= 6) 363 { 364 365 tempScale = dng_point (2, 2); 366 367 fPatRows *= tempScale.v; 368 fPatCols *= tempScale.h; 369 370 } 371 372 // Find a boolean map for this plane color and layout. 373 374 bool map [kMaxPattern] 375 [kMaxPattern]; 376 377 uint8 planeColor = info.fCFAPlaneColor [dstPlane]; 378 379 switch (info.fCFALayout) 380 { 381 382 case 1: // Rectangular (or square) layout 383 { 384 385 for (j = 0; j < fPatRows; j++) 386 { 387 388 for (k = 0; k < fPatCols; k++) 389 { 390 391 map [j] [k] = (info.fCFAPattern [j] [k] == planeColor); 392 393 } 394 395 } 396 397 break; 398 399 } 400 401 // Note that when the descriptions of the staggered patterns refer to even rows or 402 // columns, this mean the second, fourth, etc. (i.e. using one-based numbering). 403 // This needs to be clarified in the DNG specification. 404 405 case 2: // Staggered layout A: even (1-based) columns are offset down by 1/2 row 406 { 407 408 for (j = 0; j < fPatRows; j++) 409 { 410 411 for (k = 0; k < fPatCols; k++) 412 { 413 414 if ((j & 1) != (k & 1)) 415 { 416 417 map [j] [k] = false; 418 419 } 420 421 else 422 { 423 424 map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor); 425 426 } 427 428 } 429 430 } 431 432 break; 433 434 } 435 436 case 3: // Staggered layout B: even (1-based) columns are offset up by 1/2 row 437 { 438 439 for (j = 0; j < fPatRows; j++) 440 { 441 442 for (k = 0; k < fPatCols; k++) 443 { 444 445 if ((j & 1) == (k & 1)) 446 { 447 448 map [j] [k] = false; 449 450 } 451 452 else 453 { 454 455 map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor); 456 457 } 458 459 } 460 461 } 462 463 break; 464 465 } 466 467 case 4: // Staggered layout C: even (1-based) rows are offset right by 1/2 column 468 { 469 470 for (j = 0; j < fPatRows; j++) 471 { 472 473 for (k = 0; k < fPatCols; k++) 474 { 475 476 if ((j & 1) != (k & 1)) 477 { 478 479 map [j] [k] = false; 480 481 } 482 483 else 484 { 485 486 map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor); 487 488 } 489 490 } 491 492 } 493 494 break; 495 496 } 497 498 case 5: // Staggered layout D: even (1-based) rows are offset left by 1/2 column 499 { 500 501 for (j = 0; j < fPatRows; j++) 502 { 503 504 for (k = 0; k < fPatCols; k++) 505 { 506 507 if ((j & 1) == (k & 1)) 508 { 509 510 map [j] [k] = false; 511 512 } 513 514 else 515 { 516 517 map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor); 518 519 } 520 521 } 522 523 } 524 525 break; 526 527 } 528 529 case 6: // Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column 530 case 7: // Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column 531 case 8: // Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column 532 case 9: // Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column 533 { 534 535 uint32 eRow = (info.fCFALayout == 6 || 536 info.fCFALayout == 7) ? 1 : 3; 537 538 uint32 eCol = (info.fCFALayout == 6 || 539 info.fCFALayout == 8) ? 1 : 3; 540 541 for (j = 0; j < fPatRows; j++) 542 { 543 544 for (k = 0; k < fPatCols; k++) 545 { 546 547 uint32 jj = j & 3; 548 uint32 kk = k & 3; 549 550 if ((jj != 0 && jj != eRow) || 551 (kk != 0 && kk != eCol)) 552 { 553 554 map [j] [k] = false; 555 556 } 557 558 else 559 { 560 561 map [j] [k] = (info.fCFAPattern [((j >> 1) & ~1) + Min_uint32 (jj, 1)] 562 [((k >> 1) & ~1) + Min_uint32 (kk, 1)] == planeColor); 563 564 } 565 566 } 567 568 } 569 570 break; 571 572 } 573 574 default: 575 ThrowProgramError (); 576 577 } 578 579 // Find projections of maps. 580 581 bool mapH [kMaxPattern]; 582 bool mapV [kMaxPattern]; 583 584 for (j = 0; j < kMaxPattern; j++) 585 { 586 587 mapH [j] = false; 588 mapV [j] = false; 589 590 } 591 592 for (j = 0; j < fPatRows; j++) 593 { 594 595 for (k = 0; k < fPatCols; k++) 596 { 597 598 if (map [j] [k]) 599 { 600 601 mapV [j] = true; 602 mapH [k] = true; 603 604 } 605 606 } 607 608 } 609 610 // Find kernel for each patten entry. 611 612 for (patRow = 0; patRow < fPatRows; patRow += tempScale.v) 613 { 614 615 for (patCol = 0; patCol < fPatCols; patCol += tempScale.h) 616 { 617 618 dng_bilinear_kernel &kernel = fKernel [patRow] [patCol]; 619 620 // Special case no interpolation case. 621 622 if (map [patRow] [patCol]) 623 { 624 625 kernel.Add (dng_point (0, 0), 1.0f); 626 627 continue; 628 629 } 630 631 // Special case common patterns in 3 by 3 neighborhood. 632 633 uint32 n = DeltaRow (patRow, -1); 634 uint32 s = DeltaRow (patRow, 1); 635 uint32 w = DeltaCol (patCol, -1); 636 uint32 e = DeltaCol (patCol, 1); 637 638 bool mapNW = map [n] [w]; 639 bool mapN = map [n] [patCol]; 640 bool mapNE = map [n] [e]; 641 642 bool mapW = map [patRow] [w]; 643 bool mapE = map [patRow] [e]; 644 645 bool mapSW = map [s] [w]; 646 bool mapS = map [s] [patCol]; 647 bool mapSE = map [s] [e]; 648 649 // All sides. 650 651 if (mapN && mapS && mapW && mapW) 652 { 653 654 kernel.Add (dng_point (-1, 0), 0.25f); 655 kernel.Add (dng_point ( 0, -1), 0.25f); 656 kernel.Add (dng_point ( 0, 1), 0.25f); 657 kernel.Add (dng_point ( 1, 0), 0.25f); 658 659 continue; 660 661 } 662 663 // N & S. 664 665 if (mapN && mapS) 666 { 667 668 kernel.Add (dng_point (-1, 0), 0.5f); 669 kernel.Add (dng_point ( 1, 0), 0.5f); 670 671 continue; 672 673 } 674 675 // E & W. 676 677 if (mapW && mapE) 678 { 679 680 kernel.Add (dng_point ( 0, -1), 0.5f); 681 kernel.Add (dng_point ( 0, 1), 0.5f); 682 683 continue; 684 685 } 686 687 // N & SW & SE. 688 689 if (mapN && mapSW && mapSE) 690 { 691 692 kernel.Add (dng_point (-1, 0), 0.50f); 693 kernel.Add (dng_point ( 1, -1), 0.25f); 694 kernel.Add (dng_point ( 1, 1), 0.25f); 695 696 continue; 697 698 } 699 700 // S & NW & NE. 701 702 if (mapS && mapNW && mapNE) 703 { 704 705 kernel.Add (dng_point (-1, -1), 0.25f); 706 kernel.Add (dng_point (-1, 1), 0.25f); 707 kernel.Add (dng_point ( 1, 0), 0.50f); 708 709 continue; 710 711 } 712 713 // W & NE & SE. 714 715 if (mapW && mapNE && mapSE) 716 { 717 718 kernel.Add (dng_point (-1, 1), 0.25f); 719 kernel.Add (dng_point ( 0, -1), 0.50f); 720 kernel.Add (dng_point ( 1, 1), 0.25f); 721 722 continue; 723 724 } 725 726 // E & NW & SW. 727 728 if (mapE && mapNW && mapSW) 729 { 730 731 kernel.Add (dng_point (-1, -1), 0.25f); 732 kernel.Add (dng_point ( 0, 1), 0.50f); 733 kernel.Add (dng_point ( 1, -1), 0.25f); 734 735 continue; 736 737 } 738 739 // Four corners. 740 741 if (mapNW && mapNE && mapSE && mapSW) 742 { 743 744 kernel.Add (dng_point (-1, -1), 0.25f); 745 kernel.Add (dng_point (-1, 1), 0.25f); 746 kernel.Add (dng_point ( 1, -1), 0.25f); 747 kernel.Add (dng_point ( 1, 1), 0.25f); 748 749 continue; 750 751 } 752 753 // NW & SE 754 755 if (mapNW && mapSE) 756 { 757 758 kernel.Add (dng_point (-1, -1), 0.50f); 759 kernel.Add (dng_point ( 1, 1), 0.50f); 760 761 continue; 762 763 } 764 765 // NE & SW 766 767 if (mapNE && mapSW) 768 { 769 770 kernel.Add (dng_point (-1, 1), 0.50f); 771 kernel.Add (dng_point ( 1, -1), 0.50f); 772 773 continue; 774 775 } 776 777 // Else use double-bilinear kernel. 778 779 int32 dv1 = 0; 780 int32 dv2 = 0; 781 782 while (!mapV [DeltaRow (patRow, dv1)]) 783 { 784 dv1--; 785 } 786 787 while (!mapV [DeltaRow (patRow, dv2)]) 788 { 789 dv2++; 790 } 791 792 real32 w1 = LinearWeight1 (dv1, dv2) * 0.5f; 793 real32 w2 = LinearWeight2 (dv1, dv2) * 0.5f; 794 795 int32 v1 = DeltaRow (patRow, dv1); 796 int32 v2 = DeltaRow (patRow, dv2); 797 798 int32 dh1 = 0; 799 int32 dh2 = 0; 800 801 while (!map [v1] [DeltaCol (patCol, dh1)]) 802 { 803 dh1--; 804 } 805 806 while (!map [v1] [DeltaCol (patCol, dh2)]) 807 { 808 dh2++; 809 } 810 811 kernel.Add (dng_point (dv1, dh1), 812 LinearWeight1 (dh1, dh2) * w1); 813 814 kernel.Add (dng_point (dv1, dh2), 815 LinearWeight2 (dh1, dh2) * w1); 816 817 dh1 = 0; 818 dh2 = 0; 819 820 while (!map [v2] [DeltaCol (patCol, dh1)]) 821 { 822 dh1--; 823 } 824 825 while (!map [v2] [DeltaCol (patCol, dh2)]) 826 { 827 dh2++; 828 } 829 830 kernel.Add (dng_point (dv2, dh1), 831 LinearWeight1 (dh1, dh2) * w2); 832 833 kernel.Add (dng_point (dv2, dh2), 834 LinearWeight2 (dh1, dh2) * w2); 835 836 dh1 = 0; 837 dh2 = 0; 838 839 while (!mapH [DeltaCol (patCol, dh1)]) 840 { 841 dh1--; 842 } 843 844 while (!mapH [DeltaCol (patCol, dh2)]) 845 { 846 dh2++; 847 } 848 849 w1 = LinearWeight1 (dh1, dh2) * 0.5f; 850 w2 = LinearWeight2 (dh1, dh2) * 0.5f; 851 852 int32 h1 = DeltaCol (patCol, dh1); 853 int32 h2 = DeltaCol (patCol, dh2); 854 855 dv1 = 0; 856 dv2 = 0; 857 858 while (!map [DeltaRow (patRow, dv1)] [h1]) 859 { 860 dv1--; 861 } 862 863 while (!map [DeltaRow (patRow, dv2)] [h1]) 864 { 865 dv2++; 866 } 867 868 kernel.Add (dng_point (dv1, dh1), 869 LinearWeight1 (dv1, dv2) * w1); 870 871 kernel.Add (dng_point (dv2, dh1), 872 LinearWeight2 (dv1, dv2) * w1); 873 874 dv1 = 0; 875 dv2 = 0; 876 877 while (!map [DeltaRow (patRow, dv1)] [h2]) 878 { 879 dv1--; 880 } 881 882 while (!map [DeltaRow (patRow, dv2)] [h2]) 883 { 884 dv2++; 885 } 886 887 kernel.Add (dng_point (dv1, dh2), 888 LinearWeight1 (dv1, dv2) * w2); 889 890 kernel.Add (dng_point (dv2, dh2), 891 LinearWeight2 (dv1, dv2) * w2); 892 893 } 894 895 } 896 897 // Deal with temp scale case. 898 899 if (tempScale == dng_point (2, 2)) 900 { 901 902 fPatRows /= tempScale.v; 903 fPatCols /= tempScale.h; 904 905 for (patRow = 0; patRow < fPatRows; patRow++) 906 { 907 908 for (patCol = 0; patCol < fPatCols; patCol++) 909 { 910 911 int32 patRow2 = patRow << 1; 912 int32 patCol2 = patCol << 1; 913 914 dng_bilinear_kernel &kernel = fKernel [patRow2] [patCol2]; 915 916 for (j = 0; j < kernel.fCount; j++) 917 { 918 919 int32 x = patRow2 + kernel.fDelta [j].v; 920 921 if ((x & 3) != 0) 922 { 923 x = (x & ~3) + 2; 924 } 925 926 kernel.fDelta [j].v = ((x - patRow2) >> 1); 927 928 x = patCol2 + kernel.fDelta [j].h; 929 930 if ((x & 3) != 0) 931 { 932 x = (x & ~3) + 2; 933 } 934 935 kernel.fDelta [j].h = ((x - patCol2) >> 1); 936 937 } 938 939 kernel.Finalize (fScale, 940 patRow, 941 patCol, 942 rowStep, 943 colStep); 944 945 fCounts [patRow] [patCol] = kernel.fCount; 946 fOffsets [patRow] [patCol] = kernel.fOffset; 947 fWeights16 [patRow] [patCol] = kernel.fWeight16; 948 fWeights32 [patRow] [patCol] = kernel.fWeight32; 949 950 } 951 952 } 953 954 } 955 956 // Non-temp scale case. 957 958 else 959 { 960 961 for (patRow = 0; patRow < fPatRows; patRow++) 962 { 963 964 for (patCol = 0; patCol < fPatCols; patCol++) 965 { 966 967 dng_bilinear_kernel &kernel = fKernel [patRow] [patCol]; 968 969 kernel.Finalize (fScale, 970 patRow, 971 patCol, 972 rowStep, 973 colStep); 974 975 fCounts [patRow] [patCol] = kernel.fCount; 976 fOffsets [patRow] [patCol] = kernel.fOffset; 977 fWeights16 [patRow] [patCol] = kernel.fWeight16; 978 fWeights32 [patRow] [patCol] = kernel.fWeight32; 979 980 } 981 982 } 983 984 } 985 986 } 987 988 /*****************************************************************************/ 989 990 class dng_bilinear_interpolator 991 { 992 993 private: 994 995 dng_bilinear_pattern fPattern [kMaxColorPlanes]; 996 997 public: 998 999 dng_bilinear_interpolator (const dng_mosaic_info &info, 1000 int32 rowStep, 1001 int32 colStep); 1002 1003 void Interpolate (dng_pixel_buffer &srcBuffer, 1004 dng_pixel_buffer &dstBuffer); 1005 1006 }; 1007 1008 /*****************************************************************************/ 1009 1010 dng_bilinear_interpolator::dng_bilinear_interpolator (const dng_mosaic_info &info, 1011 int32 rowStep, 1012 int32 colStep) 1013 { 1014 1015 for (uint32 dstPlane = 0; dstPlane < info.fColorPlanes; dstPlane++) 1016 { 1017 1018 fPattern [dstPlane] . Calculate (info, 1019 dstPlane, 1020 rowStep, 1021 colStep); 1022 1023 } 1024 1025 } 1026 1027 /*****************************************************************************/ 1028 1029 void dng_bilinear_interpolator::Interpolate (dng_pixel_buffer &srcBuffer, 1030 dng_pixel_buffer &dstBuffer) 1031 { 1032 1033 uint32 patCols = fPattern [0] . fPatCols; 1034 uint32 patRows = fPattern [0] . fPatRows; 1035 1036 dng_point scale = fPattern [0] . fScale; 1037 1038 uint32 sRowShift = scale.v - 1; 1039 uint32 sColShift = scale.h - 1; 1040 1041 int32 dstCol = dstBuffer.fArea.l; 1042 1043 int32 srcCol = dstCol >> sColShift; 1044 1045 uint32 patPhase = dstCol % patCols; 1046 1047 for (int32 dstRow = dstBuffer.fArea.t; 1048 dstRow < dstBuffer.fArea.b; 1049 dstRow++) 1050 { 1051 1052 int32 srcRow = dstRow >> sRowShift; 1053 1054 uint32 patRow = dstRow % patRows; 1055 1056 for (uint32 dstPlane = 0; 1057 dstPlane < dstBuffer.fPlanes; 1058 dstPlane++) 1059 { 1060 1061 const void *sPtr = srcBuffer.ConstPixel (srcRow, 1062 srcCol, 1063 srcBuffer.fPlane); 1064 1065 void *dPtr = dstBuffer.DirtyPixel (dstRow, 1066 dstCol, 1067 dstPlane); 1068 1069 if (dstBuffer.fPixelType == ttShort) 1070 { 1071 1072 DoBilinearRow16 ((const uint16 *) sPtr, 1073 (uint16 *) dPtr, 1074 dstBuffer.fArea.W (), 1075 patPhase, 1076 patCols, 1077 fPattern [dstPlane].fCounts [patRow], 1078 fPattern [dstPlane].fOffsets [patRow], 1079 fPattern [dstPlane].fWeights16 [patRow], 1080 sColShift); 1081 1082 } 1083 1084 else 1085 { 1086 1087 DoBilinearRow32 ((const real32 *) sPtr, 1088 (real32 *) dPtr, 1089 dstBuffer.fArea.W (), 1090 patPhase, 1091 patCols, 1092 fPattern [dstPlane].fCounts [patRow], 1093 fPattern [dstPlane].fOffsets [patRow], 1094 fPattern [dstPlane].fWeights32 [patRow], 1095 sColShift); 1096 1097 } 1098 1099 } 1100 1101 } 1102 1103 } 1104 1105 /*****************************************************************************/ 1106 1107 class dng_fast_interpolator: public dng_filter_task 1108 { 1109 1110 protected: 1111 1112 const dng_mosaic_info &fInfo; 1113 1114 dng_point fDownScale; 1115 1116 uint32 fFilterColor [kMaxCFAPattern] [kMaxCFAPattern]; 1117 1118 public: 1119 1120 dng_fast_interpolator (const dng_mosaic_info &info, 1121 const dng_image &srcImage, 1122 dng_image &dstImage, 1123 const dng_point &downScale, 1124 uint32 srcPlane); 1125 1126 virtual dng_rect SrcArea (const dng_rect &dstArea); 1127 1128 virtual void ProcessArea (uint32 threadIndex, 1129 dng_pixel_buffer &srcBuffer, 1130 dng_pixel_buffer &dstBuffer); 1131 1132 }; 1133 1134 /*****************************************************************************/ 1135 1136 dng_fast_interpolator::dng_fast_interpolator (const dng_mosaic_info &info, 1137 const dng_image &srcImage, 1138 dng_image &dstImage, 1139 const dng_point &downScale, 1140 uint32 srcPlane) 1141 1142 : dng_filter_task (srcImage, 1143 dstImage) 1144 1145 , fInfo (info ) 1146 , fDownScale (downScale) 1147 1148 { 1149 1150 fSrcPlane = srcPlane; 1151 fSrcPlanes = 1; 1152 1153 fSrcPixelType = ttShort; 1154 fDstPixelType = ttShort; 1155 1156 fSrcRepeat = fInfo.fCFAPatternSize; 1157 1158 fUnitCell = fInfo.fCFAPatternSize; 1159 1160 fMaxTileSize = dng_point (256 / fDownScale.v, 1161 256 / fDownScale.h); 1162 1163 fMaxTileSize.h = Max_int32 (fMaxTileSize.h, fUnitCell.h); 1164 fMaxTileSize.v = Max_int32 (fMaxTileSize.v, fUnitCell.v); 1165 1166 // Find color map. 1167 1168 { 1169 1170 for (int32 r = 0; r < fInfo.fCFAPatternSize.v; r++) 1171 { 1172 1173 for (int32 c = 0; c < fInfo.fCFAPatternSize.h; c++) 1174 { 1175 1176 uint8 key = fInfo.fCFAPattern [r] [c]; 1177 1178 for (uint32 index = 0; index < fInfo.fColorPlanes; index++) 1179 { 1180 1181 if (key == fInfo.fCFAPlaneColor [index]) 1182 { 1183 1184 fFilterColor [r] [c] = index; 1185 1186 break; 1187 1188 } 1189 1190 } 1191 1192 } 1193 1194 } 1195 1196 } 1197 1198 } 1199 1200 /*****************************************************************************/ 1201 1202 dng_rect dng_fast_interpolator::SrcArea (const dng_rect &dstArea) 1203 { 1204 1205 return dng_rect (dstArea.t * fDownScale.v, 1206 dstArea.l * fDownScale.h, 1207 dstArea.b * fDownScale.v, 1208 dstArea.r * fDownScale.h); 1209 1210 } 1211 1212 /*****************************************************************************/ 1213 1214 void dng_fast_interpolator::ProcessArea (uint32 /* threadIndex */, 1215 dng_pixel_buffer &srcBuffer, 1216 dng_pixel_buffer &dstBuffer) 1217 { 1218 1219 dng_rect srcArea = srcBuffer.fArea; 1220 dng_rect dstArea = dstBuffer.fArea; 1221 1222 // Downsample buffer. 1223 1224 int32 srcRow = srcArea.t; 1225 1226 uint32 srcRowPhase1 = 0; 1227 uint32 srcRowPhase2 = 0; 1228 1229 uint32 patRows = fInfo.fCFAPatternSize.v; 1230 uint32 patCols = fInfo.fCFAPatternSize.h; 1231 1232 uint32 cellRows = fDownScale.v; 1233 uint32 cellCols = fDownScale.h; 1234 1235 uint32 plane; 1236 uint32 planes = fInfo.fColorPlanes; 1237 1238 int32 dstPlaneStep = dstBuffer.fPlaneStep; 1239 1240 uint32 total [kMaxColorPlanes]; 1241 uint32 count [kMaxColorPlanes]; 1242 1243 for (plane = 0; plane < planes; plane++) 1244 { 1245 total [plane] = 0; 1246 count [plane] = 0; 1247 } 1248 1249 for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++) 1250 { 1251 1252 const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (srcRow, 1253 srcArea.l, 1254 fSrcPlane); 1255 1256 uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, 1257 dstArea.l, 1258 0); 1259 1260 uint32 srcColPhase1 = 0; 1261 uint32 srcColPhase2 = 0; 1262 1263 for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++) 1264 { 1265 1266 const uint16 *ssPtr = sPtr; 1267 1268 srcRowPhase2 = srcRowPhase1; 1269 1270 for (uint32 cellRow = 0; cellRow < cellRows; cellRow++) 1271 { 1272 1273 const uint32 *filterRow = fFilterColor [srcRowPhase2]; 1274 1275 if (++srcRowPhase2 == patRows) 1276 { 1277 srcRowPhase2 = 0; 1278 } 1279 1280 srcColPhase2 = srcColPhase1; 1281 1282 for (uint32 cellCol = 0; cellCol < cellCols; cellCol++) 1283 { 1284 1285 uint32 color = filterRow [srcColPhase2]; 1286 1287 if (++srcColPhase2 == patCols) 1288 { 1289 srcColPhase2 = 0; 1290 } 1291 1292 total [color] += (uint32) ssPtr [cellCol]; 1293 count [color] ++; 1294 1295 } 1296 1297 ssPtr += srcBuffer.fRowStep; 1298 1299 } 1300 1301 for (plane = 0; plane < planes; plane++) 1302 { 1303 1304 uint32 t = total [plane]; 1305 uint32 c = count [plane]; 1306 1307 dPtr [plane * dstPlaneStep] = (uint16) ((t + (c >> 1)) / c); 1308 1309 total [plane] = 0; 1310 count [plane] = 0; 1311 1312 } 1313 1314 srcColPhase1 = srcColPhase2; 1315 1316 sPtr += cellCols; 1317 1318 dPtr ++; 1319 1320 } 1321 1322 srcRowPhase1 = srcRowPhase2; 1323 1324 srcRow += cellRows; 1325 1326 } 1327 1328 } 1329 1330 /*****************************************************************************/ 1331 1332 dng_mosaic_info::dng_mosaic_info () 1333 1334 : fCFAPatternSize () 1335 , fColorPlanes (0) 1336 , fCFALayout (1) 1337 , fBayerGreenSplit (0) 1338 , fSrcSize () 1339 , fCroppedSize () 1340 , fAspectRatio (1.0) 1341 1342 { 1343 1344 } 1345 1346 /*****************************************************************************/ 1347 1348 dng_mosaic_info::~dng_mosaic_info () 1349 { 1350 1351 } 1352 1353 /*****************************************************************************/ 1354 1355 void dng_mosaic_info::Parse (dng_host & /* host */, 1356 dng_stream & /* stream */, 1357 dng_info &info) 1358 { 1359 1360 // Find main image IFD. 1361 1362 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get (); 1363 1364 // This information only applies to CFA images. 1365 1366 if (rawIFD.fPhotometricInterpretation != piCFA) 1367 { 1368 return; 1369 } 1370 1371 // Copy CFA pattern. 1372 1373 fCFAPatternSize.v = rawIFD.fCFARepeatPatternRows; 1374 fCFAPatternSize.h = rawIFD.fCFARepeatPatternCols; 1375 1376 for (int32 j = 0; j < fCFAPatternSize.v; j++) 1377 { 1378 for (int32 k = 0; k < fCFAPatternSize.h; k++) 1379 { 1380 fCFAPattern [j] [k] = rawIFD.fCFAPattern [j] [k]; 1381 } 1382 } 1383 1384 // Copy CFA plane information. 1385 1386 fColorPlanes = info.fShared->fCameraProfile.fColorPlanes; 1387 1388 for (uint32 n = 0; n < fColorPlanes; n++) 1389 { 1390 fCFAPlaneColor [n] = rawIFD.fCFAPlaneColor [n]; 1391 } 1392 1393 // Copy CFA layout information. 1394 1395 fCFALayout = rawIFD.fCFALayout; 1396 1397 // Green split value for Bayer patterns. 1398 1399 fBayerGreenSplit = rawIFD.fBayerGreenSplit; 1400 1401 } 1402 1403 /*****************************************************************************/ 1404 1405 void dng_mosaic_info::PostParse (dng_host & /* host */, 1406 dng_negative &negative) 1407 { 1408 1409 // Keep track of source image size. 1410 1411 fSrcSize = negative.Stage2Image ()->Size (); 1412 1413 // Default cropped size. 1414 1415 fCroppedSize.v = Round_int32 (negative.DefaultCropSizeV ().As_real64 ()); 1416 fCroppedSize.h = Round_int32 (negative.DefaultCropSizeH ().As_real64 ()); 1417 1418 // Pixel aspect ratio. 1419 1420 fAspectRatio = negative.DefaultScaleH ().As_real64 () / 1421 negative.DefaultScaleV ().As_real64 (); 1422 1423 } 1424 1425 /*****************************************************************************/ 1426 1427 bool dng_mosaic_info::SetFourColorBayer () 1428 { 1429 1430 if (fCFAPatternSize != dng_point (2, 2)) 1431 { 1432 return false; 1433 } 1434 1435 if (fColorPlanes != 3) 1436 { 1437 return false; 1438 } 1439 1440 uint8 color0 = fCFAPlaneColor [0]; 1441 uint8 color1 = fCFAPlaneColor [1]; 1442 uint8 color2 = fCFAPlaneColor [2]; 1443 1444 // Look for color 1 repeated twice in a diagonal. 1445 1446 if ((fCFAPattern [0] [0] == color1 && fCFAPattern [1] [1] == color1) || 1447 (fCFAPattern [0] [1] == color1 && fCFAPattern [1] [0] == color1)) 1448 { 1449 1450 // OK, this looks like a Bayer pattern. 1451 1452 // Find unused color code. 1453 1454 uint8 color3 = 0; 1455 1456 while (color3 == color0 || 1457 color3 == color1 || 1458 color3 == color2) 1459 { 1460 color3++; 1461 } 1462 1463 // Switch the four color mosaic. 1464 1465 fColorPlanes = 4; 1466 1467 fCFAPlaneColor [3] = color3; 1468 1469 // Replace the "green" in the "blue" rows with the new color. 1470 1471 if (fCFAPattern [0] [0] == color0) 1472 { 1473 fCFAPattern [1] [0] = color3; 1474 } 1475 1476 else if (fCFAPattern [0] [1] == color0) 1477 { 1478 fCFAPattern [1] [1] = color3; 1479 } 1480 1481 else if (fCFAPattern [1] [0] == color0) 1482 { 1483 fCFAPattern [0] [0] = color3; 1484 } 1485 1486 else 1487 { 1488 fCFAPattern [0] [1] = color3; 1489 } 1490 1491 return true; 1492 1493 } 1494 1495 return false; 1496 1497 } 1498 1499 /*****************************************************************************/ 1500 1501 dng_point dng_mosaic_info::FullScale () const 1502 { 1503 1504 switch (fCFALayout) 1505 { 1506 1507 // Staggered layouts with offset columns double the row count 1508 // during interpolation. 1509 1510 case 2: 1511 case 3: 1512 return dng_point (2, 1); 1513 1514 // Staggered layouts with offset rows double the column count 1515 // during interpolation. 1516 1517 case 4: 1518 case 5: 1519 return dng_point (1, 2); 1520 1521 // Otherwise there is no size change during interpolation. 1522 1523 default: 1524 break; 1525 1526 } 1527 1528 return dng_point (1, 1); 1529 1530 } 1531 1532 /*****************************************************************************/ 1533 1534 bool dng_mosaic_info::IsSafeDownScale (const dng_point &downScale) const 1535 { 1536 1537 if (downScale.v >= fCFAPatternSize.v && 1538 downScale.h >= fCFAPatternSize.h) 1539 { 1540 1541 return true; 1542 1543 } 1544 1545 dng_point test; 1546 1547 test.v = Min_int32 (downScale.v, fCFAPatternSize.v); 1548 test.h = Min_int32 (downScale.h, fCFAPatternSize.h); 1549 1550 for (int32 phaseV = 0; phaseV <= fCFAPatternSize.v - test.v; phaseV++) 1551 { 1552 1553 for (int32 phaseH = 0; phaseH <= fCFAPatternSize.h - test.h; phaseH++) 1554 { 1555 1556 uint32 plane; 1557 1558 bool contains [kMaxColorPlanes]; 1559 1560 for (plane = 0; plane < fColorPlanes; plane++) 1561 { 1562 1563 contains [plane] = false; 1564 1565 } 1566 1567 for (int32 srcRow = 0; srcRow < test.v; srcRow++) 1568 { 1569 1570 for (int32 srcCol = 0; srcCol < test.h; srcCol++) 1571 { 1572 1573 uint8 srcKey = fCFAPattern [srcRow + phaseV] 1574 [srcCol + phaseH]; 1575 1576 for (plane = 0; plane < fColorPlanes; plane++) 1577 { 1578 1579 if (srcKey == fCFAPlaneColor [plane]) 1580 { 1581 1582 contains [plane] = true; 1583 1584 } 1585 1586 } 1587 1588 1589 } 1590 1591 } 1592 1593 for (plane = 0; plane < fColorPlanes; plane++) 1594 { 1595 1596 if (!contains [plane]) 1597 { 1598 1599 return false; 1600 1601 } 1602 1603 } 1604 1605 } 1606 1607 } 1608 1609 return true; 1610 1611 } 1612 1613 /*****************************************************************************/ 1614 1615 uint32 dng_mosaic_info::SizeForDownScale (const dng_point &downScale) const 1616 { 1617 1618 uint32 sizeV = Max_uint32 (1, (fCroppedSize.v + (downScale.v >> 1)) / downScale.v); 1619 uint32 sizeH = Max_uint32 (1, (fCroppedSize.h + (downScale.h >> 1)) / downScale.h); 1620 1621 return Max_int32 (sizeV, sizeH); 1622 1623 } 1624 1625 /*****************************************************************************/ 1626 1627 bool dng_mosaic_info::ValidSizeDownScale (const dng_point &downScale, 1628 uint32 minSize) const 1629 { 1630 1631 const int32 kMaxDownScale = 64; 1632 1633 if (downScale.h > kMaxDownScale || 1634 downScale.v > kMaxDownScale) 1635 { 1636 1637 return false; 1638 1639 } 1640 1641 return SizeForDownScale (downScale) >= minSize; 1642 1643 } 1644 1645 /*****************************************************************************/ 1646 1647 dng_point dng_mosaic_info::DownScale (uint32 minSize, 1648 uint32 prefSize, 1649 real64 cropFactor) const 1650 { 1651 1652 dng_point bestScale (1, 1); 1653 1654 if (prefSize && IsColorFilterArray ()) 1655 { 1656 1657 // Adjust sizes for crop factor. 1658 1659 minSize = Round_uint32 (minSize / cropFactor); 1660 prefSize = Round_uint32 (prefSize / cropFactor); 1661 1662 prefSize = Max_uint32 (prefSize, minSize); 1663 1664 // Start by assuming we need the full size image. 1665 1666 int32 bestSize = SizeForDownScale (bestScale); 1667 1668 // Find size of nearly square cell. 1669 1670 dng_point squareCell (1, 1); 1671 1672 if (fAspectRatio < 1.0 / 1.8) 1673 { 1674 1675 squareCell.h = Min_int32 (4, Round_int32 (1.0 / fAspectRatio)); 1676 1677 } 1678 1679 if (fAspectRatio > 1.8) 1680 { 1681 1682 squareCell.v = Min_int32 (4, Round_int32 (fAspectRatio)); 1683 1684 } 1685 1686 // Find minimum safe cell size. 1687 1688 dng_point testScale = squareCell; 1689 1690 while (!IsSafeDownScale (testScale)) 1691 { 1692 1693 testScale.v += squareCell.v; 1694 testScale.h += squareCell.h; 1695 1696 } 1697 1698 // See if this scale is usable. 1699 1700 if (!ValidSizeDownScale (testScale, minSize)) 1701 { 1702 1703 // We cannot downsample at all... 1704 1705 return bestScale; 1706 1707 } 1708 1709 // See if this is closer to the preferred size. 1710 1711 int32 testSize = SizeForDownScale (testScale); 1712 1713 if (Abs_int32 (testSize - (int32) prefSize) <= 1714 Abs_int32 (bestSize - (int32) prefSize)) 1715 { 1716 bestScale = testScale; 1717 bestSize = testSize; 1718 } 1719 1720 else 1721 { 1722 return bestScale; 1723 } 1724 1725 // Now keep adding square cells as long as possible. 1726 1727 while (true) 1728 { 1729 1730 testScale.v += squareCell.v; 1731 testScale.h += squareCell.h; 1732 1733 if (IsSafeDownScale (testScale)) 1734 { 1735 1736 if (!ValidSizeDownScale (testScale, minSize)) 1737 { 1738 return bestScale; 1739 } 1740 1741 // See if this is closer to the preferred size. 1742 1743 testSize = SizeForDownScale (testScale); 1744 1745 if (Abs_int32 (testSize - (int32) prefSize) <= 1746 Abs_int32 (bestSize - (int32) prefSize)) 1747 { 1748 bestScale = testScale; 1749 bestSize = testSize; 1750 } 1751 1752 else 1753 { 1754 return bestScale; 1755 } 1756 1757 } 1758 1759 } 1760 1761 } 1762 1763 return bestScale; 1764 1765 } 1766 1767 /*****************************************************************************/ 1768 1769 dng_point dng_mosaic_info::DstSize (const dng_point &downScale) const 1770 { 1771 1772 if (downScale == dng_point (1, 1)) 1773 { 1774 1775 dng_point scale = FullScale (); 1776 1777 return dng_point (fSrcSize.v * scale.v, 1778 fSrcSize.h * scale.h); 1779 1780 } 1781 1782 const int32 kMaxDownScale = 64; 1783 1784 if (downScale.h > kMaxDownScale || 1785 downScale.v > kMaxDownScale) 1786 { 1787 1788 return dng_point (0, 0); 1789 1790 } 1791 1792 dng_point size; 1793 1794 size.v = Max_int32 (1, (fSrcSize.v + (downScale.v >> 1)) / downScale.v); 1795 size.h = Max_int32 (1, (fSrcSize.h + (downScale.h >> 1)) / downScale.h); 1796 1797 return size; 1798 1799 } 1800 1801 /*****************************************************************************/ 1802 1803 void dng_mosaic_info::InterpolateGeneric (dng_host &host, 1804 dng_negative & /* negative */, 1805 const dng_image &srcImage, 1806 dng_image &dstImage, 1807 uint32 srcPlane) const 1808 { 1809 1810 // Find destination to source bit shifts. 1811 1812 dng_point scale = FullScale (); 1813 1814 uint32 srcShiftV = scale.v - 1; 1815 uint32 srcShiftH = scale.h - 1; 1816 1817 // Find tile sizes. 1818 1819 const uint32 kMaxDstTileRows = 128; 1820 const uint32 kMaxDstTileCols = 128; 1821 1822 dng_point dstTileSize = dstImage.RepeatingTile ().Size (); 1823 1824 dstTileSize.v = Min_int32 (dstTileSize.v, kMaxDstTileRows); 1825 dstTileSize.h = Min_int32 (dstTileSize.h, kMaxDstTileCols); 1826 1827 dng_point srcTileSize = dstTileSize; 1828 1829 srcTileSize.v >>= srcShiftV; 1830 srcTileSize.h >>= srcShiftH; 1831 1832 srcTileSize.v += fCFAPatternSize.v * 2; 1833 srcTileSize.h += fCFAPatternSize.h * 2; 1834 1835 // Allocate source buffer. 1836 1837 dng_pixel_buffer srcBuffer (dng_rect (srcTileSize), srcPlane, 1, 1838 srcImage.PixelType (), pcInterleaved, NULL); 1839 1840 uint32 srcBufferSize = ComputeBufferSize (srcBuffer.fPixelType, 1841 srcTileSize, srcBuffer.fPlanes, 1842 padNone); 1843 1844 AutoPtr<dng_memory_block> srcData (host.Allocate (srcBufferSize)); 1845 1846 srcBuffer.fData = srcData->Buffer (); 1847 1848 // Allocate destination buffer. 1849 1850 dng_pixel_buffer dstBuffer (dng_rect (dstTileSize), 0, fColorPlanes, 1851 dstImage.PixelType (), pcRowInterleaved, NULL); 1852 1853 uint32 dstBufferSize = ComputeBufferSize (dstBuffer.fPixelType, 1854 dstTileSize, dstBuffer.fPlanes, 1855 padNone); 1856 1857 AutoPtr<dng_memory_block> dstData (host.Allocate (dstBufferSize)); 1858 1859 dstBuffer.fData = dstData->Buffer (); 1860 1861 // Create interpolator. 1862 1863 AutoPtr<dng_bilinear_interpolator> interpolator (new dng_bilinear_interpolator (*this, 1864 srcBuffer.fRowStep, 1865 srcBuffer.fColStep)); 1866 1867 // Iterate over destination tiles. 1868 1869 dng_rect dstArea; 1870 1871 dng_tile_iterator iter1 (dstImage, dstImage.Bounds ()); 1872 1873 while (iter1.GetOneTile (dstArea)) 1874 { 1875 1876 // Break into buffer sized tiles. 1877 1878 dng_rect dstTile; 1879 1880 dng_tile_iterator iter2 (dstTileSize, dstArea); 1881 1882 while (iter2.GetOneTile (dstTile)) 1883 { 1884 1885 host.SniffForAbort (); 1886 1887 // Setup buffers for this tile. 1888 1889 dng_rect srcTile (dstTile); 1890 1891 srcTile.t >>= srcShiftV; 1892 srcTile.b >>= srcShiftV; 1893 1894 srcTile.l >>= srcShiftH; 1895 srcTile.r >>= srcShiftH; 1896 1897 srcTile.t -= fCFAPatternSize.v; 1898 srcTile.b += fCFAPatternSize.v; 1899 1900 srcTile.l -= fCFAPatternSize.h; 1901 srcTile.r += fCFAPatternSize.h; 1902 1903 srcBuffer.fArea = srcTile; 1904 dstBuffer.fArea = dstTile; 1905 1906 // Get source data. 1907 1908 srcImage.Get (srcBuffer, 1909 dng_image::edge_repeat, 1910 fCFAPatternSize.v, 1911 fCFAPatternSize.h); 1912 1913 // Process data. 1914 1915 interpolator->Interpolate (srcBuffer, 1916 dstBuffer); 1917 1918 // Save results. 1919 1920 dstImage.Put (dstBuffer); 1921 1922 } 1923 1924 } 1925 1926 } 1927 1928 /*****************************************************************************/ 1929 1930 void dng_mosaic_info::InterpolateFast (dng_host &host, 1931 dng_negative & /* negative */, 1932 const dng_image &srcImage, 1933 dng_image &dstImage, 1934 const dng_point &downScale, 1935 uint32 srcPlane) const 1936 { 1937 1938 // Create fast interpolator task. 1939 1940 dng_fast_interpolator interpolator (*this, 1941 srcImage, 1942 dstImage, 1943 downScale, 1944 srcPlane); 1945 1946 // Find area to process. 1947 1948 dng_rect bounds = dstImage.Bounds (); 1949 1950 // Do the interpolation. 1951 1952 host.PerformAreaTask (interpolator, 1953 bounds); 1954 1955 } 1956 1957 /*****************************************************************************/ 1958 1959 void dng_mosaic_info::Interpolate (dng_host &host, 1960 dng_negative &negative, 1961 const dng_image &srcImage, 1962 dng_image &dstImage, 1963 const dng_point &downScale, 1964 uint32 srcPlane) const 1965 { 1966 1967 if (downScale == dng_point (1, 1)) 1968 { 1969 1970 InterpolateGeneric (host, 1971 negative, 1972 srcImage, 1973 dstImage, 1974 srcPlane); 1975 1976 } 1977 1978 else 1979 { 1980 1981 InterpolateFast (host, 1982 negative, 1983 srcImage, 1984 dstImage, 1985 downScale, 1986 srcPlane); 1987 1988 } 1989 1990 } 1991 1992 /*****************************************************************************/ 1993