Friday, July 25, 2008

Lazy Folders revisited (C#)

Now then, following yesterday's post (and I can't promise that they'll all be every day like this!) I spent some more time with the code and put it into use on my vista machine (the main home system with all the duplicate files). It does work rather wonderfully, but I'm not quite done with the updates and modifications yet...

I spent some time working with the photo resizing and tried two main things - the first was an attempt to make the photo display work a little faster. There are two ways to put a photo in a picture box (that I know of anyway) - by loading it into the memory as an Image filetype and assigning it to the pictureBox.Image property, or by directly dropping the file into the pictureBox using the pictureBox.ImageLocation property. I figured that dropping it into the pictureBox with the ImageLocation property might be a little faster since its not going through the extra step of loading it into the memory first before displaying it.

I was wrong! The pictureBox.Image property was the faster way - by a noticable margin. I know I don't have the perfect testing environment set up, but I'm pretty confident since I was using 2Mb pictures and there was an appreciable difference in load times within the application. I may also test reducing the resolution on the loaded image (since I'm dropping it into a much smaller box than the original file size) versus leaving it alone for additional speed - but that will have to come later.

Then I played with the resizing logic and came up with this doosy:


decimal ratio = (Convert.ToDecimal(previewImage.Width) / Convert.ToDecimal(previewImage.Height));
int ySize = 279;
int xSize = Convert.ToInt32(ySize * ratio);

if (xSize > 279)
{
xSize = 279;
ySize = Convert.ToInt32(xSize / ratio);
}


Then simply assigning the xSize to the width and ySize to the height properties of the pictureBox. Basically, this function attempts to keep the height of the image at 279 pixels with correct scaling of width. If the width is greater than 279 after the ration adjustment, it does it again leaving the width 279 and ratio adjusting the height. This may be slightly faster if I evaluate the original height and width of the image and perform the ration adjustment just once, but I think this is a little more readable and fast enough for these purposes.

One other conundrum I worked through yesterday was how to pop the previewed image in the pictureBox into a Windows Picture and Fax Viewer window. This came reasonably quickly after some internet searches, but noone really had the whole solution, so I had to finagle it myself! The basic premise uses the System.Diagnostics.Process collection (referenced in the using section as System.Diagnostics) to run a command line with some Arguments following a click on the pictureBox:


string fileLoc = this.folderBrowserDialog2.SelectedPath.ToString() + @"\" + listBox3.SelectedItem.ToString();
Process proc = new Process();
proc.StartInfo.FileName = @"rundll32.exe";
proc.StartInfo.Arguments = @"C:\WINDOWS\System32\shimgvw.dll,ImageView_Fullscreen "+ fileLoc;
proc.Start();


I had discovered with the internet searches that the Windows Picture and Fax Viewer was actually a function built into another program in Windows rather than another program entirely. I found that using a single entry in the StartInfo.fileName propery including the arguments would return a file not found error. Adding them into the StartInfo.Arguments property made it work!

I am now working on reading the EXIF data to give a little more information on the image that is being previewed - more to come on that! I'll also be adding in support for additional filetypes starting with either MP3 or MPG.

Labels: , , , , , , , ,

Thursday, July 24, 2008

First Post - Lazy Folders (C#)

Hello There!

Another blog in the family of Adam's Blogs is here to blog about the code I write in my spare time! I do not consider myself and expert - let me state that up-front. I am a skilled amateur, I have yet to hit a coding problem that I haven't been able to solve, I like pie - but I am far from a professional!

That said, let's move on...

I've recently been consolidating several old hard drives and their information and find myself with more data on hand than the INS after a tightening of border control. Most of this data is duplicated in other folders and I've gotten tired of scanning by eye and picking out the photos, movies and MP3s that I need to save. So, being the "Productively Lazy" (tm) individual that I am, I've put my mind to creating a program to do it all for me.

I am coding in C# (a recent discovery for me after coding for years with PHP and HTML) in a .NET environment for both XP and Vista. Once I'm "done" (because you're never really done are you?) I may get ambitious and try to port it over to the mac.

The basic premise is this: a program that will look at the contents of two folders (henceforth and everymore to be known as "master folder" and "copy-from folder") and copy across the appropriate, non-duplicated files.

That is the core of the idea.

I've accomplished this basic premise, but have found that using the DirectoryInfo GetFiles() method will only allow a single file extension to be pulled. So, I work around the issue like a Democrat at a Republican convention, and coded a quick method of my own (read: assembled pieces I found online) to call instead, referencing an Application Setting that stores desired extensions in a pipe-delimited string:



private FileInfo[] PullFiles(string folderName)
{
DirectoryInfo dI = new DirectoryInfo(folderName);
ArrayList fiTemp = new ArrayList();
string[] imageString = Properties.Settings.Default.Images.Split('|');
foreach (string str in imageString)
{
fiTemp.AddRange(dI.GetFiles(str));
}
FileInfo[] fiTotal = (FileInfo[])fiTemp.ToArray(typeof(FileInfo));
return fiTotal;
}


Now I can simply pass the folder name to the method and it pulls all of the file extensions stored in the "Images" Setting. Easy huh? Took me about an hour to figure out all of the pieces including the casting of the ArrayList to FileInfo type before returning it... Told you I wasn't a professional!

The current incarnation compares the contents of the copy-from folder against the master folder and creates a list of un-duplicated files in a listbox that would be copied across once you click the "copy" button (after confirmation of course!).

Along the way, I came up with additional enhancements and actually enacted a few of them. The program is now able to preview the images once you select them in the listbox with appropriate scaling of the image to fit in the box provided. I'm working on enhancing this a little further, but for now it reads:


string foldername = this.folderBrowserDialog2.SelectedPath;
Image previewImage = Image.FromFile(foldername + "\\" + listBox3.SelectedItem.ToString());
decimal ratio = (Convert.ToDecimal(previewImage.Width) / Convert.ToDecimal(previewImage.Height));
int ySize = 200;
int xSize = Convert.ToInt32(ySize * ratio);
pictureBox1.Image = previewImage;
pictureBox1.Height = ySize;
pictureBox1.Width = xSize;


I've also got the program switching between displaying the non-duplicates in the folder to displaying the duplicates with a radio button.

To come: additional format support for movies and mp3s, better handling of the image previews, inclusion of the EXIF data where available, and optional functions to delete the copy-from folder when complete.

I'll be fiddling with this for a while, but will eventually go back to the first of my series of "Productively Lazy" (tm) products - the Lazy Timecard!

Labels: , , , , , , , , ,