1 /*****************************************************************************/ 2 // Copyright 2008-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_gain_map.cpp#1 $ */ 10 /* $DateTime: 2012/05/30 13:28:51 $ */ 11 /* $Change: 832332 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_gain_map.h" 17 18 #include "dng_exceptions.h" 19 #include "dng_globals.h" 20 #include "dng_host.h" 21 #include "dng_pixel_buffer.h" 22 #include "dng_safe_arithmetic.h" 23 #include "dng_stream.h" 24 #include "dng_tag_values.h" 25 26 /*****************************************************************************/ 27 28 class dng_gain_map_interpolator 29 { 30 31 private: 32 33 const dng_gain_map &fMap; 34 35 dng_point_real64 fScale; 36 dng_point_real64 fOffset; 37 38 int32 fColumn; 39 int32 fPlane; 40 41 uint32 fRowIndex1; 42 uint32 fRowIndex2; 43 real32 fRowFract; 44 45 int32 fResetColumn; 46 47 real32 fValueBase; 48 real32 fValueStep; 49 real32 fValueIndex; 50 51 public: 52 53 dng_gain_map_interpolator (const dng_gain_map &map, 54 const dng_rect &mapBounds, 55 int32 row, 56 int32 column, 57 uint32 plane); 58 59 real32 Interpolate () const 60 { 61 62 return fValueBase + fValueStep * fValueIndex; 63 64 } 65 66 void Increment () 67 { 68 69 if (++fColumn >= fResetColumn) 70 { 71 72 ResetColumn (); 73 74 } 75 76 else 77 { 78 79 fValueIndex += 1.0f; 80 81 } 82 83 } 84 85 private: 86 87 real32 InterpolateEntry (uint32 colIndex); 88 89 void ResetColumn (); 90 91 }; 92 93 /*****************************************************************************/ 94 95 dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map, 96 const dng_rect &mapBounds, 97 int32 row, 98 int32 column, 99 uint32 plane) 100 101 : fMap (map) 102 103 , fScale (1.0 / mapBounds.H (), 104 1.0 / mapBounds.W ()) 105 106 , fOffset (0.5 - mapBounds.t, 107 0.5 - mapBounds.l) 108 109 , fColumn (column) 110 , fPlane (plane) 111 112 , fRowIndex1 (0) 113 , fRowIndex2 (0) 114 , fRowFract (0.0f) 115 116 , fResetColumn (0) 117 118 , fValueBase (0.0f) 119 , fValueStep (0.0f) 120 , fValueIndex (0.0f) 121 122 { 123 124 real64 rowIndexF = (fScale.v * (row + fOffset.v) - 125 fMap.Origin ().v) / fMap.Spacing ().v; 126 127 if (rowIndexF <= 0.0) 128 { 129 130 fRowIndex1 = 0; 131 fRowIndex2 = 0; 132 133 fRowFract = 0.0f; 134 135 } 136 137 else 138 { 139 140 if (fMap.Points ().v < 1) 141 { 142 ThrowProgramError ("Empty gain map"); 143 } 144 uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1); 145 146 if (rowIndexF >= static_cast<real64> (lastRow)) 147 { 148 149 fRowIndex1 = lastRow; 150 fRowIndex2 = fRowIndex1; 151 152 fRowFract = 0.0f; 153 154 } 155 156 else 157 { 158 159 // If we got here, we know that rowIndexF can safely be converted to 160 // a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This 161 // implies fRowIndex2 <= lastRow below. 162 fRowIndex1 = static_cast<uint32> (rowIndexF); 163 fRowIndex2 = fRowIndex1 + 1; 164 165 fRowFract = (real32) (rowIndexF - (real64) fRowIndex1); 166 167 } 168 169 } 170 171 ResetColumn (); 172 173 } 174 175 /*****************************************************************************/ 176 177 real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex) 178 { 179 180 return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) + 181 fMap.Entry (fRowIndex2, colIndex, fPlane) * ( fRowFract); 182 183 } 184 185 /*****************************************************************************/ 186 187 void dng_gain_map_interpolator::ResetColumn () 188 { 189 190 real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) - 191 fMap.Origin ().h) / fMap.Spacing ().h; 192 193 if (colIndexF <= 0.0) 194 { 195 196 fValueBase = InterpolateEntry (0); 197 198 fValueStep = 0.0f; 199 200 fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h); 201 202 } 203 204 else 205 { 206 207 if (fMap.Points ().h < 1) 208 { 209 ThrowProgramError ("Empty gain map"); 210 } 211 uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1); 212 213 if (colIndexF >= static_cast<real64> (lastCol)) 214 { 215 216 fValueBase = InterpolateEntry (lastCol); 217 218 fValueStep = 0.0f; 219 220 fResetColumn = 0x7FFFFFFF; 221 222 } 223 224 else 225 { 226 227 // If we got here, we know that colIndexF can safely be converted to 228 // a uint32 and that static_cast<uint32> (colIndexF) < lastCol. This 229 // implies colIndex + 1 <= lastCol, i.e. the argument to 230 // InterpolateEntry() below is valid. 231 uint32 colIndex = static_cast<uint32> (colIndexF); 232 real64 base = InterpolateEntry (colIndex); 233 real64 delta = InterpolateEntry (colIndex + 1) - base; 234 235 fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex)); 236 237 fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h); 238 239 fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h + 240 fMap.Origin ().h) / fScale.h - fOffset.h); 241 242 } 243 244 } 245 246 fValueIndex = 0.0f; 247 248 } 249 250 /*****************************************************************************/ 251 252 dng_gain_map::dng_gain_map (dng_memory_allocator &allocator, 253 const dng_point &points, 254 const dng_point_real64 &spacing, 255 const dng_point_real64 &origin, 256 uint32 planes) 257 258 : fPoints (points) 259 , fSpacing (spacing) 260 , fOrigin (origin) 261 , fPlanes (planes) 262 263 , fRowStep (SafeUint32Mult(planes, points.h)) 264 265 , fBuffer () 266 267 { 268 269 fBuffer.Reset (allocator.Allocate ( 270 ComputeBufferSize (ttFloat, fPoints, fPlanes, pad16Bytes))); 271 272 } 273 274 /*****************************************************************************/ 275 276 real32 dng_gain_map::Interpolate (int32 row, 277 int32 col, 278 uint32 plane, 279 const dng_rect &bounds) const 280 { 281 282 dng_gain_map_interpolator interp (*this, 283 bounds, 284 row, 285 col, 286 plane); 287 288 return interp.Interpolate (); 289 290 } 291 292 /*****************************************************************************/ 293 294 uint32 dng_gain_map::PutStreamSize () const 295 { 296 297 return 44 + fPoints.v * fPoints.h * fPlanes * 4; 298 299 } 300 301 /*****************************************************************************/ 302 303 void dng_gain_map::PutStream (dng_stream &stream) const 304 { 305 306 stream.Put_uint32 (fPoints.v); 307 stream.Put_uint32 (fPoints.h); 308 309 stream.Put_real64 (fSpacing.v); 310 stream.Put_real64 (fSpacing.h); 311 312 stream.Put_real64 (fOrigin.v); 313 stream.Put_real64 (fOrigin.h); 314 315 stream.Put_uint32 (fPlanes); 316 317 for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++) 318 { 319 320 for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++) 321 { 322 323 for (uint32 plane = 0; plane < fPlanes; plane++) 324 { 325 326 stream.Put_real32 (Entry (rowIndex, 327 colIndex, 328 plane)); 329 330 } 331 332 } 333 334 } 335 336 } 337 338 /*****************************************************************************/ 339 340 dng_gain_map * dng_gain_map::GetStream (dng_host &host, 341 dng_stream &stream) 342 { 343 344 dng_point mapPoints; 345 346 mapPoints.v = stream.Get_uint32 (); 347 mapPoints.h = stream.Get_uint32 (); 348 349 dng_point_real64 mapSpacing; 350 351 mapSpacing.v = stream.Get_real64 (); 352 mapSpacing.h = stream.Get_real64 (); 353 354 dng_point_real64 mapOrigin; 355 356 mapOrigin.v = stream.Get_real64 (); 357 mapOrigin.h = stream.Get_real64 (); 358 359 uint32 mapPlanes = stream.Get_uint32 (); 360 361 #if qDNGValidate 362 363 if (gVerbose) 364 { 365 366 printf ("Points: v=%d, h=%d\n", 367 (int) mapPoints.v, 368 (int) mapPoints.h); 369 370 printf ("Spacing: v=%.6f, h=%.6f\n", 371 mapSpacing.v, 372 mapSpacing.h); 373 374 printf ("Origin: v=%.6f, h=%.6f\n", 375 mapOrigin.v, 376 mapOrigin.h); 377 378 printf ("Planes: %u\n", 379 (unsigned) mapPlanes); 380 381 } 382 383 #endif 384 385 if (mapPoints.v == 1) 386 { 387 mapSpacing.v = 1.0; 388 mapOrigin.v = 0.0; 389 } 390 391 if (mapPoints.h == 1) 392 { 393 mapSpacing.h = 1.0; 394 mapOrigin.h = 0.0; 395 } 396 397 if (mapPoints.v < 1 || 398 mapPoints.h < 1 || 399 mapSpacing.v <= 0.0 || 400 mapSpacing.h <= 0.0 || 401 mapPlanes < 1) 402 { 403 ThrowBadFormat (); 404 } 405 406 AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (), 407 mapPoints, 408 mapSpacing, 409 mapOrigin, 410 mapPlanes)); 411 412 #if qDNGValidate 413 414 uint32 linesPrinted = 0; 415 uint32 linesSkipped = 0; 416 417 #endif 418 419 for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++) 420 { 421 422 for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++) 423 { 424 425 for (uint32 plane = 0; plane < mapPlanes; plane++) 426 { 427 428 real32 x = stream.Get_real32 (); 429 430 map->Entry (rowIndex, colIndex, plane) = x; 431 432 #if qDNGValidate 433 434 if (gVerbose) 435 { 436 437 if (linesPrinted < gDumpLineLimit) 438 { 439 440 printf (" Map [%3u] [%3u] [%u] = %.4f\n", 441 (unsigned) rowIndex, 442 (unsigned) colIndex, 443 (unsigned) plane, 444 x); 445 446 linesPrinted++; 447 448 } 449 450 else 451 linesSkipped++; 452 453 } 454 455 #endif 456 457 } 458 459 } 460 461 } 462 463 #if qDNGValidate 464 465 if (linesSkipped) 466 { 467 468 printf (" ... %u map entries skipped\n", (unsigned) linesSkipped); 469 470 } 471 472 #endif 473 474 return map.Release (); 475 476 } 477 478 /*****************************************************************************/ 479 480 dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec, 481 AutoPtr<dng_gain_map> &gainMap) 482 483 : dng_inplace_opcode (dngOpcode_GainMap, 484 dngVersion_1_3_0_0, 485 kFlag_None) 486 487 , fAreaSpec (areaSpec) 488 489 , fGainMap () 490 491 { 492 493 fGainMap.Reset (gainMap.Release ()); 494 495 } 496 497 /*****************************************************************************/ 498 499 dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host, 500 dng_stream &stream) 501 502 : dng_inplace_opcode (dngOpcode_GainMap, 503 stream, 504 "GainMap") 505 506 , fAreaSpec () 507 508 , fGainMap () 509 510 { 511 512 uint32 byteCount = stream.Get_uint32 (); 513 514 uint64 startPosition = stream.Position (); 515 516 fAreaSpec.GetData (stream); 517 518 fGainMap.Reset (dng_gain_map::GetStream (host, stream)); 519 520 if (stream.Position () != startPosition + byteCount) 521 { 522 ThrowBadFormat (); 523 } 524 525 } 526 527 /*****************************************************************************/ 528 529 void dng_opcode_GainMap::PutData (dng_stream &stream) const 530 { 531 532 stream.Put_uint32 (dng_area_spec::kDataSize + 533 fGainMap->PutStreamSize ()); 534 535 fAreaSpec.PutData (stream); 536 537 fGainMap->PutStream (stream); 538 539 } 540 541 /*****************************************************************************/ 542 543 void dng_opcode_GainMap::ProcessArea (dng_negative & /* negative */, 544 uint32 /* threadIndex */, 545 dng_pixel_buffer &buffer, 546 const dng_rect &dstArea, 547 const dng_rect &imageBounds) 548 { 549 550 dng_rect overlap = fAreaSpec.Overlap (dstArea); 551 552 if (overlap.NotEmpty ()) 553 { 554 555 uint32 cols = overlap.W (); 556 557 uint32 colPitch = fAreaSpec.ColPitch (); 558 559 for (uint32 plane = fAreaSpec.Plane (); 560 plane < fAreaSpec.Plane () + fAreaSpec.Planes () && 561 plane < buffer.Planes (); 562 plane++) 563 { 564 565 uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1); 566 567 for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ()) 568 { 569 570 real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane); 571 572 dng_gain_map_interpolator interp (*fGainMap, 573 imageBounds, 574 row, 575 overlap.l, 576 mapPlane); 577 578 for (uint32 col = 0; col < cols; col += colPitch) 579 { 580 581 real32 gain = interp.Interpolate (); 582 583 dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f); 584 585 for (uint32 j = 0; j < colPitch; j++) 586 { 587 interp.Increment (); 588 } 589 590 } 591 592 } 593 594 } 595 596 } 597 598 } 599 600 /*****************************************************************************/ 601