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 
Interpolate() const59 		real32 Interpolate () const
60 			{
61 
62 			return fValueBase + fValueStep * fValueIndex;
63 
64 			}
65 
Increment()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 
dng_gain_map_interpolator(const dng_gain_map & map,const dng_rect & mapBounds,int32 row,int32 column,uint32 plane)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 
InterpolateEntry(uint32 colIndex)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 
ResetColumn()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 
dng_gain_map(dng_memory_allocator & allocator,const dng_point & points,const dng_point_real64 & spacing,const dng_point_real64 & origin,uint32 planes)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 
Interpolate(int32 row,int32 col,uint32 plane,const dng_rect & bounds) const276 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 
PutStreamSize() const294 uint32 dng_gain_map::PutStreamSize () const
295 	{
296 
297 	return 44 + fPoints.v * fPoints.h * fPlanes * 4;
298 
299 	}
300 
301 /*****************************************************************************/
302 
PutStream(dng_stream & stream) const303 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 
GetStream(dng_host & host,dng_stream & stream)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 
dng_opcode_GainMap(const dng_area_spec & areaSpec,AutoPtr<dng_gain_map> & gainMap)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 
dng_opcode_GainMap(dng_host & host,dng_stream & stream)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 
PutData(dng_stream & stream) const529 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 
ProcessArea(dng_negative &,uint32,dng_pixel_buffer & buffer,const dng_rect & dstArea,const dng_rect & imageBounds)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