This is Part #1 of a multi-part series on a picture importer I am working on.
Picture Importer
I’m a (very) amateur photographer. I bought a simple DSLR camera (a Canon EOS REBEL T4i) a few years ago, and since then I’ve been the family photographer at various events. I find that I take a LOT of pictures (think about how many can fit on a 32GB memory card), but most of them just aren’t very good or I took 20 pictures of the same subject with the same framing, and I really don’t need to keep all 20 of them, just the best one or two.
There are a lot of good picture importing programs out there
I’m sure there are a lot of software packages available out there that can pull images off of a memory card or a camera connected via USB and copy them to your computer. Heck, a lot of them will even do what I want to do… but I guess I like the ability to have control over it.
Objectives
- Pull images off any random memory card / external storage device — Since I might get a different camera in the future, I don’t want to hard-code some kind of folder structure that is unique to a brand of camera. As a bonus side-effect, it will also work with any random USB thumb drive full of images — say, if someone else took the pictures and I want to add them to my library. This will also allow other people to use it, so, from a code re-use perspective, this is also a good thing.
- Place all images into a “vault” — I have a tendency to not want to throw anything away in the off chance that I might need it or want it later. Since disk space is relatively cheap these days, it doesn’t seem too bad to keep all of the images even if they aren’t the best ones.
- Only pull in new images — The images pulled from the memory card should be checked against ones already in the vault. There’s no sense in duplicating the images.
- Place images into a structured folder system — The easiest way for me to find images after I take them is to put them into a dated folder. Images that get placed into the vault should be placed into a folder matching the date the image was taken.
- Option to only save the good images into a different location — To start, this will just be a manual process. Eventually, I want to make this a WPF application that will make it easy to view the images and decide which ones to put into the “good images” folder and which ones to simply leave in the vault.
- Sync good images to OneDrive — Having pictures in the cloud makes it easy to share them whenever. There are a lot of different cloud services out there, but OneDrive is the one I’m most familiar with (and the one I’m already using).
First Step
To start, I’m just going to make a simple console application to pull the images off of a memory card or other external storage device.
Discovering Memory Cards
C# has a nice API for getting drive information from the system called DriveInfo. Calling the static method GetDrives() will provide an array of DriveInfo objects. DriveInfo has an enum of DriveType that we can use to filter to only removable devices.
[code language=”csharp”]
using System.IO;
function IEnumerable<DriveInfo> GetMemoryCards()
{
var drives = DriveInfo.GetDrives();
return drives.Where(d => d.DriveType == DriveType.Removable);
}
[/code]
A DriveInfo object also contains information about the maximum capacity of the drive, the used capacity of the drive, and the letter assigned to the drive. There might also be information about the actual name of the drive (if the flash drive was formatted with a name, for example). To make things a little bit easier to work with, I created a simple MemoryCard class the wrap around the DriveInfo object. The main reason for this is to override the ToString method so I can easily print out the names of the drives, but it also gives me the ability to put some additional stuff in there if I need it.
[code language=”csharp”]
public class MemoryCard
{
private DriveInfo Drive { get; set; }
public MemoryCard(DriveInfo driveInfo)
{
Drive = driveInfo;
}
public string DriveLetter { get { return Drive.Name; } }
public string Name
{
get
{
return string.IsNullOrWhiteSpace(Drive.VolumeLabel) ?
Drive.DriveType.ToString() : Drive.VolumeLabel;
}
}
public double Capacity
{
get
{
return Math.Round(BytesToGigaBytes(Drive.TotalSize), 2);
}
}
public double FreeSpace
{
get
{
return Math.Round(BytesToGigaBytes(Drive.TotalSize – Drive.AvailableFreeSpace), 2);
}
}
public double PercentFree
{
get
{
return Math.Round(100 * Math.Abs(1 – (double)FreeSpace / (double)Capacity), 2);
}
}
private double BytesToMegabytes(long bytes)
{
return Math.Round(((double)bytes / 1048576.0), 2);
}
private double BytesToGigaBytes(long bytes)
{
return Math.Round(((double)bytes / 1073741824.0), 2);
}
public override string ToString()
{
return $"{DriveLetter} – {Name} ({FreeSpace} GB\{Capacity} GB {PercentFree}% Free)";
}
}
[/code]
Now I can create a method to return the list of memory cards:
[code language=”csharp”]
private IEnumerable<MemoryCard> GetDriveInfo()
{
var drives = DriveInfo.GetDrives();
return drives.Where(d => d.DriveType == DriveType.Removable).Select(d => new MemoryCard(d));
}
[/code]
In the next post I will be building up the framework for choosing which memory card to target, finding the images, and copying them to the vault.