Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/dng_sdk/source/dng_color_spec.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************/
2
// Copyright 2006-2008 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_color_spec.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
#include "dng_color_spec.h"
15
16
#include "dng_assertions.h"
17
#include "dng_camera_profile.h"
18
#include "dng_exceptions.h"
19
#include "dng_matrix.h"
20
#include "dng_negative.h"
21
#include "dng_temperature.h"
22
#include "dng_utils.h"
23
#include "dng_xy_coord.h"
24
25
/*****************************************************************************/
26
27
dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1,
28
                    const dng_xy_coord &white2)
29
0
  {
30
  
31
  // Use the linearized Bradford adaptation matrix.
32
  
33
0
  dng_matrix_3by3 Mb ( 0.8951,  0.2664, -0.1614,
34
0
                -0.7502,  1.7135,  0.0367,
35
0
                 0.0389, -0.0685,  1.0296);
36
  
37
0
  dng_vector_3 w1 = Mb * XYtoXYZ (white1);
38
0
  dng_vector_3 w2 = Mb * XYtoXYZ (white2);
39
  
40
  // Negative white coordinates are kind of meaningless.
41
  
42
0
  w1 [0] = Max_real64 (w1 [0], 0.0);
43
0
  w1 [1] = Max_real64 (w1 [1], 0.0);
44
0
  w1 [2] = Max_real64 (w1 [2], 0.0);
45
  
46
0
  w2 [0] = Max_real64 (w2 [0], 0.0);
47
0
  w2 [1] = Max_real64 (w2 [1], 0.0);
48
0
  w2 [2] = Max_real64 (w2 [2], 0.0);
49
50
  // Limit scaling to something reasonable.
51
  
52
0
  dng_matrix_3by3 A;
53
  
54
0
  A [0] [0] = Pin_real64 (0.1, w1 [0] > 0.0 ? w2 [0] / w1 [0] : 10.0, 10.0);
55
0
  A [1] [1] = Pin_real64 (0.1, w1 [1] > 0.0 ? w2 [1] / w1 [1] : 10.0, 10.0);
56
0
  A [2] [2] = Pin_real64 (0.1, w1 [2] > 0.0 ? w2 [2] / w1 [2] : 10.0, 10.0);
57
    
58
0
  dng_matrix_3by3 B = Invert (Mb) * A * Mb;
59
  
60
0
  return B;
61
  
62
0
  }
63
64
/******************************************************************************/
65
66
dng_color_spec::dng_color_spec (const dng_negative &negative,
67
                  const dng_camera_profile *profile)
68
                
69
  : fChannels (negative.ColorChannels ())
70
  
71
  , fTemperature1 (0.0)
72
  , fTemperature2 (0.0)
73
  
74
  , fColorMatrix1 ()
75
  , fColorMatrix2 ()
76
  
77
  , fForwardMatrix1 ()
78
  , fForwardMatrix2 ()
79
  
80
  , fReductionMatrix1 ()
81
  , fReductionMatrix2 ()
82
  
83
  , fCameraCalibration1 ()
84
  , fCameraCalibration2 ()
85
  
86
  , fAnalogBalance ()
87
  
88
  , fWhiteXY ()
89
  
90
  , fCameraWhite ()
91
  , fCameraToPCS ()
92
  
93
  , fPCStoCamera ()
94
  
