Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Photo Selector is a C# Program for Selecting Keeper Photographs from your Camera or Memory Card

0.00/5 (No votes)
20 Jan 2016 1  
In this article I will show how simple programs can help improve your photography work flow. It simplifies the first step of selecting which images on your memory card or camera are worth processing. It uses a replacement for the PictureBox control that displays photographs and allows them to be zoo

Introduction

Photo Selector is a simple image processing program designed to simplify the process of selecting and copying JPG and RAW photographs from external media to a working folder on your hard drive. You need to shoot JPG or JPG + RAW to use this program.

Background

I take a lot of photographs using my digital cameras. When I get home from a photo shoot, I might have 500 photographs to sort through. I used to copy them all to my picture folder for the month. The problem was I never got around to deleting the duds. To fix this issue, I started using Windows Photo Viewer to scan through the photos on my memory card. I'd write down the numbers of the photos worth processing and then move the selected few to my hard drive. "Write down numbers"? Nobody should have to write down numbers. So, I devised a fairly simple software solution. My solution lets you review the photos on your memory card (or equivalent), zoom and pan, to check focus and sharpness, and then copy the keepers to a designated folder on your hard drive. While my program is limited to displaying JPG images, it knows to transfer RAW images to a designated working folder.

I'm indebted to Code Project contributor Lev Danielyan for his EXIF metadata extraction library and to Bob Powell for his ZoomPicBox control.

Displaying Images

The program uses Bob Powell's ZoomPicBox control to display images. The control provides smooth panning and zooming. I added code to Dispose the Image to ensure Image deletion worked. This is the method that displays an image.

private void ShowImage()
{
   this.Text = "Photo Selector - " + _SourceImageFile;
   LoadExifInto(_SourceImagePath);
   Bitmap image = new Bitmap(_SourceImagePath, true);
   zoomPic.Image = RotateImage(image);
   this.trkZoom.Value = 20;
   this.zoomPic.Zoom = 0.01f * this.trkZoom.Value;
}

The "Orientation" tag in the EXIF tag is used to determine the orientation of the photograph. RotateImage uses a standard .Net method to rotate the image, if required. Note that the orientation of the image file is not changed. The rotation is to ensure the photograph is displayed with the correct orientation.

Zooming is accomplished with a one line event handler.

private void trkZoom_ValueChanged_1(object sender, EventArgs e)
{
    this.zoomPic.Zoom = 0.01f * this.trkZoom.Value;
}

Panning is handled using the MouseDown, MouseMove and MouseUp events on the ZoomPicBox.

private void zoomPic_MouseDown(object sender, MouseEventArgs e)
{
   if (e.Button == System.Windows.Forms.MouseButtons.Left)
   {
      _MouseDown = true;
      clickPosition.X = e.X;
      clickPosition.Y = e.Y;
   }
}
private void zoomPic_MouseMove(object sender, MouseEventArgs e)
{
   if (_MouseDown)
   {
      Cursor = Cursors.Hand;
      scrollPosition.X = clickPosition.X - e.X - lastPosition.X;
      scrollPosition.Y = clickPosition.Y - e.Y - lastPosition.Y;
      zoomPic.AutoScrollPosition = scrollPosition;
   }
}
private void zoomPic_MouseUp(object sender, MouseEventArgs e)
{
   Cursor = Cursors.Default;
   lastPosition.X = zoomPic.AutoScrollPosition.X;
   lastPosition.Y = zoomPic.AutoScrollPosition.Y;
   _MouseDown = false;
}

EXIF Data

The user can see the EXIT data displayed in a simple DataGrid. To avoid showing too much infomation, I exclude some tags.

Menu Options

File/Choose Initial Image

This menu item displays a dialog box that lets you choose the first JPG file of the set you want to process. It limits you to JPG files. You can choose any file, perhaps the first one in a particular shooting session. Once you select a JPG file, it will be displayed. You can zoom using the Zoom slider and pan by dragging the image with your mouse or using the scroll bars that appear when the image is zoomed.

Choose Raw Images Folder (if different from JPG Source Device Folder)

