bool dng_camera_profile::ValidForwardMatrix (const dng_matrix &m) { const real64 kThreshold = 0.01; if (m.NotEmpty ()) { dng_vector cameraOne; cameraOne.SetIdentity (m.Cols ()); dng_vector xyz = m * cameraOne; dng_vector pcs = PCStoXYZ (); if (Abs_real64 (xyz [0] - pcs [0]) > kThreshold || Abs_real64 (xyz [1] - pcs [1]) > kThreshold || Abs_real64 (xyz [2] - pcs [2]) > kThreshold) { return false; } } return true; }
dng_xy_coord dng_color_spec::NeutralToXY (const dng_vector &neutral) { const uint32 kMaxPasses = 30; if (fChannels == 1) { return PCStoXY (); } dng_xy_coord last = D50_xy_coord (); for (uint32 pass = 0; pass < kMaxPasses; pass++) { dng_matrix xyzToCamera = FindXYZtoCamera (last); dng_xy_coord next = XYZtoXY (Invert (xyzToCamera) * neutral); if (Abs_real64 (next.x - last.x) + Abs_real64 (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; }
void dng_srational::Set_real64 (real64 x, int32 dd) { if (x == 0.0) { *this = dng_srational (0, 1); } if (dd == 0) { real64 y = Abs_real64 (x); if (y >= 32768.0) { dd = 1; } else if (y >= 1.0) { dd = 32768; } else { dd = 32768 * 32768; } } *this = dng_srational (Round_int32 (x * dd), dd); }
static dng_matrix Invert3by3 (const dng_matrix &A) { real64 a00 = A [0] [0]; real64 a01 = A [0] [1]; real64 a02 = A [0] [2]; real64 a10 = A [1] [0]; real64 a11 = A [1] [1]; real64 a12 = A [1] [2]; real64 a20 = A [2] [0]; real64 a21 = A [2] [1]; real64 a22 = A [2] [2]; real64 temp [3] [3]; temp [0] [0] = a11 * a22 - a21 * a12; temp [0] [1] = a21 * a02 - a01 * a22; temp [0] [2] = a01 * a12 - a11 * a02; temp [1] [0] = a20 * a12 - a10 * a22; temp [1] [1] = a00 * a22 - a20 * a02; temp [1] [2] = a10 * a02 - a00 * a12; temp [2] [0] = a10 * a21 - a20 * a11; temp [2] [1] = a20 * a01 - a00 * a21; temp [2] [2] = a00 * a11 - a10 * a01; real64 det = (a00 * temp [0] [0] + a01 * temp [1] [0] + a02 * temp [2] [0]); if (Abs_real64 (det) < kNearZero) { ThrowMatrixMath (); } dng_matrix B (3, 3); for (uint32 j = 0; j < 3; j++) for (uint32 k = 0; k < 3; k++) { B [j] [k] = temp [j] [k] / det; } return B; }
real64 dng_1d_function::EvaluateInverse (real64 y) const { const uint32 kMaxIterations = 30; const real64 kNearZero = 1.0e-10; real64 x0 = 0.0; real64 y0 = Evaluate (x0); real64 x1 = 1.0; real64 y1 = Evaluate (x1); for (uint32 iteration = 0; iteration < kMaxIterations; iteration++) { if (Abs_real64 (y1 - y0) < kNearZero) { break; } real64 x2 = Pin_real64 (0.0, x1 + (y - y1) * (x1 - x0) / (y1 - y0), 1.0); real64 y2 = Evaluate (x2); x0 = x1; y0 = y1; x1 = x2; y1 = y2; } return x1; }
static dng_matrix InvertNbyN (const dng_matrix &A) { uint32 i; uint32 j; uint32 k; uint32 n = A.Rows (); real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2]; for (i = 0; i < n; i++) for (j = 0; j < n; j++) { temp [i] [j ] = A [i] [j]; temp [i] [j + n] = (i == j ? 1.0 : 0.0); } for (i = 0; i < n; i++) { real64 alpha = temp [i] [i]; if (Abs_real64 (alpha) < kNearZero) { ThrowMatrixMath (); } for (j = 0; j < n * 2; j++) { temp [i] [j] /= alpha; } for (k = 0; k < n; k++) { if (i != k) { real64 beta = temp [k] [i]; for (j = 0; j < n * 2; j++) { temp [k] [j] -= beta * temp [i] [j]; } } } } dng_matrix B (n, n); for (i = 0; i < n; i++) for (j = 0; j < n; j++) { B [i] [j] = temp [i] [j + n]; } return B; }
void dng_shared::PostParse (dng_host & /* host */, dng_exif & /* exif */) { // Fill in default values for DNG images. if (fDNGVersion != 0) { // Support for DNG versions before 1.0.0.0. if (fDNGVersion < dngVersion_1_0_0_0) { #if qDNGValidate ReportWarning ("DNGVersion less than 1.0.0.0"); #endif // The CalibrationIlluminant tags were added just before // DNG version 1.0.0.0, and were hardcoded before that. fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA; fCameraProfile.fCalibrationIlluminant2 = lsD65; fDNGVersion = dngVersion_1_0_0_0; } // Default value for DNGBackwardVersion tag. if (fDNGBackwardVersion == 0) { fDNGBackwardVersion = fDNGVersion & 0xFFFF0000; } // Check DNGBackwardVersion value. if (fDNGBackwardVersion < dngVersion_1_0_0_0) { #if qDNGValidate ReportWarning ("DNGBackwardVersion less than 1.0.0.0"); #endif fDNGBackwardVersion = dngVersion_1_0_0_0; } if (fDNGBackwardVersion > fDNGVersion) { #if qDNGValidate ReportWarning ("DNGBackwardVersion > DNGVersion"); #endif fDNGBackwardVersion = fDNGVersion; } // Check UniqueCameraModel. if (fUniqueCameraModel.IsEmpty ()) { #if qDNGValidate ReportWarning ("Missing or invalid UniqueCameraModel"); #endif fUniqueCameraModel.Set ("Digital Negative"); } // If we don't know the color depth yet, it must be a monochrome DNG. if (fCameraProfile.fColorPlanes == 0) { fCameraProfile.fColorPlanes = 1; } // Check color info. if (fCameraProfile.fColorPlanes > 1) { // Check illuminant pair. if (fCameraProfile.fColorMatrix2.NotEmpty ()) { if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown || (fCameraProfile.fCalibrationIlluminant2 == lsUnknown || (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2))) { #if qDNGValidate ReportWarning ("Invalid CalibrationIlluminant pair"); #endif fCameraProfile.fColorMatrix2 = dng_matrix (); } } // If the colorimetric reference is the ICC profile PCS, then the // data must already be white balanced. The "AsShotWhiteXY" is required // to be the ICC Profile PCS white point. if (fColorimetricReference == crICCProfilePCS) { if (fAsShotNeutral.NotEmpty ()) { #if qDNGValidate ReportWarning ("AsShotNeutral not allowed for this " "ColorimetricReference value"); #endif fAsShotNeutral.Clear (); } dng_xy_coord pcs = PCStoXY (); #if qDNGValidate if (fAsShotWhiteXY.IsValid ()) { if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 || Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01) { ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS"); } } #endif fAsShotWhiteXY = pcs; } else { // Warn if both AsShotNeutral and AsShotWhiteXY are specified. if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ()) { #if qDNGValidate ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included"); #endif fAsShotWhiteXY = dng_xy_coord (); } // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified. #if qDNGValidate if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ()) { ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included", "legal but not recommended"); } #endif } // Default values of calibration signatures are required for legacy // compatiblity. if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA && fCameraProfile.fCalibrationIlluminant2 == lsD65 && fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes && fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes && fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes && fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes && fCameraCalibrationSignature.IsEmpty () && fCameraProfile.fProfileCalibrationSignature.IsEmpty () ) { fCameraCalibrationSignature.Set (kAdobeCalibrationSignature); fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature); } } // Check BaselineNoise. if (fBaselineNoise.As_real64 () <= 0.0) { #if qDNGValidate ReportWarning ("Invalid BaselineNoise"); #endif fBaselineNoise = dng_urational (1, 1); } // Check BaselineSharpness. if (fBaselineSharpness.As_real64 () <= 0.0) { #if qDNGValidate ReportWarning ("Invalid BaselineSharpness"); #endif fBaselineSharpness = dng_urational (1, 1); } // Check NoiseProfile. if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0) { #if qDNGValidate ReportWarning ("Invalid NoiseProfile"); #endif fNoiseProfile = dng_noise_profile (); } // Check LinearResponseLimit. if (fLinearResponseLimit.As_real64 () < 0.5 || fLinearResponseLimit.As_real64 () > 1.0) { #if qDNGValidate ReportWarning ("Invalid LinearResponseLimit"); #endif fLinearResponseLimit = dng_urational (1, 1); } // Check ShadowScale. if (fShadowScale.As_real64 () <= 0.0) { #if qDNGValidate ReportWarning ("Invalid ShadowScale"); #endif fShadowScale = dng_urational (1, 1); } } }