95
0
  {
96
  
97
0
  if (fChannels > 1)
98
0
    {
99
  
100
0
    if (!profile || !profile->IsValid (fChannels))
101
0
      {
102
0
      ThrowBadFormat ();
103
0
      }
104
      
105
0
    if (profile->WasStubbed ())
106
0
      {
107
0
      ThrowProgramError ("Using stubbed profile");
108
0
      }
109
    
110
0
    fTemperature1 = profile->CalibrationTemperature1 ();
111
0
    fTemperature2 = profile->CalibrationTemperature2 ();
112
    
113
0
    fColorMatrix1 = profile->ColorMatrix1 ();
114
0
    fColorMatrix2 = profile->ColorMatrix2 ();
115
        
116
0
    fForwardMatrix1 = profile->ForwardMatrix1 ();
117
0
    fForwardMatrix2 = profile->ForwardMatrix2 ();
118
        
119
0
    fReductionMatrix1 = profile->ReductionMatrix1 ();
120
0
    fReductionMatrix2 = profile->ReductionMatrix2 ();
121
    
122
0
    fCameraCalibration1.SetIdentity (fChannels);
123
0
    fCameraCalibration2.SetIdentity (fChannels);
124
125
0
    if (negative. CameraCalibrationSignature () ==
126
0
      profile->ProfileCalibrationSignature ())
127
0
      {
128
      
129
0
      if (negative.CameraCalibration1 ().Rows () == fChannels &&
130
0
        negative.CameraCalibration1 ().Cols () == fChannels)
131
0
        {
132
        
133
0
        fCameraCalibration1 = negative.CameraCalibration1 ();
134
        
135
0
        }
136
        
137
0
      if (negative.CameraCalibration2 ().Rows () == fChannels &&
138
0
        negative.CameraCalibration2 ().Cols () == fChannels)
139
0
        {
140
        
141
0
        fCameraCalibration2 = negative.CameraCalibration2 ();
142
        
143
0
        }
144
              
145
0
      }
146
147
0
    fAnalogBalance = dng_matrix (fChannels, fChannels);
148
    
149
0
    for (uint32 j = 0; j < fChannels; j++)
150
0
      {
151
      
152
0
      fAnalogBalance [j] [j] = negative.AnalogBalance (j);
153
      
154
0
      }
155
156
0
    dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix1);
157
    
158
0
    fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1;
159
                
160
0
    if (!profile->HasColorMatrix2 () ||
161
0
        fTemperature1 <= 0.0 ||
162
0
        fTemperature2 <= 0.0 ||
163
0
        fTemperature1 == fTemperature2)
164
0
      {
165
      
166
0
      fTemperature1 = 5000.0;
167
0
      fTemperature2 = 5000.0;
168
      
169
0
      fColorMatrix2       = fColorMatrix1;
170
0
      fForwardMatrix2     = fForwardMatrix1;
171
0
      fReductionMatrix2   = fReductionMatrix1;
172
0
      fCameraCalibration2 = fCameraCalibration1;
173
      
174
0
      }
175
      
176
0
    else
177
0
      {
178
      
179
0
      dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix2);
180
      
181
0
      fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2;
182
      
183
      // Swap values if temperatures are out of order.
184
                      
185
0
      if (fTemperature1 > fTemperature2)
186
0
        {
187
        
188
0
        real64 temp   = fTemperature1;
189
0
        fTemperature1 = fTemperature2;
190
0
        fTemperature2 = temp;
191
        
192
0
        dng_matrix T  = fColorMatrix1;
193
0
        fColorMatrix1 = fColorMatrix2;
194
0
        fColorMatrix2 = T;
195
        
196
0
        T               = fForwardMatrix1;
197
0
        fForwardMatrix1 = fForwardMatrix2;
198
0
        fForwardMatrix2 = T;
199
        
200
0
        T                 = fReductionMatrix1;
201
0
        fReductionMatrix1 = fReductionMatrix2;
202
0
        fReductionMatrix2 = T;
203
        
204
0
        T                   = fCameraCalibration1;
205
0
        fCameraCalibration1 = fCameraCalibration2;
206
0
        fCameraCalibration2 = T;
207
        
208
0
        }
209
        
210
0
      }
211
      
212
0
    }
213
    
214
0
  }
215
216
/*****************************************************************************/
217
218
dng_matrix dng_color_spec::FindXYZtoCamera (const dng_xy_coord &white,
219
                      dng_matrix *forwardMatrix,
220
                          dng_matrix *reductionMatrix,
221
                      dng_matrix *cameraCalibration)