Some cameras allow you to use two different memory cards with the option of assigning one to JPG images and the other to RAW. Others may store the files in separate folders on the same memory card. When you choose your Initial (JPG) file, Photo Selector checks to see if a matching RAW file exists in the same folder. If so, it assumes that every JPG file in that folder will have a matching RAW file. If it does not find that RAW file, then it enables the menu option Choose Raw Images Folder (if different from JPG Source Device Folder). That lets you choose the folder where the matching RAW files are stored.

A problem arises if your computer only has one memory card slot or reader and your camera uses two cards. In this case, you copy the JPG files to a temporary folder on your hard drive, and choose a file there as your Initial Image. I suggest copying the JPG files instead of the RAW files as they are smaller. Either way works.

File/Choose Raw Images Folder

This menu item displays a dialog box that lets you choose the folder where you would like to store copies of RAW images. Typically, this would be a folder on your hard drive.

If you do not choose such a folder then Photo Selector will not save RAW files.

File/Choose JPG Images Folder

This menu item displays a dialog box that lets you choose the folder where you would like to store copies of JPG images. Typically, this would be a folder on your hard drive.

Settings/Set Raw Extension

This menu item displays a dialog box that lets you set the extension that your camera uses for RAW files. The default is .ARW.

Tool Bar

If you click the Back button, the image file preceding the current image file will be displayed. If you are at the first image then the last image will be displayed.

If you click the Forward button, the image file following the current image file will be displayed. If you are at the last image then the first image will be displayed.

If you click the Delete button, the current image file will be deleted, subject to a confirmation dialog. The RAW and JPG images are both deleted. Then the next image file will be displayed.

If you click Copy button, the current image will be copied to the selected target image folder(s). Then the next image file will be displayed.

If you click the EXIF button, the major EXIF tags for the current image file will be displayed.

Moving the slider will zoom in and out of the image. You will probably use this to check sharpness. If you click on the image and hold down the left mouse button, while you move the mouse, you can also pan the image.

Saving Images

The program checks for files with the same name when you copy an image file from the source folder to the target folder. You can get collisions because you already copied the file, or you copied files from a different memory card to the same target folder, or your camera cycled through its set of numbers.

If the program finds a collision, it checks if the files are the same length. If they are, it reads both files into memory and compares every byte. If the files truly are identical, it tells you so. Otherwise, it adds a number in parentheses to the file name using the same convention as Windows. This is the code used to read and compare files.

private bool FilesIdentical(string X, string Y)
{
   byte[] bX;
   byte[] bY;
   try {
      bX = ReadAll(new FileStream(X, FileMode.Open, FileAccess.Read));
      bY = ReadAll(new FileStream(Y, FileMode.Open, FileAccess.Read));
   }
   catch (Exception ex) {
      throw ex;
   }
   for (int i = 0; i < bX.Length; i++) {
      if (bX[i] != bY[i]) {
         return false;
      }
   }
   bX = null;
   bY = null;
   return true;
}
public static byte[] ReadAll(FileStream fileStream)
{
   MemoryStream m = new MemoryStream();
   fileStream.CopyTo(m);
   fileStream.Close();
   fileStream.Dispose();
   return m.ToArray();
}

Other file comparison methods read a byte at a time from each file until they find a mis-match. That method would be faster than reading the whole file if you expect the files not to match. However, when two files are the same size and have the same name, it is highly likely they are identical. In that case, the technique I used is probably just as fast.

Help

I created a help file using Microsoft Word and saved it as a PDF file. The Help file is displayed when the Help button is clicked.

Using the code

This code uses intermediate C# coding techniques. It could serve as a starting point for applications that process photographs because it allows images to be displayed, zoomed and panned. It also illustrates how to get EXIF data and how to rotate photographs to the correct orientation.

As a photographer, I found this program improved my work flow and stopped me from saving unwanted photographs to my hard drive.

Points of Interest

The program demonstrates how to display, zoom and pan images using Bob Powell's ZoomPicBox control. It also demonstrates how to use Lev Danielyan's EXIF metadata extraction library. The byte-by-byte file comparison method is reusable. The program helps me sort through the photographs on my memory cards and decide which are "keepers".

History

First Version for Code-Project

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here