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