222
0
  {
223
  
224
  // Convert to temperature/offset space.
225
  
226
0
  dng_temperature td (white);
227
  
228
  // Find fraction to weight the first calibration.
229
  
230
0
  real64 g;
231
  
232
0
  if (td.Temperature () <= fTemperature1)
233
0
    g = 1.0;
234
  
235
0
  else if (td.Temperature () >= fTemperature2)
236
0
    g = 0.0;
237
  
238
0
  else
239
0
    {
240
    
241
0
    real64 invT = 1.0 / td.Temperature ();
242
    
243
0
    g = (invT                  - (1.0 / fTemperature2)) /
244
0
        ((1.0 / fTemperature1) - (1.0 / fTemperature2));
245
        
246
0
    }
247
    
248
  // Interpolate the color matrix.
249
  
250
0
  dng_matrix colorMatrix;
251
    
252
0
  if (g >= 1.0)
253
0
    colorMatrix = fColorMatrix1;
254
    
255
0
  else if (g <= 0.0)
256
0
    colorMatrix = fColorMatrix2;
257
    
258
0
  else
259
0
    colorMatrix = (g      ) * fColorMatrix1 +
260
0
            (1.0 - g) * fColorMatrix2;
261
             
262
  // Interpolate forward matrix, if any.
263
  
264
0
  if (forwardMatrix)
265
0
    {
266
           
267
0
    bool has1 = fForwardMatrix1.NotEmpty ();
268
0
    bool has2 = fForwardMatrix2.NotEmpty ();
269
             
270
0
    if (has1 && has2)
271
0
      {
272
      
273
0
      if (g >= 1.0)
274
0
        *forwardMatrix = fForwardMatrix1;
275
      
276
0
      else if (g <= 0.0)
277
0
        *forwardMatrix = fForwardMatrix2;
278
        
279
0
      else
280
0
        *forwardMatrix = (g      ) * fForwardMatrix1 +
281
0
                 (1.0 - g) * fForwardMatrix2;
282
      
283
0
      }
284
      
285
0
    else if (has1)
286
0
      {
287
      
288
0
      *forwardMatrix = fForwardMatrix1;
289
    
290
0
      }
291
      
292
0
    else if (has2)
293
0
      {
294
      
295
0
      *forwardMatrix = fForwardMatrix2;
296
    
297
0
      }
298
      
299
0
    else
300
0
      {
301
      
302
0
      forwardMatrix->Clear ();
303
      
304
0
      }
305
      
306
0
    }
307
      
308
  // Interpolate reduction matrix, if any.
309
  
310
0
  if (reductionMatrix)
311
0
    {
312
           
313
0
    bool has1 = fReductionMatrix1.NotEmpty ();
314
0
    bool has2 = fReductionMatrix2.NotEmpty ();
315
             
316
0
    if (has1 && has2)
317
0
      {
318
      
319
0
      if (g >= 1.0)
320
0
        *reductionMatrix = fReductionMatrix1;
321
      
322
0
      else if (g <= 0.0)
323
0
        *reductionMatrix = fReductionMatrix2;
324
        
325
0
      else
326
0
        *reductionMatrix = (g      ) * fReductionMatrix1 +
327
0
                   (1.0 - g) * fReductionMatrix2;
328
      
329
0
      }
330
      
331
0
    else if (has1)
332
0
      {
333
      
334
0
      *reductionMatrix = fReductionMatrix1;
335
    
336
0
      }
337
      
338
0
    else if (has2)
339
0
      {
340
      
341
0
      *reductionMatrix = fReductionMatrix2;
342
    
343
0
      }
344
      
345
0
    else
346
0
      {
347
      
348
0
      reductionMatrix->Clear ();
349
      
350
0
      }
351
      
352
0
    }
353
      
354
  // Interpolate camera calibration matrix.
355
  
356
0
  if (cameraCalibration)
357
0
    {
358
           
359
0
    if (g >= 1.0)
360
0
      *cameraCalibration = fCameraCalibration1;
361
    
362
0
    else if (g <= 0.0)
363
0
      *cameraCalibration = fCameraCalibration2;
364
      
365
0
    else
366
0
      *cameraCalibration = (g      ) * fCameraCalibration1 +
367
0
                   (1.0 - g) * fCameraCalibration2;
368
            
369
0
    }
370
      
371
  // Return the interpolated color matrix.
372
    
373
0
  return colorMatrix;
374
    
375
0
  }
376
377
/*****************************************************************************/
378
379
void dng_color_spec::SetWhiteXY (const dng_xy_coord &white)
380
0
  {
381
  
382
0
  fWhiteXY = white;
383
  
384
  // Deal with monochrome cameras.
385
  
386
0
  if (fChannels == 1)
387
0
    {
388
    
389
0
    fCameraWhite.SetIdentity (1);
390
    
391
0
    fCameraToPCS = PCStoXYZ ().AsColumn ();
392
    
393
0
    return;
394
    
395
0
    }
396
  
397
  // Interpolate an matric values for this white point.
398
  
399
0
  dng_matrix colorMatrix;
400
0
  dng_matrix forwardMatrix;
401
0
  dng_matrix reductionMatrix;
402
0
  dng_matrix cameraCalibration;
403
  
404
0
  colorMatrix = FindXYZtoCamera (fWhiteXY,
405
0
                   &forwardMatrix,
406
0
                   &reductionMatrix,
407
0
                   &cameraCalibration);
408
                   
409
  // Find the camera white values.
410
  
411
0
  fCameraWhite = colorMatrix * XYtoXYZ (fWhiteXY);
412
413
0
  real64 cameraWhiteMaxEntry = MaxEntry (fCameraWhite);
414
0
  if (cameraWhiteMaxEntry == 0)
415
0
    {
416
0
     ThrowBadFormat ();
417
0
    }
418
0
  real64 whiteScale = 1.0 / cameraWhiteMaxEntry;
419
  
420
0
  for (uint32 j = 0; j < fChannels; j++)
421
0
    {
422
    
423
    // We don't support non-positive values for camera neutral values.
424
    
425
0
    fCameraWhite [j] = Pin_real64 (0.001,
426
0
                     whiteScale * fCameraWhite [j], 
427
0
                     1.0);
428
    
429
0
    }
430
    
431
  // Find PCS to Camera transform. Scale matrix so PCS white can just be
432
  // reached when the first camera channel saturates
433
  
434
0
  fPCStoCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY);
