LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkColorLookUpTable.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 74 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkColorLookUpTable.h"
       9             : #include "SkColorSpaceXformPriv.h"
      10             : #include "SkFloatingPoint.h"
      11             : 
      12           0 : void SkColorLookUpTable::interp(float* dst, const float* src) const {
      13           0 :     if (fInputChannels == 3) {
      14           0 :         interp3D(dst, src);
      15             :     } else {
      16           0 :         SkASSERT(dst != src);
      17             :         // index gets initialized as the algorithm proceeds by interpDimension.
      18             :         // It's just there to store the choice of low/high so far.
      19             :         int index[kMaxColorChannels];
      20           0 :         for (uint8_t outputDimension = 0; outputDimension < kOutputChannels; ++outputDimension) {
      21           0 :             dst[outputDimension] = interpDimension(src, fInputChannels - 1, outputDimension,
      22             :                                                    index);
      23             :         }
      24             :     }
      25           0 : }
      26             : 
      27           0 : void SkColorLookUpTable::interp3D(float* dst, const float* src) const {
      28             :     SkASSERT(3 == kOutputChannels);
      29             :     // Call the src components x, y, and z.
      30           0 :     const uint8_t maxX = fGridPoints[0] - 1;
      31           0 :     const uint8_t maxY = fGridPoints[1] - 1;
      32           0 :     const uint8_t maxZ = fGridPoints[2] - 1;
      33             : 
      34             :     // An approximate index into each of the three dimensions of the table.
      35           0 :     const float x = src[0] * maxX;
      36           0 :     const float y = src[1] * maxY;
      37           0 :     const float z = src[2] * maxZ;
      38             : 
      39             :     // This gives us the low index for our interpolation.
      40           0 :     int ix = sk_float_floor2int(x);
      41           0 :     int iy = sk_float_floor2int(y);
      42           0 :     int iz = sk_float_floor2int(z);
      43             : 
      44             :     // Make sure the low index is not also the max index.
      45           0 :     ix = (maxX == ix) ? ix - 1 : ix;
      46           0 :     iy = (maxY == iy) ? iy - 1 : iy;
      47           0 :     iz = (maxZ == iz) ? iz - 1 : iz;
      48             : 
      49             :     // Weighting factors for the interpolation.
      50           0 :     const float diffX = x - ix;
      51           0 :     const float diffY = y - iy;
      52           0 :     const float diffZ = z - iz;
      53             : 
      54             :     // Constants to help us navigate the 3D table.
      55             :     // Ex: Assume x = a, y = b, z = c.
      56             :     //     table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c].
      57           0 :     const int n000 = 0;
      58           0 :     const int n001 = 3 * fGridPoints[1] * fGridPoints[2];
      59           0 :     const int n010 = 3 * fGridPoints[2];
      60           0 :     const int n011 = n001 + n010;
      61           0 :     const int n100 = 3;
      62           0 :     const int n101 = n100 + n001;
      63           0 :     const int n110 = n100 + n010;
      64           0 :     const int n111 = n110 + n001;
      65             : 
      66             :     // Base ptr into the table.
      67           0 :     const float* ptr = &(table()[ix*n001 + iy*n010 + iz*n100]);
      68             : 
      69             :     // The code below performs a tetrahedral interpolation for each of the three
      70             :     // dst components.  Once the tetrahedron containing the interpolation point is
      71             :     // identified, the interpolation is a weighted sum of grid values at the
      72             :     // vertices of the tetrahedron.  The claim is that tetrahedral interpolation
      73             :     // provides a more accurate color conversion.
      74             :     // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/
      75             :     //
      76             :     // I have one test image, and visually I can't tell the difference between
      77             :     // tetrahedral and trilinear interpolation.  In terms of computation, the
      78             :     // tetrahedral code requires more branches but less computation.  The
      79             :     // SampleICC library provides an option for the client to choose either
      80             :     // tetrahedral or trilinear.
      81           0 :     for (int i = 0; i < 3; i++) {
      82           0 :         if (diffZ < diffY) {
      83           0 :             if (diffZ > diffX) {
      84           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) +
      85           0 :                                       diffY * (ptr[n010] - ptr[n000]) +
      86           0 :                                       diffX * (ptr[n111] - ptr[n110]));
      87           0 :             } else if (diffY < diffX) {
      88           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
      89           0 :                                       diffY * (ptr[n011] - ptr[n001]) +
      90           0 :                                       diffX * (ptr[n001] - ptr[n000]));
      91             :             } else {
      92           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) +
      93           0 :                                       diffY * (ptr[n010] - ptr[n000]) +
      94           0 :                                       diffX * (ptr[n011] - ptr[n010]));
      95             :             }
      96             :         } else {
      97           0 :             if (diffZ < diffX) {
      98           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) +
      99           0 :                                       diffY * (ptr[n111] - ptr[n101]) +
     100           0 :                                       diffX * (ptr[n001] - ptr[n000]));
     101           0 :             } else if (diffY < diffX) {
     102           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
     103           0 :                                       diffY * (ptr[n111] - ptr[n101]) +
     104           0 :                                       diffX * (ptr[n101] - ptr[n100]));
     105             :             } else {
     106           0 :                 dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) +
     107           0 :                                       diffY * (ptr[n110] - ptr[n100]) +
     108           0 :                                       diffX * (ptr[n111] - ptr[n110]));
     109             :             }
     110             :         }
     111             : 
     112             :         // |src| is guaranteed to be in the 0-1 range as are all entries
     113             :         // in the table.  For "increasing" tables, outputs will also be
     114             :         // in the 0-1 range.  While this property is logical for color
     115             :         // look up tables, we don't check for it.
     116             :         // And for arbitrary, non-increasing tables, it is easy to see how
     117             :         // the output might not be 0-1.  So we clamp here.
     118           0 :         dst[i] = clamp_0_1(dst[i]);
     119             : 
     120             :         // Increment the table ptr in order to handle the next component.
     121             :         // Note that this is the how table is designed: all of nXXX
     122             :         // variables are multiples of 3 because there are 3 output
     123             :         // components.
     124           0 :         ptr++;
     125             :     }
     126           0 : }
     127             : 
     128           0 : float SkColorLookUpTable::interpDimension(const float* src, int inputDimension,
     129             :                                           int outputDimension,
     130             :                                           int index[kMaxColorChannels]) const {
     131             :     // Base case. We've already decided whether to use the low or high point for each dimension
     132             :     // which is stored inside of index[] where index[i] gives the point in the CLUT to use for
     133             :     // input dimension i.
     134           0 :     if (inputDimension < 0) {
     135             :         // compute index into CLUT and look up the colour
     136           0 :         int outputIndex = outputDimension;
     137           0 :         int indexMultiplier = kOutputChannels;
     138           0 :         for (int i = fInputChannels - 1; i >= 0; --i) {
     139           0 :             outputIndex += index[i] * indexMultiplier;
     140           0 :             indexMultiplier *= fGridPoints[i];
     141             :         }
     142           0 :         return table()[outputIndex];
     143             :     }
     144             :     // for each dimension (input channel), try both the low and high point for it
     145             :     // and then do the same recursively for the later dimensions.
     146             :     // Finally, we need to LERP the results. ie LERP X then LERP Y then LERP Z.
     147           0 :     const float x = src[inputDimension] * (fGridPoints[inputDimension] - 1);
     148             :     // try the low point for this dimension
     149           0 :     index[inputDimension] = sk_float_floor2int(x);
     150           0 :     const float diff = x - index[inputDimension];
     151             :     // and recursively LERP all sub-dimensions with the current dimension fixed to the low point
     152           0 :     const float lo = interpDimension(src, inputDimension - 1, outputDimension, index);
     153             :     // now try the high point for this dimension
     154           0 :     index[inputDimension] = sk_float_ceil2int(x);
     155             :     // and recursively LERP all sub-dimensions with the current dimension fixed to the high point
     156           0 :     const float hi = interpDimension(src, inputDimension - 1, outputDimension, index);
     157             :     // then LERP the results based on the current dimension
     158           0 :     return clamp_0_1((1 - diff) * lo + diff * hi);
     159             : }

Generated by: LCOV version 1.13