//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//  
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;

namespace ImageProcessing
{
	/// <summary>
	/// Podsumowanie dla Form1.
	/// </summary>
	public class ImageForm : System.Windows.Forms.Form
	{
		private System.Windows.Forms.PictureBox image;
		private System.Windows.Forms.Label imagePathLabel;
		private System.Windows.Forms.TextBox imagePath;
		private System.Windows.Forms.Button processButton;
		private System.Windows.Forms.Button exitButton;
		private System.Windows.Forms.Button loadButton;
		private Bitmap rawImage;
		/// <summary>
		/// Wymagana zmienna.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public ImageForm()
		{
			//
			// Wymagane do obsługi Windows Form Designer
			//
			InitializeComponent();

			//
			// TODO: Dodanie kodu konstruktora po wywołaniu InitializeComponent
			//
		}

		/// <summary>
		/// Oczyszczenie używanych zasobów.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
					rawImage.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Metoda wymagana do obsługi Designera - nie należy modyfikować
		/// zawartości tej metody przy użyciu edytora kodu.
		/// </summary>
		private void InitializeComponent()
		{
			this.image = new System.Windows.Forms.PictureBox();
			this.imagePathLabel = new System.Windows.Forms.Label();
			this.imagePath = new System.Windows.Forms.TextBox();
			this.processButton = new System.Windows.Forms.Button();
			this.exitButton = new System.Windows.Forms.Button();
			this.loadButton = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// image
			// 
			this.image.Location = new System.Drawing.Point(8, 8);
			this.image.Name = "image";
			this.image.Size = new System.Drawing.Size(512, 512);
			this.image.TabIndex = 0;
			this.image.TabStop = false;
			// 
			// imagePathLabel
			// 
			this.imagePathLabel.Location = new System.Drawing.Point(8, 536);
			this.imagePathLabel.Name = "imagePathLabel";
			this.imagePathLabel.Size = new System.Drawing.Size(100, 24);
			this.imagePathLabel.TabIndex = 1;
			this.imagePathLabel.Text = "Ścieżka do rysunku";
			// 
			// imagePath
			// 
			this.imagePath.Location = new System.Drawing.Point(128, 536);
			this.imagePath.Name = "imagePath";
			this.imagePath.Size = new System.Drawing.Size(120, 20);
			this.imagePath.TabIndex = 2;
			this.imagePath.Text = "..\\..\\coca-cola.bmp";
			// 
			// processButton
			// 
			this.processButton.Location = new System.Drawing.Point(352, 536);
			this.processButton.Name = "processButton";
			this.processButton.TabIndex = 3;
			this.processButton.Text = "Przetwarzanie";
			this.processButton.Click += new System.EventHandler(this.OnProcess);
			// 
			// exitButton
			// 
			this.exitButton.Location = new System.Drawing.Point(440, 536);
			this.exitButton.Name = "exitButton";
			this.exitButton.TabIndex = 4;
			this.exitButton.Text = "Wyjdź";
			this.exitButton.Click += new System.EventHandler(this.OnExit);
			// 
			// loadButton
			// 
			this.loadButton.Location = new System.Drawing.Point(264, 536);
			this.loadButton.Name = "loadButton";
			this.loadButton.TabIndex = 5;
			this.loadButton.Text = "Ładuj";
			this.loadButton.Click += new System.EventHandler(this.OnLoad);
			// 
			// ImageForm
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(528, 573);
			this.Controls.AddRange(new System.Windows.Forms.Control[] {
																		  this.loadButton,
																		  this.exitButton,
																		  this.processButton,
																		  this.imagePath,
																		  this.imagePathLabel,
																		  this.image});
			this.Name = "ImageForm";
			this.Text = "Przetwarzanie rysunków";
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// Główny punkt wejścia dla aplikacji.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			Application.Run(new ImageForm());
		}

		private void OnLoad(object sender, System.EventArgs e)
		{
			try
			{
				rawImage = new Bitmap(imagePath.Text);
				image.Image = rawImage;
			}
			catch(Exception exception)
			{
				Debug.WriteLine(exception);
			}
		}