435
    
436
0
  real64 scale = MaxEntry (fPCStoCamera * PCStoXYZ ());
437
438
0
  if (scale == 0)
439
0
    {
440
0
     ThrowBadFormat ();
441
0
    }
442
0
  fPCStoCamera = (1.0 / scale) * fPCStoCamera;
443
444
  // If we have a forward matrix, then just use that.
445
  
446
0
  if (forwardMatrix.NotEmpty ())
447
0
    {
448
    
449
0
    dng_matrix individualToReference = Invert (fAnalogBalance * cameraCalibration);
450
    
451
0
    dng_vector refCameraWhite = individualToReference * fCameraWhite;
452
    
453
0
    fCameraToPCS = forwardMatrix *
454
0
             Invert (refCameraWhite.AsDiagonal ()) *
455
0
             individualToReference;
456
    
457
0
    }
458
    
459
  // Else we need to use the adapt in XYZ method.
460
  
461
0
  else
462
0
    {
463
464
    // Invert this PCS to camera matrix.  Note that if there are more than three
465
    // camera channels, this inversion is non-unique.
466
    
467
0
    fCameraToPCS = Invert (fPCStoCamera, reductionMatrix);
468
    
469
0
    }
470
  
471
0
  }
472
473
/*****************************************************************************/
474
475
const dng_xy_coord & dng_color_spec::WhiteXY () const
476
0
  {
477
  
478
0
  DNG_ASSERT (fWhiteXY.IsValid (), "Using invalid WhiteXY");
479
  
480
0
  return fWhiteXY;
481
482
0
  }
483
484
/*****************************************************************************/
485
486
const dng_vector & dng_color_spec::CameraWhite () const
487
0
  {
488
  
489
0
  DNG_ASSERT (fCameraWhite.NotEmpty (), "Using invalid CameraWhite");
490
  
491
0
  return fCameraWhite;
492
  
493
0
  }
494
495
/*****************************************************************************/
496
497
const dng_matrix & dng_color_spec::CameraToPCS () const
498
0
  {
499
  
500
0
  DNG_ASSERT (fCameraToPCS.NotEmpty (), "Using invalid CameraToPCS");
501
  
502
0
  return fCameraToPCS;
503
  
504
0
  }
505
506
/*****************************************************************************/
507
508
const dng_matrix & dng_color_spec::PCStoCamera () const
509
0
  {
510
  
511
0
  DNG_ASSERT (fPCStoCamera.NotEmpty (), "Using invalid PCStoCamera");
512
  
513
0
  return fPCStoCamera;
514
  
515
0
  }
516
517
/*****************************************************************************/
518
519
dng_xy_coord dng_color_spec::NeutralToXY (const dng_vector &neutral)
520
0
  {
521
  
522
0
  const uint32 kMaxPasses = 30;
523
  
524
0
  if (fChannels == 1)
525
0
    {
526
    
527
0
    return PCStoXY ();
528
    
529
0
    }
530
  
531
0
  dng_xy_coord last = D50_xy_coord ();
532
  
533
0
  for (uint32 pass = 0; pass < kMaxPasses; pass++)
534
0
    {
535
    
536
0
    dng_matrix xyzToCamera = FindXYZtoCamera (last);
537
    
538
0
    dng_xy_coord next = XYZtoXY (Invert (xyzToCamera) * neutral);
539
    
540
0
    if (Abs_real64 (next.x - last.x) +
541
0
      Abs_real64 (next.y - last.y) < 0.0000001)
542
0
      {
543
      
544
0
      return next;
545
      
546
0
      }
547
      
548
    // If we reach the limit without converging, we are most likely
549
    // in a two value oscillation.  So take the average of the last
550
    // two estimates and give up.
551
      
552
0
    if (pass == kMaxPasses - 1)
553
0
      {
554
      
555
0
      next.x = (last.x + next.x) * 0.5;
556
0
      next.y = (last.y + next.y) * 0.5;
557
      
558
0
      }
559
      
560
0
    last = next;
561
    
562
0
    }
563
    
564
0
  return last;
565
  
566
0
  }
567
      
568
/*****************************************************************************/