dng_hue_sat_map.cpp revision 29c7498fabe2e3c87a85b487bfe9d783c401e1f0
1/*****************************************************************************/
2// Copyright 2007 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_hue_sat_map.cpp#1 $ */
10/* $DateTime: 2012/05/30 13:28:51 $ */
11/* $Change: 832332 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_hue_sat_map.h"
17
18#include "dng_assertions.h"
19#include "dng_auto_ptr.h"
20#include "dng_bottlenecks.h"
21#include "dng_exceptions.h"
22#include "dng_host.h"
23
24/*****************************************************************************/
25
26dng_hue_sat_map::dng_hue_sat_map ()
27
28	:	fHueDivisions (0)
29	,	fSatDivisions (0)
30	,	fValDivisions (0)
31	,	fHueStep      (0)
32	,	fValStep	  (0)
33	,	fDeltas       ()
34
35	{
36
37	}
38
39/*****************************************************************************/
40
41dng_hue_sat_map::dng_hue_sat_map (const dng_hue_sat_map &src)
42
43	:	fHueDivisions (0)
44	,	fSatDivisions (0)
45	,	fValDivisions (0)
46	,	fHueStep      (0)
47	,	fValStep	  (0)
48	,	fDeltas       ()
49
50	{
51
52	*this = src;
53
54	}
55
56/*****************************************************************************/
57
58dng_hue_sat_map &dng_hue_sat_map::operator= (const dng_hue_sat_map &rhs)
59	{
60
61	if (this != &rhs)
62		{
63
64		if (!rhs.IsValid ())
65			{
66
67			SetInvalid ();
68
69			}
70
71		else
72			{
73
74			fHueDivisions = rhs.fHueDivisions;
75			fSatDivisions = rhs.fSatDivisions;
76			fValDivisions = rhs.fValDivisions;
77
78			fHueStep = rhs.fHueStep;
79			fValStep = rhs.fValStep;
80
81			fDeltas = rhs.fDeltas;
82
83			}
84
85		}
86
87	return *this;
88
89	}
90
91/*****************************************************************************/
92
93dng_hue_sat_map::~dng_hue_sat_map ()
94	{
95
96	}
97
98/*****************************************************************************/
99
100#if defined(__clang__) && defined(__has_attribute)
101#if __has_attribute(no_sanitize)
102__attribute__((no_sanitize("unsigned-integer-overflow")))
103#endif
104#endif
105void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
106									uint32 satDivisions,
107									uint32 valDivisions)
108	{
109
110	DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
111	DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
112
113	if (valDivisions == 0)
114		valDivisions = 1;
115
116	if (hueDivisions == fHueDivisions &&
117		satDivisions == fSatDivisions &&
118		valDivisions == fValDivisions)
119		{
120		return;
121		}
122
123	fHueDivisions = hueDivisions;
124	fSatDivisions = satDivisions;
125	fValDivisions = valDivisions;
126
127	fHueStep = satDivisions;
128	fValStep = hueDivisions * fHueStep;
129
130	uint32 size = DeltasCount () * (uint32) sizeof (HSBModify);
131
132	fDeltas.Allocate (size);
133
134	DoZeroBytes (fDeltas.Buffer (), size);
135
136	}
137
138/*****************************************************************************/
139
140void dng_hue_sat_map::GetDelta (uint32 hueDiv,
141								uint32 satDiv,
142								uint32 valDiv,
143								HSBModify &modify) const
144	{
145
146	if (hueDiv >= fHueDivisions ||
147		satDiv >= fSatDivisions ||
148		valDiv >= fValDivisions ||
149		fDeltas.Buffer () == NULL)
150		{
151
152		DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
153
154		ThrowProgramError ();
155
156		}
157
158	int32 offset = valDiv * fValStep +
159				   hueDiv * fHueStep +
160				   satDiv;
161
162	const HSBModify *deltas = GetConstDeltas ();
163
164	modify.fHueShift = deltas [offset].fHueShift;
165	modify.fSatScale = deltas [offset].fSatScale;
166	modify.fValScale = deltas [offset].fValScale;
167
168	}
169
170/*****************************************************************************/
171
172void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
173											  uint32 satDiv,
174											  uint32 valDiv,
175											  const HSBModify &modify)
176	{
177
178	if (hueDiv >= fHueDivisions ||
179		satDiv >= fSatDivisions ||
180		valDiv >= fValDivisions ||
181		fDeltas.Buffer () == NULL)
182		{
183
184		DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
185
186		ThrowProgramError ();
187
188		}
189
190	// Set this entry.
191
192	int32 offset = valDiv * fValStep +
193				   hueDiv * fHueStep +
194				   satDiv;
195
196	SafeGetDeltas () [offset] = modify;
197
198	// The zero saturation entry is required to have a value scale
199	// of 1.0f.
200
201	if (satDiv == 0)
202		{
203
204		if (modify.fValScale != 1.0f)
205			{
206
207			#if qDNGValidate
208
209			ReportWarning ("Value scale for zero saturation entries must be 1.0");
210
211			#endif
212
213			SafeGetDeltas () [offset] . fValScale = 1.0f;
214
215			}
216
217		}
218
219	// If we are settings the first saturation entry and we have not
220	// set the zero saturation entry yet, fill in the zero saturation entry
221	// by extrapolating first saturation entry.
222
223	if (satDiv == 1)
224		{
225
226		HSBModify zeroSatModify;
227
228		GetDelta (hueDiv, 0, valDiv, zeroSatModify);
229
230		if (zeroSatModify.fValScale != 1.0f)
231			{
232
233			zeroSatModify.fHueShift = modify.fHueShift;
234			zeroSatModify.fSatScale = modify.fSatScale;
235			zeroSatModify.fValScale = 1.0f;
236
237			SetDelta (hueDiv, 0, valDiv, zeroSatModify);
238
239			}
240
241		}
242
243	}
244
245/*****************************************************************************/
246
247bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
248	{
249
250	if (fHueDivisions != rhs.fHueDivisions ||
251		fSatDivisions != rhs.fSatDivisions ||
252		fValDivisions != rhs.fValDivisions)
253		return false;
254
255	if (!IsValid ())
256		return true;
257
258	return memcmp (GetConstDeltas (),
259				   rhs.GetConstDeltas (),
260				   DeltasCount () * sizeof (HSBModify)) == 0;
261
262	}
263
264/*****************************************************************************/
265
266dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
267											    const dng_hue_sat_map &map2,
268											    real64 weight1)
269	{
270
271	if (weight1 >= 1.0)
272		{
273
274		if (!map1.IsValid ())
275			{
276
277			DNG_REPORT ("map1 is not valid");
278
279			ThrowProgramError ();
280
281			}
282
283		return new dng_hue_sat_map (map1);
284
285		}
286
287	if (weight1 <= 0.0)
288		{
289
290		if (!map2.IsValid ())
291			{
292			DNG_REPORT ("map2 is not valid");
293
294			ThrowProgramError ();
295
296			}
297
298		return new dng_hue_sat_map (map2);
299
300		}
301
302	// Both maps must be valid if we are using both.
303
304	if (!map1.IsValid () || !map2.IsValid ())
305		{
306
307		DNG_REPORT ("map1 or map2 is not valid");
308
309		ThrowProgramError ();
310
311		}
312
313	// Must have the same dimensions.
314
315	if (map1.fHueDivisions != map2.fHueDivisions ||
316		map1.fSatDivisions != map2.fSatDivisions ||
317		map1.fValDivisions != map2.fValDivisions)
318		{
319
320		DNG_REPORT ("map1 and map2 have different sizes");
321
322		ThrowProgramError ();
323
324		}
325
326	// Make table to hold interpolated results.
327
328	AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
329
330	result->SetDivisions (map1.fHueDivisions,
331						  map1.fSatDivisions,
332						  map1.fValDivisions);
333
334	// Interpolate between the tables.
335
336	real32 w1 = (real32) weight1;
337	real32 w2 = 1.0f - w1;
338
339	const HSBModify *data1 = map1.GetConstDeltas ();
340	const HSBModify *data2 = map2.GetConstDeltas ();
341
342	HSBModify *data3 = result->SafeGetDeltas ();
343
344	uint32 count = map1.DeltasCount ();
345
346	for (uint32 index = 0; index < count; index++)
347		{
348
349		data3->fHueShift = w1 * data1->fHueShift +
350						   w2 * data2->fHueShift;
351
352		data3->fSatScale = w1 * data1->fSatScale +
353						   w2 * data2->fSatScale;
354
355		data3->fValScale = w1 * data1->fValScale +
356						   w2 * data2->fValScale;
357
358		data1++;
359		data2++;
360		data3++;
361
362		}
363
364	// Return interpolated tables.
365
366	return result.Release ();
367
368	}
369
370/*****************************************************************************/
371