Как стать автором
Поиск
Написать публикацию
Обновить

Организация коллекции изображений на основании данных EXIF. Пример на C#

Когда на жестком диске лежит около 10 ГБ отснятых разными аппаратами цифровых фотографий, разложить все это по полочкам не так уж просто.
Конечно, наверняка существуют платные и бесплатные приложения, помогающие разложить фотографии по папкам на основании данных о дате съемки, но для моих требований оказалось проще написать небольшую консольную программу на C#, почти скрипт.

Исходил из следующего:
1. Все фотографии разложены в папки по годам и месяцам (попытки навести порядок предпринимались неоднократно). Необходимо чтобы структура папок была сохранена.
2. Фотографии в папках некорректно отсортированы, т.к. снимал двумя телефонами и двумя фотоаппаратами, у каждого свой формат именования файла. Необходимо переименовать файлы так, чтобы сортировка по имени была сразу же сортировкой по дате, камере. Для надежности, сохранить старое имя файла.

Таким образом, нужно чтобы, файл, например, D:\Pictures\2008-03\11032008.jpg был скопирован в D:\Pictures New\2008-03\20080311 08.26.37 Nokia 5800 Xpres 11032008.jpg

А старую папку пожму архиватором в архив.

Оказалось, что в .NET 3.5 есть удобные классы для чтения метаданных из файла.

В итоге, за небольшое время получается такой код:

using System;
using System.Linq;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media.Imaging;

namespace Exifer
{
  class Program
  {
    static void Main(string[] args)
    {
      var sourceDirectoryPath = string.Empty;
      var targetDirectoryPath = string.Empty;
      var mask = string.Empty;

      if (args.Length == 3)
      {
        sourceDirectoryPath = args[0];
        targetDirectoryPath = args[1];
        mask = args[2];
      }

      while (!Directory.Exists(sourceDirectoryPath))
      {
        Console.WriteLine("Source path:");
        sourceDirectoryPath = Console.ReadLine();
      }

      while (!Directory.Exists(targetDirectoryPath))
      {
        Console.WriteLine("Target path:");
        targetDirectoryPath = Console.ReadLine();
        if (!string.IsNullOrEmpty(targetDirectoryPath))
          Directory.CreateDirectory(targetDirectoryPath);
      }

      while (string.IsNullOrEmpty(mask))
      {
        Console.WriteLine("Mask:");
        mask = Console.ReadLine();
      }
      
      var pathes = GetFilesRecursive(sourceDirectoryPath, mask);

      foreach (var oldFilePath in pathes)
      {
        var fileStream = new FileStream(
          oldFilePath,    // path
          FileMode.Open,   // mode
          FileAccess.Read,  // access
          FileShare.Read);  // share

        var jpegBitmapDecoder = new JpegBitmapDecoder(
          fileStream,                 // bitmapStream
          BitmapCreateOptions.PreservePixelFormat,  // createOptions
          BitmapCacheOption.Default);         // casheOption

        var bitmapFrame = jpegBitmapDecoder.Frames.FirstOrDefault();

        var newFilePath = string.Empty;

        if (bitmapFrame != null)
        {
          var bitmapMetadata = jpegBitmapDecoder.Frames[0].Metadata as BitmapMetadata;

          if (bitmapMetadata != null)
          {
            if (!string.IsNullOrEmpty(bitmapMetadata.DateTaken))
              newFilePath += Convert.ToDateTime(bitmapMetadata.DateTaken)
                .ToString("yyyyMMdd HH.mm.ss");

            if (!string.IsNullOrEmpty(bitmapMetadata.CameraManufacturer))
              newFilePath += " " + bitmapMetadata.CameraManufacturer;

            if (!string.IsNullOrEmpty(bitmapMetadata.CameraModel))
              newFilePath += " " + bitmapMetadata.CameraModel;
          }
          
          newFilePath += " " + Path.GetFileNameWithoutExtension(oldFilePath);
        }

        newFilePath = oldFilePath
          .Replace(sourceDirectoryPath, targetDirectoryPath)
          .Replace(Path.GetFileName(oldFilePath), newFilePath + Path.GetExtension(oldFilePath));

        if (!Directory.Exists(newFilePath))
          Directory.CreateDirectory(Path.GetDirectoryName(newFilePath));

        File.Copy(
          oldFilePath,  // sourceFileName
          newFilePath,  // destFileName
          false);     // overwrite

        Console.WriteLine("{0} -> {1}", Path.GetFileName(oldFilePath), Path.GetFileName(newFilePath));
      }
      Console.ReadKey();
    }

    public static List<string> GetFilesRecursive(string path, string searchPattern)
    {
      var result = new List<string>();
      var stack = new Stack<string>();

      stack.Push(path);

      while (stack.Count > 0)
      {
        var directory = stack.Pop();
        result.AddRange(Directory.GetFiles(directory, searchPattern));
        foreach (var subdirectory in Directory.GetDirectories(directory)) stack.Push(subdirectory);
      }
      return result;
    }
  }
}

* This source code was highlighted with Source Code Highlighter.

Все 10 гигов обработало успешно.
Правда, в них были только файлы с расширением *.jpg, на других не проверял.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.