		unsafe private void OnProcess(object sender, System.EventArgs e)
		{
			BitmapData data = null;
			try
			{
				// ColorPalette pal = rawImage.Palette;
				// Color [] lut = pal.Entries;
				// for(int i = 0; i < lut.Length; i++)
				// {
				//	Debug.WriteLine(string.Format("{0} {1}", i, lut[i]));
				// }
				data = rawImage.LockBits(new Rectangle(new Point(0,0), new Size(rawImage.Width, rawImage.Height)),
					                     ImageLockMode.ReadWrite,
					                     rawImage.PixelFormat);
				Debug.Write(string.Format("PixelFormat 0x{0:X} {1}: ", data.PixelFormat, data.PixelFormat.ToString()));
				Debug.WriteIf(data.PixelFormat == PixelFormat.Alpha, "Alpha ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Canonical, "Canonical ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.DontCare, "DontCare ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Extended, "Extended ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format16bppArgb1555, "Format16bppArgb1555 ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format16bppGrayScale, "Format16bppGrayScale ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format16bppRgb555, "Format16bppRgb555 ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format16bppRgb565, "Format16bppRgb565 ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format24bppRgb, "Format24bppRgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format32bppArgb, "Format32bppArgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format32bppPArgb, "Format32bppPArgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format32bppRgb, "Format32bppRgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format48bppRgb, "Format48bppRgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format64bppArgb, "Format64bppArgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Format64bppPArgb, "Format64bppPArgb ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Gdi, "Gdi ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Max, "Max ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.PAlpha, "PAlpha ");
				Debug.WriteIf(data.PixelFormat == PixelFormat.Undefined, "Undefined ");
				Debug.WriteLine("");
				Debug.WriteLine(string.Format("Scan0: 0x{0:X}", data.Scan0));
				Debug.WriteLine("Stride: " + data.Stride);
				Debug.WriteLine("Width: " + data.Width);
				Debug.WriteLine("Height: " + data.Height);
				int [,] cache = new int[data.Height,data.Width];
				Byte *p1;
				Byte *p2;
				Byte *p3;
				int max, min, temp;
				max = 0;
				min = 255;
				// Wyszukanie zakresu
				for(int i = 1; i < data.Height - 1; i++)
				{
					// Points to the center of the kernel
					p1 = (Byte *)data.Scan0.ToPointer() + ((i - 1) * data.Stride);
					p2 = (Byte *)data.Scan0.ToPointer() + (i * data.Stride);
					p3 = (Byte *)data.Scan0.ToPointer() + ((i + 1) * data.Stride);
					for(int j = 1; j < data.Width - 1; j++)
					{
						temp = (Math.Abs((*p1 + *(p1 + 1) * 2 + *(p1 + 2)) - (*p3 + *(p3 + 1) * 2 + *(p3 + 2))) +
							    Math.Abs((*(p1 + 2) + *(p2 + 2) * 2 + *(p3 + 2)) - (*p1 + *p2 * 2 + *p3)));
						if(temp > max)
							max = temp;
						if(temp < min)
							min = temp;
						cache[i,j] = temp;
						p1++;
						p2++;
						p3++;
					}
				}
				Debug.WriteLine("Min: " + Convert.ToString(min));
				Debug.WriteLine("Max: " + Convert.ToString(max));
				for(int i = 1; i < data.Height - 1; i++)
				{
					// Wskazanie środka
					p2 = (Byte *)data.Scan0.ToPointer() + (i * data.Stride) + 1;
					for(int j = 1; j < data.Width - 1; j++)
					{
						temp = (int)(((float)cache[i,j]/(float)max) * 255.0);
						*p2++ = (Byte)temp;
					}
				}
			}
			finally
			{
				rawImage.UnlockBits(data);
				image.Refresh();
			}
		}

		private void OnExit(object sender, System.EventArgs e)
		{
			Application.Exit();
		}
	}
}
