Raw Code - Picture Renaming and Sorting
2018-04-30 10:26
A while back I needed to rename a bunch of pictures, prefixing them with numbers, so that they'd sort the way I wanted.
Here's the code I used. I ran this in LINQPad, but you could use it in a console app with minor modifications. One nice thing I learned to do: get image datetime without loading the whole image.
Hope this is useful to you in some way!
void Main()
{
string path = @"C:\Users\charles\Pictures\Inbox\20160630";
List<FileChange> list = new List<UserQuery.FileChange>();
foreach (string fileName in Directory.GetFiles(path))
{
DateTime taken;
try
{
taken = GetDateTakenFromImage(fileName);
}
catch
{
try
{
taken = GetDateTakenFromFilename(fileName);
}
catch
{
taken = File.GetLastWriteTime(fileName);
if (File.GetCreationTime(fileName) < taken) { taken = File.GetCreationTime(fileName); }
}
}
FileChange item = new FileChange(fileName, "", taken);
//set new taken on to old.
item.NewTakenOn = item.OldTakenOn;
list.Add(item);
}
//sort and set new name
int newNbr = 1;
foreach (var item in list.OrderBy(l => l.OldTakenOn))
{
item.DestinationFileName = GetNewFileName(item.SourceFileName, newNbr);
newNbr++;
}
DumpList(list.OrderBy(l => l.OldTakenOn).ToList());
DumpList(list.OrderBy(l => l.NewTakenOn).ToList());
//rename
list.ForEach(a => File.Move(a.SourceFileName, a.DestinationFileName));
}
public static void DumpList(List<FileChange> list)
{
var newList = list
.Select(l => new { oldName = Path.GetFileName(l.SourceFileName), newName = Path.GetFileName(l.DestinationFileName), l.OldTakenOn, l.NewTakenOn });
newList.Dump();
}
//http://stackoverflow.com/questions/180030/how-can-i-find-out-when-a-picture-was-actually-taken-in-c-sharp-running-on-vista
//we init this once so that if the function is repeatedly called
//it isn't stressing the garbage man
private static Regex r = new Regex(":");
//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Image myImage = Image.FromStream(fs, false, false))
{
//if (!myImage.PropertyIdList.Any(a => a == 36867)){ return DateTime.Parse("1/1/1900");}
PropertyItem propItem = myImage.GetPropertyItem(36867);
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
//string t = Encoding.UTF8.GetString(propItem.Value);
return DateTime.Parse(dateTaken);
}
}
public static DateTime GetDateTakenFromFilename(string path)
{
var takenPartSplit = path.Substring(3, 15).Split('_');
string datePart = takenPartSplit[0];
string timePart = takenPartSplit[1];
datePart = datePart.Substring(0, 4) + "-" + datePart.Substring(4, 2) + "-" + datePart.Substring(6, 2);
timePart = timePart.Substring(0, 2) + ":" + timePart.Substring(2, 2) + ":" + timePart.Substring(4, 2);
string datetime = datePart + " " + timePart;
return DateTime.Parse(datetime);
}
public static string GetNewFileName(string path, int newNumber)
{
string oldName = Path.GetFileName(path);
string newName = oldName;
newName = newNumber.ToString().PadLeft(3, '0') + " " + newName;
return path.Replace(oldName, newName);
}
public class FileChange
{
public string SourceFileName { get; set; }
public string DestinationFileName { get; set; }
public DateTime OldTakenOn { get; set; }
public DateTime NewTakenOn { get; set; }
public FileChange(string source, string destination, DateTime takenOn)
{
SourceFileName = source;
DestinationFileName = destination;
OldTakenOn = takenOn;
}
}