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
28class 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
95dng_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
177real32 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
187void 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
252dng_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
276real32 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
294uint32 dng_gain_map::PutStreamSize () const
295 {
296
297 return 44 + fPoints.v * fPoints.h * fPlanes * 4;
298
299 }
300
301/*****************************************************************************/
302
303void 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
340dng_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
480dng_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
499dng_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
529void 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
543void 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