Click here to Skip to main content
15,888,000 members
Articles / Programming Languages / C#

An Image Viewer with Lossless Rotation, EXIF and Other Goodies

Rate me:
Please Sign up or sign in to vote.
3.16/5 (15 votes)
27 Aug 2003CPOL6 min read 146.3K   1.4K   90  
This article demonstrates a simple viewer for JPEG images.
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Management;
using System.Globalization;
using System.DirectoryServices;
using System.Configuration;
using System.Collections.Specialized;

using TowerSoftware.IO;
using TowerSoftware.LinkedListCode;
using TowerSoftware.ImageFunctionSoftware;

public class Explorer : System.Windows.Forms.Form
{
	private System.Windows.Forms.Splitter splitter1;
	private System.Windows.Forms.MainMenu mainMenu1;
	private System.Windows.Forms.MenuItem menuItem1;
	private System.Windows.Forms.MenuItem menuItem2;
	private System.Windows.Forms.MenuItem menuItem3;
	private System.Windows.Forms.MenuItem menuItem4;
	private System.Windows.Forms.TreeView tvFolders;
	private System.Windows.Forms.ImageList m_imageListTreeView;
	private System.Windows.Forms.PictureBox sizablePicture;
	private System.Windows.Forms.MenuItem menuItemRotate;
	private System.ComponentModel.IContainer components;

	public Explorer()
	{
		//
		// Required for Windows Form Designer support
		//
		InitializeComponent();

		// Populate TreeView with Drive list
		PopulateDriveList();
	}

	/// <summary>
	/// Clean up any resources being used.
	/// </summary>
	protected override void Dispose( bool disposing )
	{
		if( disposing )
		{
			if (components != null) 
			{
				components.Dispose();
			}
		}
		base.Dispose( disposing );
	}


