diff --git a/Filters/ConvolveFilter.cs b/Filters/ConvolveFilter.cs
index 13cab78..62a5fb0 100644
--- a/Filters/ConvolveFilter.cs
+++ b/Filters/ConvolveFilter.cs
@@ -396,4 +396,129 @@ public static bool NearColors(int rgb1, int rgb2, int tolerance) {
return Math.Abs(r1 - r2) <= tolerance && Math.Abs(g1 - g2) <= tolerance && Math.Abs(b1 - b2) <= tolerance;
}
}
+
+ public class ImageMath {
+ /**
+ * Clamp a value to an interval.
+ * @param a the lower clamp threshold
+ * @param b the upper clamp threshold
+ * @param x the input parameter
+ * @return the clamped value
+ */
+
+ public static float Clamp(float x, float a, float b) {
+ return (x < a) ? a : (x > b) ? b : x;
+ }
+
+ /**
+ * Clamp a value to an interval.
+ * @param a the lower clamp threshold
+ * @param b the upper clamp threshold
+ * @param x the input parameter
+ * @return the clamped value
+ */
+
+ public static int Clamp(int x, int a, int b) {
+ return (x < a) ? a : (x > b) ? b : x;
+ }
+
+
+
+ // Catmull-Rom splines
+ private static float m00 = -0.5f;
+ private static float m01 = 1.5f;
+ private static float m02 = -1.5f;
+ private static float m03 = 0.5f;
+ private static float m10 = 1.0f;
+ private static float m11 = -2.5f;
+ private static float m12 = 2.0f;
+ private static float m13 = -0.5f;
+ private static float m20 = -0.5f;
+ private static float m21 = 0.0f;
+ private static float m22 = 0.5f;
+ private static float m23 = 0.0f;
+ private static float m30 = 0.0f;
+ private static float m31 = 1.0f;
+ private static float m32 = 0.0f;
+ private static float m33 = 0.0f;
+
+ /**
+ * Compute a Catmull-Rom spline.
+ * @param x the input parameter
+ * @param numKnots the number of knots in the spline
+ * @param knots the array of knots
+ * @return the spline value
+ */
+
+ public static float spline(float x, int numKnots, float[] knots) {
+ int span;
+ int numSpans = numKnots - 3;
+ float k0, k1, k2, k3;
+ float c0, c1, c2, c3;
+
+ if (numSpans < 1)
+ throw new ArgumentException("Too few knots in spline");
+
+ x = Clamp(x, 0, 1)*numSpans;
+ span = (int)x;
+ if (span > numKnots - 4)
+ span = numKnots - 4;
+ x -= span;
+
+ k0 = knots[span];
+ k1 = knots[span + 1];
+ k2 = knots[span + 2];
+ k3 = knots[span + 3];
+
+ c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
+ c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
+ c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
+ c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;
+
+ return ((c3*x + c2)*x + c1)*x + c0;
+ }
+
+ /**
+ * Compute a Catmull-Rom spline, but with variable knot spacing.
+ * @param x the input parameter
+ * @param numKnots the number of knots in the spline
+ * @param xknots the array of knot x values
+ * @param yknots the array of knot y values
+ * @return the spline value
+ */
+
+ public static float spline(float x, int numKnots, int[] xknots, int[] yknots) {
+ int span;
+ int numSpans = numKnots - 3;
+ float k0, k1, k2, k3;
+ float c0, c1, c2, c3;
+
+ if (numSpans < 1)
+ throw new ArgumentException("Too few knots in spline");
+
+ for (span = 0; span < numSpans; span++)
+ if (xknots[span + 1] > x)
+ break;
+ if (span > numKnots - 3)
+ span = numKnots - 3;
+ float t = (float)(x - xknots[span])/(xknots[span + 1] - xknots[span]);
+ span--;
+ if (span < 0) {
+ span = 0;
+ t = 0;
+ }
+
+ k0 = yknots[span];
+ k1 = yknots[span + 1];
+ k2 = yknots[span + 2];
+ k3 = yknots[span + 3];
+
+ c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
+ c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
+ c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
+ c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;
+
+ return ((c3*t + c2)*t + c1)*t + c0;
+ }
+ }
}
diff --git a/Filters/Curve.cs b/Filters/Curve.cs
new file mode 100644
index 0000000..e46d24a
--- /dev/null
+++ b/Filters/Curve.cs
@@ -0,0 +1,127 @@
+#region License and copyright notice
+/*
+ * Ported to .NET for use in Kaliko.ImageLibrary by Fredrik Schultz 2015
+ *
+ * Original License:
+ * Copyright 2006 Jerry Huxtable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+#endregion
+
+namespace Kaliko.ImageLibrary.Filters {
+ using System;
+
+ public class Curve {
+ public float[] X;
+ public float[] Y;
+
+ public Curve() {
+ X = new float[] { 0, 1 };
+ Y = new float[] { 0, 1 };
+ }
+
+ public Curve(Curve curve) {
+ X = (float[])curve.X.Clone();
+ Y = (float[])curve.Y.Clone();
+ }
+
+ public int AddKnot(float kx, float ky) {
+ var pos = -1;
+ var numKnots = X.Length;
+ var nx = new float[numKnots + 1];
+ var ny = new float[numKnots + 1];
+ var j = 0;
+ for (var i = 0; i < numKnots; i++) {
+ if (pos == -1 && X[i] > kx) {
+ pos = j;
+ nx[j] = kx;
+ ny[j] = ky;
+ j++;
+ }
+ nx[j] = X[i];
+ ny[j] = Y[i];
+ j++;
+ }
+ if (pos == -1) {
+ pos = j;
+ nx[j] = kx;
+ ny[j] = ky;
+ }
+ X = nx;
+ Y = ny;
+ return pos;
+ }
+
+ public void RemoveKnot(int n) {
+ var numKnots = X.Length;
+ if (numKnots <= 2) {
+ return;
+ }
+ var nx = new float[numKnots - 1];
+ var ny = new float[numKnots - 1];
+ var j = 0;
+ for (var i = 0; i < numKnots - 1; i++) {
+ if (i == n) {
+ j++;
+ }
+ nx[i] = X[j];
+ ny[i] = Y[j];
+ j++;
+ }
+ X = nx;
+ Y = ny;
+ }
+
+ private void SortKnots() {
+ var numKnots = X.Length;
+ for (var i = 1; i < numKnots - 1; i++) {
+ for (var j = 1; j < i; j++) {
+ if (!(X[i] < X[j])) {
+ continue;
+ }
+
+ var t = X[i];
+ X[i] = X[j];
+ X[j] = t;
+ t = Y[i];
+ Y[i] = Y[j];
+ Y[j] = t;
+ }
+ }
+ }
+
+ public int[] MakeTable() {
+ var numKnots = X.Length;
+ var nx = new float[numKnots + 2];
+ var ny = new float[numKnots + 2];
+ Array.Copy(X, 0, nx, 1, numKnots);
+ Array.Copy(Y, 0, ny, 1, numKnots);
+ nx[0] = nx[1];
+ ny[0] = ny[1];
+ nx[numKnots + 1] = nx[numKnots];
+ ny[numKnots + 1] = ny[numKnots];
+
+ var table = new int[256];
+ for (var i = 0; i < 1024; i++) {
+ var f = i / 1024.0f;
+ var x = (int)(255 * ImageMath.spline(f, nx.Length, nx) + 0.5f);
+ var y = (int)(255 * ImageMath.spline(f, nx.Length, ny) + 0.5f);
+ x = ImageMath.Clamp(x, 0, 255);
+ y = ImageMath.Clamp(y, 0, 255);
+ table[x] = y;
+ }
+ return table;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Filters/CurvesFilter.cs b/Filters/CurvesFilter.cs
new file mode 100644
index 0000000..df94abb
--- /dev/null
+++ b/Filters/CurvesFilter.cs
@@ -0,0 +1,69 @@
+#region License and copyright notice
+/*
+ * Ported to .NET for use in Kaliko.ImageLibrary by Fredrik Schultz 2015
+ *
+ * Original License:
+ * Copyright 2006 Jerry Huxtable
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+#endregion
+
+namespace Kaliko.ImageLibrary.Filters {
+ using System;
+
+ public class CurvesFilter : TransferFilter, IFilter {
+
+ private Curve[] _curves;
+
+ public CurvesFilter() {
+ _curves = new Curve[3];
+ _curves[0] = new Curve();
+ _curves[1] = new Curve();
+ _curves[2] = new Curve();
+ }
+
+ protected override void Initialize() {
+ Initialized = true;
+ if (_curves.Length == 1) {
+ rTable = gTable = bTable = _curves[0].MakeTable();
+ }
+ else {
+ rTable = _curves[0].MakeTable();
+ gTable = _curves[1].MakeTable();
+ bTable = _curves[2].MakeTable();
+ }
+ }
+
+ public void SetCurve(Curve curve) {
+ _curves = new[] { curve };
+ Initialized = false;
+ }
+
+ public void SetCurves(Curve[] curves) {
+ if (curves == null || (curves.Length != 1 && curves.Length != 3)) {
+ throw new ArgumentException("Curves must be length 1 or 3");
+ }
+ _curves = curves;
+ Initialized = false;
+ }
+
+ public Curve[] GetCurves() {
+ return _curves;
+ }
+
+ public void Run(KalikoImage image) {
+
+ }
+ }
+}
diff --git a/Filters/PointFilter.cs b/Filters/PointFilter.cs
new file mode 100644
index 0000000..fa9634f
--- /dev/null
+++ b/Filters/PointFilter.cs
@@ -0,0 +1,37 @@
+namespace Kaliko.ImageLibrary.Filters {
+ public abstract class PointFilter {
+
+ protected bool CanFilterIndexColorModel = false;
+
+ public void ApplyFilter(KalikoImage image) {
+ var pixels = image.IntArray;
+
+ var width = image.Width;
+ var height = image.Height;
+
+ for (var y = 0; y < height; y++) {
+ // We try to avoid calling getRGB on images as it causes them to become unmanaged, causing horrible performance problems.
+ //if (type == BufferedImage.TYPE_INT_ARGB) {
+ // srcRaster.getDataElements(0, y, width, 1, inPixels);
+ // for (int x = 0; x < width; x++)
+ // inPixels[x] = filterRGB(x, y, inPixels[x]);
+ // dstRaster.setDataElements(0, y, width, 1, inPixels);
+ //}
+ //else {
+ // src.getRGB(0, y, width, 1, inPixels, 0, width);
+ for (var x = 0; x < width; x++) {
+ pixels[x] = (int)FilterRgb(x, y, (uint)pixels[x]);
+ }
+ // dst.setRGB(0, y, width, 1, inPixels, 0, width);
+ //}
+ }
+
+ image.IntArray = pixels;
+ }
+
+ public void SetDimensions(int width, int height) {
+ }
+
+ public abstract uint FilterRgb(int x, int y, uint rgb);
+ }
+}
\ No newline at end of file
diff --git a/Filters/TransferFilter.cs b/Filters/TransferFilter.cs
new file mode 100644
index 0000000..e521365
--- /dev/null
+++ b/Filters/TransferFilter.cs
@@ -0,0 +1,58 @@
+namespace Kaliko.ImageLibrary.Filters {
+ public abstract class TransferFilter : PointFilter {
+
+ protected int[] rTable, gTable, bTable;
+ protected bool Initialized = false;
+
+ protected TransferFilter() {
+ CanFilterIndexColorModel = true;
+ }
+
+ public override uint FilterRgb(int x, int y, uint rgb) {
+ uint a = rgb & 0xff000000;
+ uint r = (rgb >> 16) & 0xff;
+ uint g = (rgb >> 8) & 0xff;
+ uint b = rgb & 0xff;
+ r = (uint)rTable[r];
+ g = (uint)gTable[g];
+ b = (uint)bTable[b];
+ return a | (r << 16) | (g << 8) | b;
+ }
+
+ //public BufferedImage filter(BufferedImage src, BufferedImage dst) {
+ // if (!initialized)
+ // initialize();
+ // return super.filter(src, dst);
+ //}
+
+ protected virtual void Initialize() {
+ Initialized = true;
+ rTable = gTable = bTable = MakeTable();
+ }
+
+ protected int[] MakeTable() {
+ var table = new int[256];
+ for (var i = 0; i < 256; i++) {
+ table[i] = PixelUtils.Clamp((int)(255*TransferFunction(i/255.0f)));
+ }
+ return table;
+ }
+
+ protected float TransferFunction(float v) {
+ return 0;
+ }
+
+ public uint[] GetLUT() {
+ if (!Initialized) {
+ Initialize();
+ }
+
+ var lut = new uint[256];
+ for (uint i = 0; i < 256; i++) {
+ lut[i] = FilterRgb(0, 0, (i << 24) | (i << 16) | (i << 8) | i);
+ }
+ return lut;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ImageLibrary.csproj b/ImageLibrary.csproj
index 5cc0346..d340c45 100644
--- a/ImageLibrary.csproj
+++ b/ImageLibrary.csproj
@@ -40,6 +40,61 @@
false
bin\Release\Kaliko.ImageLibrary.XML
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+ false
+ ..\.build\net20\Kaliko.ImageLibrary.XML
+ ..\.build\net20\
+ v2.0
+
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+ false
+ ..\.build\net30\Kaliko.ImageLibrary.XML
+ ..\.build\net30\
+ v3.0
+
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+ false
+ ..\.build\net35\Kaliko.ImageLibrary.XML
+ ..\.build\net35\
+ v3.5
+
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+ false
+ ..\.build\net40\Kaliko.ImageLibrary.XML
+ ..\.build\net40\
+ v4.0
+
+
+ pdbonly
+ true
+ TRACE
+ prompt
+ 4
+ false
+ ..\.build\net45\Kaliko.ImageLibrary.XML
+ ..\.build\net45\
+ v4.5
+
@@ -59,15 +114,20 @@
+
+
+
+
+
diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs
index 4f25029..93477b6 100644
--- a/Properties/AssemblyInfo.cs
+++ b/Properties/AssemblyInfo.cs
@@ -1,5 +1,4 @@
using System.Reflection;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -21,15 +20,3 @@
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("58b4262b-c04f-4c08-a1c9-948ddd0cbf84")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("2.0.4.0")]
-[assembly: AssemblyFileVersion("2.0.4.0")]
diff --git a/Properties/SolutionInfo.cs b/Properties/SolutionInfo.cs
new file mode 100644
index 0000000..be03d13
--- /dev/null
+++ b/Properties/SolutionInfo.cs
@@ -0,0 +1,10 @@
+//
+using System.Reflection;
+
+[assembly: AssemblyVersionAttribute("2.0.5")]
+[assembly: AssemblyFileVersionAttribute("2.0.5")]
+namespace System {
+ internal static class AssemblyVersionInformation {
+ internal const string Version = "2.0.5";
+ }
+}
diff --git a/ReleaseNotes.md b/ReleaseNotes.md
new file mode 100644
index 0000000..88916cb
--- /dev/null
+++ b/ReleaseNotes.md
@@ -0,0 +1,29 @@
+### New in 2.0.5
+* Added curves filter
+
+### New in 2.0.4-beta
+* Added new TextField class for better text support
+* Fixed scaling bug and updated test program
+
+### New in 2.0.0
+* Replaced Gaussian blur filter with better implementation (affects unsharpen masks)
+* Added chroma key filter
+* Rewritten API for Scaling
+* Added color space handling
+
+### New in 1.2.4
+* Updated to Visual Studio 2010.
+* Code clean-up.
+* Unwanted-border-artifact-problem fixed (thanks Richard!)
+* IDisponable has been implemented.
+
+### New in 1.2.3
+* Minor changes.
+* First API documentation uploaded. Still missing a whole lot, but it's a start :)
+
+### New in 1.2.2
+* Minor changes
+
+### New in 1.2.1
+* Bug in thumbnail function fixed.
+* Code cleaned up.