/// Return the XY value to use for SetWhiteXY for a given camera color /// space coordinate as the white point. /// \param neutral A camera color space value to use for white point. /// Components range from 0.0 to 1.0 and should be normalized such that /// the largest value is 1.0 . /// \retval White point in XY space that makes neutral map to this /// XY value as closely as possible. public DNGxyCoord NeutralToXY(DNGVector neutral) { const uint kMaxPasses = 30; if (fChannels == 1) { return(DNGxyCoord.PCStoXY); } DNGxyCoord last = DNGxyCoord.D50; for (uint pass = 0; pass < kMaxPasses; pass++) { DNGMatrix nullMat = null; DNGMatrix xyzToCamera = FindXYZtoCamera(last, ref nullMat, ref nullMat, ref nullMat); DNGMatrix inv = xyzToCamera.Invert(); DNGVector vec = inv * neutral; DNGVector3 vec3 = new DNGVector3(vec); DNGxyCoord next = DNGxyCoord.XYZtoXY(new DNGVector3(xyzToCamera.Invert() * neutral)); if (Math.Abs(next.X - last.X) + Math.Abs(next.Y - last.Y) < 0.0000001) { return(next); } // If we reach the limit without converging, we are most likely // in a two value oscillation. So take the average of the last // two estimates and give up. if (pass == kMaxPasses - 1) { next.X = (last.X + next.X) * 0.5; next.Y = (last.Y + next.Y) * 0.5; } last = next; } return(last); }
public DNGColorSpace(DNGMatrix3x3 toPCS) { // The matrix values are often rounded, so adjust to // get them to convert device white exactly to the PCS. DNGVector W1 = toPCS * new DNGVector3(1.0, 1.0, 1.0); DNGVector W2 = DNGxyCoord.PCStoXYZ; double s0 = W2[0] / W1[0]; double s1 = W2[1] / W1[1]; double s2 = W2[2] / W1[2]; DNGMatrix3x3 S = new DNGMatrix3x3(s0, 0, 0, 0, s1, 0, 0, 0, s2); mToPCS = S * toPCS; // Find reverse matrix. mFromPCS = mToPCS.Invert(); }