// project created on 3/13/2007 at 7:10 PM using System; using System.Drawing; using System.Drawing.Imaging; namespace imaging { struct ContrastLayer { public ushort[] curve; public ushort[] mask; } class MainClass { static byte[] values; static int width, height, stride; static ushort FloatToSample (float f) { return (ushort)(f * 65535.0); } static ushort SampleMul (ushort a, ushort b) { return (ushort)(((uint)a * (uint)b) >> 16); } static void Process (int width, int height, ushort[] outData, ushort[] inData, float red, float green, float blue, ContrastLayer[] contrastLayers, float tintHue, float tintAmount) { int redFactor = (int)(red * 2048.0); int greenFactor = (int)(green * 2048.0); int blueFactor = (int)(blue * 2048.0); int i; ushort f; ushort saturation = FloatToSample (tintAmount); tintHue = tintHue / 60.0f; if (tintHue >= 6.0f) tintHue -= 6.0f; i = (int)Math.Floor(tintHue); f = FloatToSample (tintHue - i); for (int y = 0; y < height; ++y) { int rowIndex = y * width * 3; int rowMaskIndex = y * width; for (int x = 0; x < width; ++x) { int index = rowIndex + x * 3; int maskIndex = rowMaskIndex + x; ushort ir = inData[index + 2]; ushort ig = inData[index + 1]; ushort ib = inData[index + 0]; int sgray = (int)ir * redFactor + (int)ig * greenFactor + (int)ib * blueFactor; ushort gray; ushort contrasted, inverted; ushort s, v, p, q, t; ushort r, g, b; if (sgray < 0) sgray = 0; sgray >>= 11; gray = (ushort)((sgray > 65535) ? 65535 : sgray); contrasted = gray; for (int layer = 0; layer < contrastLayers.Length; ++layer) { ushort result = contrastLayers [layer].curve [gray >> 5]; if (contrastLayers [layer].mask == null) contrasted = result; else { ushort mask = contrastLayers [layer].mask [maskIndex]; contrasted = (ushort)(SampleMul (result, mask) + SampleMul (contrasted, (ushort)(65535 - mask))); } } inverted = (ushort)(65535 - contrasted); if (inverted < 65535 / 2) { s = (ushort)(inverted * 2); v = 65535; } else { s = 65535; v = (ushort)(65535 - ((int)inverted - 65535 / 2) * 2); } p = SampleMul (v, (ushort)(65535 - s)); q = SampleMul (v, (ushort)(65535 - (SampleMul (s, f)))); t = SampleMul (v, (ushort)(65535 - (SampleMul (s, (ushort)(65535 - f))))); switch (i) { case 0 : r = v; g = t; b = p; break; case 1 : r = q; g = v; b = p; break; case 2 : r = p; g = v; b = t; break; case 3 : r = p; g = q; b = v; break; case 4 : r = t; g = p; b = v; break; case 5 : r = v; g = p; b = q; break; default : r = 0; g = 0; b = 0; break; } outData [index + 2] = (ushort)(SampleMul (r, saturation) + SampleMul ((ushort)(65535 - inverted), (ushort)(65535 - saturation))); outData [index + 1] = (ushort)(SampleMul (g, saturation) + SampleMul ((ushort)(65535 - inverted), (ushort)(65535 - saturation))); outData [index + 0] = (ushort)(SampleMul (b, saturation) + SampleMul ((ushort)(65535 - inverted), (ushort)(65535 - saturation))); } } } static void getAndAddPixel (int x, int y, double f, byte[] pixel) { byte r, g, b, a; if (x < 0 || x >= width || y < 0 || y >= height) r = g = b = a = 0; else { int i = y * stride + x * 3; r = values[i + 2]; g = values[i + 1]; b = values[i + 0]; a = 1; } pixel[0] += (byte)(r * f); pixel[1] += (byte)(g * f); pixel[2] += (byte)(b * f); pixel[3] += (byte)(a * f); } static void getIntersamplePixel (double x, double y, byte[] pixel) { int x0 = (int)Math.Floor(x), x1 = x0 + 1; int y0 = (int)Math.Floor(y), y1 = y0 + 1; double fx1 = x - Math.Floor(x), fx0 = 1.0 - fx1; double fy1 = y - Math.Floor(y), fy0 = 1.0 - fy1; pixel[0] = pixel[1] = pixel[2] = pixel[3] = 0; getAndAddPixel(x0, y0, fx0 * fy0, pixel); getAndAddPixel(x0, y1, fx0 * fy1, pixel); getAndAddPixel(x1, y0, fx1 * fy0, pixel); getAndAddPixel(x1, y1, fx1 * fy1, pixel); } public static void Main(string[] args) { Bitmap bmp = new Bitmap("/photos/Photographs/Marlene/marlene7.jpg"); //Bitmap bmp = new Bitmap(100, 100); width = bmp.Width; height = bmp.Height; double middle_x = width / 2.0; double middle_y = height / 2.0; Rectangle rect = new Rectangle(0, 0, width, height); BitmapData data = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); stride = data.Stride; IntPtr ptr = data.Scan0; int numBytes = stride * height; Console.WriteLine("w:" + width + " h:" + height + " str:" + stride); values = new byte[numBytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, values, 0, numBytes); ushort[] inData = new ushort[width * height * 3]; ushort[] outData = new ushort[width * height * 3]; for (int iy = 0; iy < height; ++iy) { for (int ix = 0; ix < width; ++ix) { inData[(iy * width + ix) * 3 + 0] = (ushort)(values[iy * stride + ix * 3 + 0] << 8); inData[(iy * width + ix) * 3 + 1] = (ushort)(values[iy * stride + ix * 3 + 1] << 8); inData[(iy * width + ix) * 3 + 2] = (ushort)(values[iy * stride + ix * 3 + 2] << 8); } } ushort[] contrastCurve = new ushort[2048]; ushort[] brightenCurve = new ushort[2048]; ushort[] darkenCurve = new ushort[2048]; for (int i = 0; i < 2048; ++i) { contrastCurve [i] = FloatToSample (i / 2048f); brightenCurve [i] = FloatToSample ((float)Math.Pow (i / 2048f, 0.5)); darkenCurve [i] = FloatToSample ((float)Math.Pow (i / 2048f, 2.0)); } ushort[] brightenMask = new ushort [width * height]; ushort[] darkenMask = new ushort [width * height]; for (int y = 0; y < height; ++y) for (int x = 0; x < width; ++x) { float fx = (float)(x - (width / 2)) / (width / 2); float fy = (float)(y - (height / 2)) / (height / 2); float r = (float)Math.Sqrt(fx*fx + fy*fy); if (r >= 1.0) { brightenMask [y * width + x] = 0; darkenMask [y * width + x] = 65535; } else { brightenMask [y * width + x] = FloatToSample (1.0f - r); darkenMask [y * width + x] = FloatToSample (r); } } ContrastLayer[] layers = new ContrastLayer[1]; layers [0].curve = contrastCurve; layers [0].mask = null; /* layers [1].curve = brightenCurve; layers [1].mask = brightenMask; layers [2].curve = darkenCurve; layers [2].mask = darkenMask; */ for (int i = 0; i < 100; ++i) Process(width, height, outData, inData, 0.5f, 0.3f, 0.2f, layers, 23.0f, 0.1f); byte[] newValues = new byte[numBytes]; for (int iy = 0; iy < height; ++iy) { int rowI = stride * iy; for (int ix = 0; ix < width; ++ix) { newValues[rowI + ix * 3 + 0] = (byte)(outData[(iy * width + ix) * 3 + 0] >> 8); newValues[rowI + ix * 3 + 1] = (byte)(outData[(iy * width + ix) * 3 + 1] >> 8); newValues[rowI + ix * 3 + 2] = (byte)(outData[(iy * width + ix) * 3 + 2] >> 8); } } /* byte[] pixel = new byte[4]; double R = Math.Sqrt(width * height); //for (int loop = 0; loop < 100; ++loop) for (int iy = 0; iy < height; ++iy) { int i = stride * iy; double y = iy - middle_y; for (int ix = 0; ix < width; ++ix) { double x = ix - middle_x; double r = Math.Sqrt(x * x + y * y); double a = Math.Atan2(y, x); a -= (r/R-1)*Math.PI/5; x = Math.Cos(a) * r; y = Math.Sin(a) * r; getIntersamplePixel(x + middle_x + 0.3, y + middle_y + 0.8, pixel); new_values[i + 0] = pixel[2]; new_values[i + 1] = pixel[1]; new_values[i + 2] = pixel[0]; i += 3; } } */ System.Runtime.InteropServices.Marshal.Copy(newValues, 0, ptr, numBytes); bmp.UnlockBits(data); bmp.Save("/tmp/heusl.png", ImageFormat.Png); Console.WriteLine("Hello World!"); } } }