diff --git a/tools/RTProfileBuilderSample.cs b/tools/RTProfileBuilderSample.cs index 9b110c325..0573df459 100644 --- a/tools/RTProfileBuilderSample.cs +++ b/tools/RTProfileBuilderSample.cs @@ -9,8 +9,9 @@ using System.Collections; using System.Collections.Specialized; #endregion -// Raw Therapee sample Custom Profile builder (version 2010-11-08) +// *** Raw Therapee sample Custom Profile builder (version 2010-11-15) *** // WARNING: PP3 format may change in the future versions! If this happens there will probably be no automatic migration path, you'll have to adjust on your own. +// This is a sample, and therefore not supported by the RT team (just by oduis) // // How to use: // 1. Modify the GetCorrectedSettings function below according to your needs. @@ -18,7 +19,15 @@ using System.Collections.Specialized; // You can get it for free via Windows Update or from microsoft.com. No need for Visual Studio etc. // 3. Open a command line and compile this CS-File using the C# 32bit compiler. It is usually installed somewhere here: // C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe -// Call csc.exe with your .CS file as parameter. CSC will compile it and emit an EXE. +// Call csc.exe (C#-Compiler) with your .CS file as parameter like this (one big line): +// +// C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc +// /r:C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll +// /r:C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Configuration.dll +// RTProfileBuilderSample.cs +// +// (On most machines it already works with "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc RTProfileBuilderSample.cs") +// CSC will compile it and emit an EXE. // 4. Open your RT options files and find the entry [Profiles]/CustomProfileBuilder // 5. Enter the path to your newly built exe here. On Windows, don't forget double slashes (e.g. "C:\\MyDir\\Mybuilder.exe") // And you're done! The EXE is only called on opening the image editor and there is no PP3 already @@ -37,6 +46,16 @@ namespace RTProfilerBuilder { /// Main class. Mostly change GetCorrectedSettings. class RTProfileBuilder { + /// Adds the Nikkor zoom distortion correction profile. + /// First array is list of focal lengths, second array is the RT setting that should correct the + /// distortion for the corresponding focal length. Values between these values are automatically interpolated. + /// The focal length values must already be ordered. The number of sample points is not limited. + static DistortionCorrectProf distNikkor24120f4 = new DistortionCorrectProf( + new double[] { 24, 28, 35, 50, 70, 85, 120 }, + new double[] { -0.1, -0.063, -0.012, 0.018, 0.034, 0.04, 0.048 } + ); + + /// This is your personalisation function /// Full EXIF from EXIFTOOL (if configured). /// Entry, like "Sharpening/Radius" @@ -46,12 +65,12 @@ namespace RTProfilerBuilder { /// Lens from EXIFCamera from EXIF /// The value to be written. Simply take the current value if you have nothing to touch. static string GetCorrectedSetting(NameValueCollection exif, string sectionEntry, string value, - float fNumber, float exposureSecs, float focalLength, long iso, string lens, string camera) { + double fNumber, double exposureSecs, double focalLength, long iso, string lens, string camera) { string s; // We don't do anything to the value if it's not our camera - if (camera.EndsWith("NIKON D700", StringComparison.InvariantCultureIgnoreCase) && lens.Contains("24.0-120.0")) { + if (camera.EndsWith("NIKON D700", StringComparison.InvariantCultureIgnoreCase) && lens.Contains("24.0-120.0 mm f/4.0")) { switch (sectionEntry) { // Here is the place to adjust your settings // Pretty simple: "SectionName/EntryName" in options file @@ -76,6 +95,11 @@ namespace RTProfilerBuilder { if (iso >= 6400) value = "0"; // Colors will get poppy anyway... break; + case "Distortion/Amount": + // we already checked in the IF upstairs that this is "our" lens + value = distNikkor24120f4.GetDistortionAmount(focalLength); + break; + // Add other parameters here. Mention this is case sensitive! default: break; // we don't touch values we don't care about @@ -130,9 +154,9 @@ namespace RTProfilerBuilder { string defaultProfileFilePath = args[argNo++]; // Note that old C++ has no automatic number globalization - float fNumber = float.Parse(args[argNo++], CultureInfo.InvariantCulture); - float exposureSecs = float.Parse(args[argNo++], CultureInfo.InvariantCulture); - float focalLength = float.Parse(args[argNo++], CultureInfo.InvariantCulture); + double fNumber = double.Parse(args[argNo++], CultureInfo.InvariantCulture); + double exposureSecs = double.Parse(args[argNo++], CultureInfo.InvariantCulture); + double focalLength = double.Parse(args[argNo++], CultureInfo.InvariantCulture); long iso = long.Parse(args[argNo++], CultureInfo.InvariantCulture); string lens = args[argNo++]; @@ -209,4 +233,43 @@ namespace RTProfilerBuilder { #endregion } + + #region DistortionCorrectProf + /// Holds a distortion correction profile for one lens. Uses sample points (focal length vs. dist. correction) as input. + class DistortionCorrectProf { + double[] adFocLen, adCorrect; + + /// Parses array to internal structure + /// Focal lengths + /// Correction factors + public DistortionCorrectProf(double[] focLen, double[] correct) { + if (focLen == null || correct == null || focLen.Length != correct.Length || focLen.Length < 2) + throw new Exception("DistortionCorrectProf inputs must be valid and of the same lenghts, at least 2 points"); + + adFocLen = focLen; adCorrect = correct; + + for (int i = 0; i < adFocLen.Length - 1; i++) + if (adFocLen[i] >= adFocLen[i + 1]) throw new Exception("The distortion correction focal length points must be ordered!"); + } + + /// Calculates regession value of RT distortion amount for the given focal length. + /// Input focal length. + /// Distortion in RT format. + public string GetDistortionAmount(double focalLength) { + // if it's out of area (which should just happing with e.g. rounding errors), return flat defaults. + if (focalLength <= adFocLen[0]) return adCorrect[0].ToString("G", CultureInfo.InvariantCulture); + if (focalLength >= adFocLen[adFocLen.Length - 1]) return adCorrect[adFocLen.Length - 1].ToString("G", CultureInfo.InvariantCulture); + + for (int i = 0; i < adFocLen.Length - 1; i++) { + if (focalLength >= adFocLen[i] && focalLength < adFocLen[i + 1]) { + // from the sample curves taken so far, it it safe to take a simple linear interpolation here + double corr = adCorrect[i] + (adCorrect[i + 1] - adCorrect[i]) * (focalLength - adFocLen[i]) / (adFocLen[i + 1] - adFocLen[i]); + return corr.ToString("G3", CultureInfo.InvariantCulture); + } + } + + return ""; // should never happen + } + } + #endregion }