fbpx

Dodawanie daty do nazwy zdjęcia

Opublikowane przez Jerzy Wickowski w dniu

Lubię robić zdjęcia. Jakiś czas temu stanąłem przed problemem uporządkowania archiwum zdjęć. Udało mi się to ogarnąć rozdzielając zdjęcia na odpowiedne katalogi. Problem natomiast się skomplikował w sytuacji, gdy zacząłem używać więcej niż jednego urządzenia do fotografowania. Uważam, że zdjęcia powinny być posortowane chronologicznie. Wpadłem zatem na pomysł, aby dopisywać datę i czas zrobienia zdjęcia, jako prefiks do każdej fotografii. Aby się nie napracować napisałem skrypt w powershellu. Jeżeli jesteś ciekawy jak on działa to zapraszam najserdeczniej.

Metadane

Aby móc automatycznie nazywać pliki, należy wyciągnąć informacje z metadanych. Ale czym one są? Każdy plik posiada informacje go opisujące. Mogą to być ogólne dane jak wielkość obrazu, data ostatniej modyfikacji, czy informacja o prawach autorskich. W przypadku plików muzycznych może to być informacja o wykonawcy, roku wydania, czy nazwie albumu. Natomiast w przypadku zdjęć może to być model aparatu, informacje o ekspozycji, ale i to co mnie najbardziej interesuje. Data wykonania zdjęcia.

Wyciąganie metadanych.

Skoro wiemy czym są metadane. Pozostaje zatem się do nich dobrać. Najbardziej uniwersalnym sposobem jest ręczne parsowanie nagłówka plików w celu poszukiwania metadanych. Gdyby wydajność i uniwersalność byłaby dla mnie, w tym przypadku, priorytetem to z pewnością poszedłbym w tę stronę. Jednak istnieje łatwiejsza opcja na początek. Mianowicie w windowsie istnieje biblioteka shell32.dll która pozwala na wydobycie metadanych z plików.

Naprawa metadanych

Skoro już mam wszystkie informacje o plikach to już powinno być z górki. Nic bardziej mylnego. O ile shell32.dll pozwolił mi na bardzo szybkie dobranie się do metadanych, to nie okazał się rozwiązaniem bez wad. Okazało się, że zwraca on dane zależne od ustawień regionalnych systemu operacyjnego. Co konkretnie mnie uderzyło? Już piszę.

  • Nazwy wartości metadanych są tłumaczone, zatem pole z datą zrobienia zdjęcia w polskim windowsie to 'Data wykonania', natomiast w angielskim to 'Data taken'.
  • Format daty również zależy od ustawień regionalnych. Aby odpowiednio sparsować datę należy wcześniej pobrać aktualne formaty.
  • Jeżeli rozszerzenia znanych plików są ukryte, to również zostaną one pominięte.
  • Dodatkowo data zawierała niewidoczne znaki, przez co była neparsowalna. Był to znak #8026, czyli Left-to-right[https://en.wikipedia.org/wiki/Left-to-right_mark].

Wszystkie te rzeczy zostały rozwiązane. Poniżej znajduje się kompletny skrypt, który u mnie działa :) i nazwy plików odpowiednio się zmieniają.
Zatem zapraszam do analizy kodu.

Kod

function Add-DataTakenToFilesName {
 param(
    [Parameter(Mandatory)]
    [string] 
    $Path)
	
  $filesMetadata = Get-FileMetaData -folder $Path
  foreach($fileMetadata in $filesMetadata)
  {
    $dateTaken = Get-DataTaken -fileMetadata $fileMetadata
    if (-not $dateTaken)
      {
        continue;
      }
       
    $fileName = Get-FileName -fileMetadata $fileMetadata

    if($fileName.StartsWith($dateTaken) )
    {
      continue
    }

    $filePath = Join-Path -Path $Path -ChildPath $fileName
    $newName = $dateTaken + ' - ' + $fileName 
    $newPath = Join-Path -Path $Path -ChildPath $newName

    Rename-Item -Path $filePath -newName $newName
  }
}

function Get-FileMetaData {
  Param([string]$folder)
  $a = 0
  $objShell = New-Object -ComObject Shell.Application
  $objFolder = $objShell.namespace($folder)

  foreach ($File in $objFolder.items())
  { 
    $FileMetaData = New-Object PSOBJECT
    for ($a ; $a  -le 266; $a++)
    { 
      if($objFolder.getDetailsOf($File, $a))
      {
        $hash += @{$($objFolder.getDetailsOf($objFolder.items, $a))  =
        $($objFolder.getDetailsOf($File, $a)) }
        $FileMetaData | Add-Member $hash
        $hash.clear() 
      }
    }  
    $a=0
    $FileMetaData
  }
} 

function Get-DataTaken {
  param ($fileMetadata)
  $rawDate = $fileMetadata.'Data wykonania'
  $rawDate = $rawDate -replace '[^a-zA-Z0-9 :.]', '' #remove non date format characters
  $datePattern = [System.Threading.Thread]::CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern;
  $timePattern = [System.Threading.Thread]::CurrentThread.CurrentUICulture.DateTimeFormat.ShortTimePattern;
  $pattern = "$datePattern $timePattern"
  $culture = [System.Globalization.CultureInfo]::InvariantCulture 

  $parsedDate = [DateTime]::ParseExact($rawDate, $pattern, $culture)

  $formatedDate = $parsedDate.ToString('yyyy.MM.dd HH-mm');
  $formatedDate 
}


function Get-FileName {
 param ($fileMetadata)
 $name = $fileMetadata.'Nazwa'
 $extenstion = Get-Extension -fileMetadata $fileMetadata
 if($name.EndsWith($extenstion) )
 {
   $name
  }
  $name = $name + $extenstion
  $name
}

function Get-Extension {
  param ($fileMetadata)
  $rawExtension= $fileMetadata.'Rozszerzenie Pliku'
  $rawExtension
}

Podoba się?
Takie podejście i ten skrypt bardzo uprościły mi proces segregacji i archiwizacji zdjęć. Mam nadzieję, że również dla Ciebie będzie przydatny. Jeżeli masz jakiekolwiek sugestie do skryptu to pisz. Chętnie podyskutuję i pomogę. Pozdrawiam serdecznie :).



Czy to był wartościowy artykuł? Zapisz się, a wyślę Ci dwa ebooki o czystym kodzie oraz będę informował Cię o nowych postach

0 Komentarzy

Dodaj komentarz

Twój adres email nie zostanie opublikowany.

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.


    Zapisz się

    Wyślę Ci dwa dokumenty mówiące o jakości kodu. Dodatkowo będę Cię informował o nowych postach i nowościach.