public static DNGxyCoord XYZtoXY(DNGVector3 coord) { double X = coord[0]; double Y = coord[1]; double Z = coord[2]; double total = X + Y + Z; if (total > 0.0) { return(new DNGxyCoord(X / total, Y / total)); } return(DNGxyCoord.D50); }
/// 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); }