		#region Windows Form Designer generated code
	/// <summary>
	/// Required method for Designer support - do not modify
	/// the contents of this method with the code editor.
	/// </summary>
	private void InitializeComponent()
	{
		this.components = new System.ComponentModel.Container();
		System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Explorer));
		this.tvFolders = new System.Windows.Forms.TreeView();
		this.m_imageListTreeView = new System.Windows.Forms.ImageList(this.components);
		this.splitter1 = new System.Windows.Forms.Splitter();
		this.mainMenu1 = new System.Windows.Forms.MainMenu();
		this.menuItem1 = new System.Windows.Forms.MenuItem();
		this.menuItem2 = new System.Windows.Forms.MenuItem();
		this.menuItemRotate = new System.Windows.Forms.MenuItem();
		this.menuItem3 = new System.Windows.Forms.MenuItem();
		this.menuItem4 = new System.Windows.Forms.MenuItem();
		this.sizablePicture = new System.Windows.Forms.PictureBox();
		this.SuspendLayout();
		// 
		// tvFolders
		// 
		this.tvFolders.CheckBoxes = true;
		this.tvFolders.Dock = System.Windows.Forms.DockStyle.Left;
		this.tvFolders.ImageList = this.m_imageListTreeView;
		this.tvFolders.Name = "tvFolders";
		this.tvFolders.Size = new System.Drawing.Size(215, 535);
		this.tvFolders.TabIndex = 2;
		this.tvFolders.Move += new System.EventHandler(this.tvFolders_onMove);
		this.tvFolders.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.tvFolders_AfterSelect);
		this.tvFolders.SizeChanged += new System.EventHandler(this.tvFolders_onSizeChanged);
		// 
		// m_imageListTreeView
		// 
		this.m_imageListTreeView.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
		this.m_imageListTreeView.ImageSize = new System.Drawing.Size(16, 16);
		this.m_imageListTreeView.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("m_imageListTreeView.ImageStream")));
		this.m_imageListTreeView.TransparentColor = System.Drawing.Color.Transparent;
		// 
		// splitter1
		// 
		this.splitter1.Location = new System.Drawing.Point(215, 0);
		this.splitter1.Name = "splitter1";
		this.splitter1.Size = new System.Drawing.Size(4, 535);
		this.splitter1.TabIndex = 3;
		this.splitter1.TabStop = false;
		// 
		// mainMenu1
		// 
		this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																				  this.menuItem1,
																				  this.menuItem3});
		// 
		// menuItem1
		// 
		this.menuItem1.Index = 0;
		this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																				  this.menuItem2,
																				  this.menuItemRotate});
		this.menuItem1.Text = "&File";
		// 
		// menuItem2
		// 
		this.menuItem2.Index = 0;
		this.menuItem2.Text = "&Close";
		this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click);
		// 
		// menuItemRotate
		// 
		this.menuItemRotate.Index = 1;
		this.menuItemRotate.Text = "Rotate";
		this.menuItemRotate.Click += new System.EventHandler(this.menuItemRotate_Click);
		// 
		// menuItem3
		// 
		this.menuItem3.Index = 1;
		this.menuItem3.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																				  this.menuItem4});
		this.menuItem3.Text = "&Help";
		// 
		// menuItem4
		// 
		this.menuItem4.Index = 0;
		this.menuItem4.Text = "&About";
		// 
		// sizablePicture
		// 
		this.sizablePicture.Location = new System.Drawing.Point(219, 0);
		this.sizablePicture.Name = "sizablePicture";
		this.sizablePicture.Size = new System.Drawing.Size(405, 535);
		this.sizablePicture.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
		this.sizablePicture.TabIndex = 4;
		this.sizablePicture.TabStop = false;
		this.sizablePicture.Click += new System.EventHandler(this.pictureBox1_Click);
		// 
		// Explorer
		// 
		this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
		this.ClientSize = new System.Drawing.Size(624, 535);
		this.Controls.AddRange(new System.Windows.Forms.Control[] {
																	  this.sizablePicture,
																	  this.splitter1,
																	  this.tvFolders});
		this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
		this.Menu = this.mainMenu1;
		this.Name = "Explorer";
		this.Text = "My Window Explorer";
		this.ResumeLayout(false);

	}
		#endregion

	/// <summary>
	/// The main entry point for the application.
	/// </summary>
	[STAThread]
	static void xxxxxMain() 
	{
		Application.Run(new Explorer());
	}

	enum IconType
	{
		myComputer = 0,
		Removable = 2,
		LocalDisk = 3,
		Network = 4,
		CD = 5,
		//const int RAMDrive = 6;
		FILES = 11
	};
	//This procedure populate the TreeView with the Drive list
	private void PopulateDriveList()
	{
		TreeNode nodeTreeNode;
		IconType imageIndex;
		IconType selectIndex;


		this.Cursor = Cursors.WaitCursor;
		//clear TreeView
		tvFolders.Nodes.Clear();
		nodeTreeNode = new TreeNode("My Computer", (int)IconType.myComputer, (int)IconType.myComputer);
		tvFolders.Nodes.Add(nodeTreeNode);

		//set node collection
		TreeNodeCollection nodeCollection = nodeTreeNode.Nodes;

		//Get Drive list
		ManagementObjectCollection queryCollection = GetDrives();
		foreach ( ManagementObject mo in queryCollection)
		{
			
			switch (int.Parse( mo["DriveType"].ToString()))
			{
				case (int)IconType.Removable:			//removable drives
					selectIndex = imageIndex = IconType.Removable;
					break;
				case (int)IconType.CD:				//CD rom drives
					selectIndex = imageIndex = IconType.CD;
					continue;
				case (int)IconType.Network:			//Network drives
					selectIndex = imageIndex = IconType.Network;
					break;
				case (int)IconType.LocalDisk:			//Local drives
					selectIndex = imageIndex = IconType.LocalDisk;
					break;
				default:				//default to folder
					selectIndex = imageIndex = IconType.LocalDisk;
					break;
			}
			//create new drive node
			nodeTreeNode = new TreeNode(mo["Name"].ToString() + "\\" , (int)imageIndex, (int)selectIndex);

			//add new node
			nodeCollection.Add(nodeTreeNode);

		}


		//Init files ListView
		InitListView();

		this.Cursor = Cursors.Default;

	}
		

	private void tvFolders_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
	{
		//Populate folders and files when a folder is selected
		this.Cursor = Cursors.WaitCursor;

		//get current selected drive or folder
		TreeNode nodeCurrent = e.Node;

		//clear all sub-folders
		nodeCurrent.Nodes.Clear();

		if (nodeCurrent.SelectedImageIndex == (int)IconType.myComputer) 
		{
			//Selected My Computer - repopulate drive list
			PopulateDriveList();
		}
		else 
		{
			//populate sub-folders and folder files
			PopulateDirectory(nodeCurrent, nodeCurrent.Nodes);
		}
		this.Cursor = Cursors.Default;
	}
		
	protected void InitListView()
	{
		//init ListView control
		//lvFiles.Clear();		//clear control
		//create column header for ListView
		//lvFiles.Columns.Add("Name",150,System.Windows.Forms.HorizontalAlignment.Left);
		//lvFiles.Columns.Add("Size",75, System.Windows.Forms.HorizontalAlignment.Right);
		//lvFiles.Columns.Add("Created", 140, System.Windows.Forms.HorizontalAlignment.Left);
		//lvFiles.Columns.Add("Modified", 140, System.Windows.Forms.HorizontalAlignment.Left);

	}

		
	public bool OLDshowPicha(TreeNode nodeCurrent)
	{
		//MessageBox.Show("Directory or path " + nodeCurrent.ToString() + " does not exist.");
		string fn = GetFullPath(nodeCurrent.FullPath);
		Image fullSizeImg = System.Drawing.Image.FromFile(fn);
		int xi = fullSizeImg.Width;
		int yi = fullSizeImg.Height; 

		double aspectRatio = xi / (double)yi;
		bool crappyThumbNailDoesntalwaysWork = false;
		if ( crappyThumbNailDoesntalwaysWork )
		{
			int xp = sizablePicture.Size.Width;
			int yp = sizablePicture.Size.Height;
			int newImageWidth = xp;
			int newImageHeight = yp;
			if ( (double)xp/yp > aspectRatio)
			{
				newImageWidth = (int)(yp * aspectRatio);
			}
			else
			{
				newImageHeight = (int)(xp / aspectRatio);
			}
			//Image fullSizeImg = Image.FromFile(Server.MapPath(imageUrl));
			Image.GetThumbnailImageAbort dummyCallBack	= new Image.GetThumbnailImageAbort(ThumbnailCallback);
			Image thumbNailImg 	= fullSizeImg.GetThumbnailImage(newImageWidth, newImageHeight, 
				dummyCallBack, IntPtr.Zero);
			sizablePicture.Image = thumbNailImg; 
		}
		else
		{
			// Try to resize the picture box
			int xp = this.Width - tvFolders.Width;
			int yp = this.Height;
			int newpictureBoxWidth = xp;
			int newpictureBoxHeight = yp;
			if ( (double)xp/yp > aspectRatio)
			{
				newpictureBoxWidth = (int)(yp * aspectRatio);
			}
			else
			{
				newpictureBoxHeight = (int)(xp / aspectRatio);
			}
			sizablePicture.Width = newpictureBoxWidth;
			sizablePicture.Height = newpictureBoxHeight;
			sizablePicture.Image = Image.FromFile(fn);
		}
		return true;
	}

	//this function is reqd for thumbnail creation
	public bool ThumbnailCallback()
	{
		return false;
	}
	protected void PopulateDirectory(TreeNode nodeCurrent, TreeNodeCollection nodeCurrentCollection)
	{
		TreeNode nodeDir;

		if ( nodeCurrent.SelectedImageIndex != 1) 
		{
			//populate treeview with folders
			try
			{
				//check path
				if ( Directory.Exists(GetFullPath(nodeCurrent.FullPath)) == false)
				{
					Size theSize = new Size(this.Width - tvFolders.Width, this.Height);
					ImageFunctions.ShowPicture(sizablePicture, theSize, GetFullPath(nodeCurrent.FullPath));
				}
				else
				{
					//populate files
					PopulateFiles(nodeCurrent, nodeCurrentCollection);

					string[] stringDirectories = Directory.GetDirectories(GetFullPath(nodeCurrent.FullPath));
					string stringFullPath = "";
					string stringPathName = "";

					//loop throught all directories
					foreach (string stringDir in stringDirectories)
					{
						stringFullPath = stringDir;
						stringPathName = GetPathName(stringFullPath);
							
						//create node for directories
						nodeDir = new TreeNode(stringPathName.ToString(), (int)IconType.LocalDisk, (int)IconType.LocalDisk);
						nodeCurrentCollection.Add(nodeDir);
					}
				}
			}
			catch (IOException )
			{
				MessageBox.Show("Error: Drive not ready or directory does not exist.");
			}
			catch (UnauthorizedAccessException )
			{
				MessageBox.Show("Error: Drive or directory access denided.");
			}
			catch (Exception e)
			{
				MessageBox.Show("Error: " + e);
			}
		}
	}

	protected string GetPathName(string stringPath)
	{
		//Get Name of folder
		string[] stringSplit = stringPath.Split('\\');
		int _maxIndex = stringSplit.Length;
		return stringSplit[_maxIndex-1];
	}

	protected void PopulateFiles(TreeNode nodeCurrent, TreeNodeCollection nodeCollection)
	{
			
		//Populate listview with files
		string[] lvData =  new string[4];
			
		//clear list
		InitListView();

		if (nodeCurrent.SelectedImageIndex != (int)IconType.myComputer) 
		{
			//check path
			if(Directory.Exists((string) GetFullPath(nodeCurrent.FullPath)) == false)
			{
				MessageBox.Show("Directory or path " + nodeCurrent.ToString() + " does not exist.");
			}
			else
			{
				try
				{
					string[] stringFiles = Directory.GetFiles(GetFullPath(nodeCurrent.FullPath), "*.jpg");
					string stringFileName = "";
					DateTime dtCreateDate, dtModifyDate;
					Int64 lFileSize = 0;

					//loop throught all files
					foreach (string stringFile in stringFiles)
					{
						stringFileName = stringFile;
						string stringPathName = GetPathName(stringFileName);
						TreeNode nodeTreeNode = new TreeNode(stringPathName, (int)IconType.FILES, (int)IconType.FILES);
						nodeCollection.Add(nodeTreeNode);
					}

					// loop throught all files
					foreach (string stringFile in stringFiles)
					{
						stringFileName = stringFile;
						FileInfo objFileSize = new FileInfo(stringFileName);
						lFileSize = objFileSize.Length;
						dtCreateDate = objFileSize.CreationTime; //GetCreationTime(stringFileName);
						dtModifyDate = objFileSize.LastWriteTime; //GetLastWriteTime(stringFileName);

						//create listview data
						lvData[0] = GetPathName(stringFileName);
						lvData[1] = formatSize(lFileSize);
							
						//check if file is in local current day light saving time
						if (TimeZone.CurrentTimeZone.IsDaylightSavingTime(dtCreateDate) == false)
						{
							//not in day light saving time adjust time
							lvData[2] = FormatDate(dtCreateDate.AddHours(1));
						}
						else
						{
							//is in day light saving time adjust time
							lvData[2] = FormatDate(dtCreateDate);
						}

						//check if file is in local current day light saving time
						if (TimeZone.CurrentTimeZone.IsDaylightSavingTime(dtModifyDate) == false)
						{
							//not in day light saving time adjust time
							lvData[3] = FormatDate(dtModifyDate.AddHours(1));
						}
						else							
						{
							//not in day light saving time adjust time
							lvData[3] = FormatDate(dtModifyDate);
						}


					}
				}
				catch (IOException )
				{
					MessageBox.Show("Error: Drive not ready or directory does not exist.");
				}
				catch (UnauthorizedAccessException )
				{
					MessageBox.Show("Error: Drive or directory access denied.");
				}
				catch (Exception e)
				{
					MessageBox.Show("Error: " + e);
				}
			}
		}
	}

	protected string GetFullPath(string stringPath)
	{
		//Get Full path
		string stringParse = "";
		//remove My Computer from path.
		stringParse = stringPath.Replace("My Computer\\", "");

		return stringParse;
	}
		
	protected ManagementObjectCollection GetDrives()
	{
		//get drive collection
		ManagementObjectSearcher query = new ManagementObjectSearcher("SELECT * From Win32_LogicalDisk ");
		ManagementObjectCollection queryCollection = query.Get();
			
		return queryCollection;
	}

	protected string FormatDate(DateTime dtDate)
	{
		//Get date and time in short format
		string stringDate = "";

		stringDate = dtDate.ToShortDateString().ToString() + " " + dtDate.ToShortTimeString().ToString();

		return stringDate;
	}

	protected string formatSize(Int64 lSize)
	{
		//Format number to KB
		string stringSize = "";
		NumberFormatInfo myNfi = new NumberFormatInfo();

		Int64 lKBSize = 0;

		if (lSize < 1024 ) 
		{
			if (lSize == 0) 
			{
				//zero byte
				stringSize = "0";
			}
			else 
			{
				//less than 1K but not zero byte
				stringSize = "1";
			}
		}
		else 
		{
			//convert to KB
			lKBSize = lSize / 1024;
			//format number with default format
			stringSize = lKBSize.ToString("n",myNfi);
			//remove decimal
			stringSize = stringSize.Replace(".00", "");
		}

		return stringSize + " KB";

	}

	private void menuItem2_Click(object sender, System.EventArgs e)
	{
		//quit application
		this.Close();
	}

	private void pictureBox1_Click(object sender, System.EventArgs e)
	{
	}

	private void recursivelyRotate(TreeNodeCollection nodes)
	{			
		foreach(TreeNode node in nodes)
		{
			if (node.GetNodeCount(false) == 0)
			{
				if ( node.Checked)
				{
					string fname = GetFullPath(node.FullPath);
					ImageFunctions.Rotate90(fname);
				}
			}
			else
			{
				recursivelyRotate(node.Nodes);
			}
				
		}
	}

	private void menuItemRotate_Click(object sender, System.EventArgs e)
	{		
		sizablePicture.Image = null;
		sizablePicture.Invalidate();
		recursivelyRotate(tvFolders.Nodes);
		sizablePicture.Image = System.Drawing.Image.FromFile(GetFullPath(tvFolders.SelectedNode.FullPath));
	}

	private void tvFolders_onMove(object sender, System.EventArgs e)
	{
		//tvFolders.SelectedNode = tvFolders.SelectedNode;
		if ( tvFolders.SelectedNode != null )
		{
			if (tvFolders.SelectedNode.SelectedImageIndex > 10 ) 
			{
				//System.Windows.Forms.TreeViewEventArgs tve = new System.Windows.Forms.TreeViewEventArgs(tvFolders.SelectedNode);
				//tvFolders_AfterSelect(null, tve);
			}
		}
	}

	private void tvFolders_onSizeChanged(object sender, System.EventArgs e)
	{
		//tvFolders.SelectedNode = tvFolders.SelectedNode;
		if ( tvFolders.SelectedNode != null )
		{
			if ( tvFolders.SelectedNode.SelectedImageIndex == (int)IconType.FILES ) 
			{
				//System.Windows.Forms.TreeViewEventArgs tve = new System.Windows.Forms.TreeViewEventArgs(tvFolders.SelectedNode);
				//tvFolders_AfterSelect(null, tve);
				sizablePicture.Left = tvFolders.Width+2;
				Size theSize = new Size(this.Width - sizablePicture.Left, this.Height);
				ImageFunctions.ShowPicture(sizablePicture,  theSize, GetFullPath(tvFolders.SelectedNode.FullPath));
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Australia Australia
Frank has been in computing since the age of the dinosaurs. He prefers playing table tennis to writing C#, C++, VB, or any of the other dozen or more languages he has written since the Jurasic.

Comments and Discussions