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
100void dng_hue_sat_map::SetDivisions (uint32 hueDivisions,
101 uint32 satDivisions,
102 uint32 valDivisions)
103 {
104
105 DNG_ASSERT (hueDivisions >= 1, "Must have at least 1 hue division.");
106 DNG_ASSERT (satDivisions >= 2, "Must have at least 2 sat divisions.");
107
108 if (valDivisions == 0)
109 valDivisions = 1;
110
111 if (hueDivisions == fHueDivisions &&
112 satDivisions == fSatDivisions &&
113 valDivisions == fValDivisions)
114 {
115 return;
116 }
117
118 fHueDivisions = hueDivisions;
119 fSatDivisions = satDivisions;
120 fValDivisions = valDivisions;
121
122 fHueStep = satDivisions;
123 fValStep = SafeUint32Mult(hueDivisions, fHueStep);
124
125 uint32 size = SafeUint32Mult(DeltasCount (), (uint32) sizeof (HSBModify));
126
127 fDeltas.Allocate (size);
128
129 DoZeroBytes (fDeltas.Buffer (), size);
130
131 }
132
133/*****************************************************************************/
134
135void dng_hue_sat_map::GetDelta (uint32 hueDiv,
136 uint32 satDiv,
137 uint32 valDiv,
138 HSBModify &modify) const
139 {
140
141 if (hueDiv >= fHueDivisions ||
142 satDiv >= fSatDivisions ||
143 valDiv >= fValDivisions ||
144 fDeltas.Buffer () == NULL)
145 {
146
147 DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
148
149 ThrowProgramError ();
150
151 }
152
153 int32 offset = valDiv * fValStep +
154 hueDiv * fHueStep +
155 satDiv;
156
157 const HSBModify *deltas = GetConstDeltas ();
158
159 modify.fHueShift = deltas [offset].fHueShift;
160 modify.fSatScale = deltas [offset].fSatScale;
161 modify.fValScale = deltas [offset].fValScale;
162
163 }
164
165/*****************************************************************************/
166
167void dng_hue_sat_map::SetDeltaKnownWriteable (uint32 hueDiv,
168 uint32 satDiv,
169 uint32 valDiv,
170 const HSBModify &modify)
171 {
172
173 if (hueDiv >= fHueDivisions ||
174 satDiv >= fSatDivisions ||
175 valDiv >= fValDivisions ||
176 fDeltas.Buffer () == NULL)
177 {
178
179 DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
180
181 ThrowProgramError ();
182
183 }
184
185 // Set this entry.
186
187 int32 offset = valDiv * fValStep +
188 hueDiv * fHueStep +
189 satDiv;
190
191 SafeGetDeltas () [offset] = modify;
192
193 // The zero saturation entry is required to have a value scale
194 // of 1.0f.
195
196 if (satDiv == 0)
197 {
198
199 if (modify.fValScale != 1.0f)
200 {
201
202 #if qDNGValidate
203
204 ReportWarning ("Value scale for zero saturation entries must be 1.0");
205
206 #endif
207
208 SafeGetDeltas () [offset] . fValScale = 1.0f;
209
210 }
211
212 }
213
214 // If we are settings the first saturation entry and we have not
215 // set the zero saturation entry yet, fill in the zero saturation entry
216 // by extrapolating first saturation entry.
217
218 if (satDiv == 1)
219 {
220
221 HSBModify zeroSatModify;
222
223 GetDelta (hueDiv, 0, valDiv, zeroSatModify);
224
225 if (zeroSatModify.fValScale != 1.0f)
226 {
227
228 zeroSatModify.fHueShift = modify.fHueShift;
229 zeroSatModify.fSatScale = modify.fSatScale;
230 zeroSatModify.fValScale = 1.0f;
231
232 SetDelta (hueDiv, 0, valDiv, zeroSatModify);
233
234 }
235
236 }
237
238 }
239
240/*****************************************************************************/
241
242bool dng_hue_sat_map::operator== (const dng_hue_sat_map &rhs) const
243 {
244
245 if (fHueDivisions != rhs.fHueDivisions ||
246 fSatDivisions != rhs.fSatDivisions ||
247 fValDivisions != rhs.fValDivisions)
248 return false;
249
250 if (!IsValid ())
251 return true;
252
253 return memcmp (GetConstDeltas (),
254 rhs.GetConstDeltas (),
255 DeltasCount () * sizeof (HSBModify)) == 0;
256
257 }
258
259/*****************************************************************************/
260
261dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
262 const dng_hue_sat_map &map2,
263 real64 weight1)
264 {
265
266 if (weight1 >= 1.0)
267 {
268
269 if (!map1.IsValid ())
270 {
271
272 DNG_REPORT ("map1 is not valid");
273
274 ThrowProgramError ();
275
276 }
277
278 return new dng_hue_sat_map (map1);
279
280 }
281
282 if (weight1 <= 0.0)
283 {
284
285 if (!map2.IsValid ())
286 {
287 DNG_REPORT ("map2 is not valid");
288
289 ThrowProgramError ();
290
291 }
292
293 return new dng_hue_sat_map (map2);
294
295 }
296
297 // Both maps must be valid if we are using both.
298
299 if (!map1.IsValid () || !map2.IsValid ())
300 {
301
302 DNG_REPORT ("map1 or map2 is not valid");
303
304 ThrowProgramError ();
305
306 }
307
308 // Must have the same dimensions.
309
310 if (map1.fHueDivisions != map2.fHueDivisions ||
311 map1.fSatDivisions != map2.fSatDivisions ||
312 map1.fValDivisions != map2.fValDivisions)
313 {
314
315 DNG_REPORT ("map1 and map2 have different sizes");
316
317 ThrowProgramError ();
318
319 }
320
321 // Make table to hold interpolated results.
322
323 AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
324
325 result->SetDivisions (map1.fHueDivisions,
326 map1.fSatDivisions,
327 map1.fValDivisions);
328
329 // Interpolate between the tables.
330
331 real32 w1 = (real32) weight1;
332 real32 w2 = 1.0f - w1;
333
334 const HSBModify *data1 = map1.GetConstDeltas ();
335 const HSBModify *data2 = map2.GetConstDeltas ();
336
337 HSBModify *data3 = result->SafeGetDeltas ();
338
339 uint32 count = map1.DeltasCount ();
340
341 for (uint32 index = 0; index < count; index++)
342 {
343
344 data3->fHueShift = w1 * data1->fHueShift +
345 w2 * data2->fHueShift;
346
347 data3->fSatScale = w1 * data1->fSatScale +
348 w2 * data2->fSatScale;
349
350 data3->fValScale = w1 * data1->fValScale +
351 w2 * data2->fValScale;
352
353 data1++;
354 data2++;
355 data3++;
356
357 }
358
359 // Return interpolated tables.
360
361 return result.Release ();
362
363 }
364
365/*****************************************************************************/
366