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
}