This shows you the differences between two versions of the page.
| Next revision | Previous revision | ||
|
script:powershell:multimedia:photo [2020/11/08 12:36] admin created |
script:powershell:multimedia:photo [2022/10/23 09:35] (current) admin [Organiser ces photos avec la lecture de l'exif] |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== PowerShell et la photo ====== | ====== PowerShell et la photo ====== | ||
| - | Déplacer les fichiers par date vers un autre dossier | + | ===== Organiser ces photos avec la lecture de l'exif ===== |
| + | L'EXIF, c'est un format de fichier utilisé pour les images prises par un appareil photographique numérique, la première version de l'Exif date de 1995.\\ **C'est une mine d'or pour organiser ces photos.**\\ Je suis tombé sur le travail de **Jon Gallant**, [[https://blog.jongallant.com/2021/03/organize-photos-powershell/|sur son blog ]], depuis je n'utilise que ce script.\\ Attention pour les utilisateurs de la suite Adobe, on est loin des capacités d'un [[https://helpx.adobe.com/camera-raw/using/navigate-open-save-images-camera.html|Adobe Camera Raw]]. | ||
| + | <sxh powershell> | ||
| + | Param( | ||
| + | [string]$source, | ||
| + | [string]$dest, | ||
| + | [string]$format = "yyyy/MM_yyyy/dd_MM_yyyy" | ||
| + | ) | ||
| + | |||
| + | $shell = New-Object -ComObject Shell.Application | ||
| + | |||
| + | function Get-File-Date { | ||
| + | [CmdletBinding()] | ||
| + | Param ( | ||
| + | $object | ||
| + | ) | ||
| + | |||
| + | $dir = $shell.NameSpace( $object.Directory.FullName ) | ||
| + | $file = $dir.ParseName( $object.Name ) | ||
| + | |||
| + | # First see if we have Date Taken, which is at index 12 | ||
| + | $date = Get-Date-Property-Value $dir $file 12 | ||
| + | |||
| + | if ($null -eq $date) { | ||
| + | # If we don't have Date Taken, then find the oldest date from all date properties | ||
| + | 0..287 | ForEach-Object { | ||
| + | $name = $dir.GetDetailsof($dir.items, $_) | ||
| + | |||
| + | if ( $name -match '(date)|(created)') { | ||
| + | |||
| + | # Only get value if date field because the GetDetailsOf call is expensive | ||
| + | $tmp = Get-Date-Property-Value $dir $file $_ | ||
| + | if ( ($null -ne $tmp) -and (($null -eq $date) -or ($tmp -lt $date))) { | ||
| + | $date = $tmp | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | return $date | ||
| + | } | ||
| + | |||
| + | function Get-Date-Property-Value { | ||
| + | [CmdletBinding()] | ||
| + | |||
| + | Param ( | ||
| + | $dir, | ||
| + | $file, | ||
| + | $index | ||
| + | ) | ||
| + | |||
| + | $value = ($dir.GetDetailsof($file, $index) -replace "`u{200e}") -replace "`u{200f}" | ||
| + | if ($value -and $value -ne '') { | ||
| + | return [DateTime]::ParseExact($value, "g", $null) | ||
| + | } | ||
| + | return $null | ||
| + | } | ||
| + | |||
| + | Get-ChildItem -Attributes !Directory $source -Recurse | | ||
| + | Foreach-Object { | ||
| + | Write-Host "Processing $_" | ||
| + | |||
| + | $date = Get-File-Date $_ | ||
| + | |||
| + | if ($date) { | ||
| + | |||
| + | $destinationFolder = Get-Date -Date $date -Format $format | ||
| + | $destinationPath = Join-Path -Path $dest -ChildPath $destinationFolder | ||
| + | |||
| + | # See if the destination file exists and rename until we get a unique name | ||
| + | $newFullName = Join-Path -Path $destinationPath -ChildPath $_.Name | ||
| + | if ($_.FullName -eq $newFullName) { | ||
| + | Write-Host "Skipping: Source file and destination files are at the same location. $_" | ||
| + | return | ||
| + | } | ||
| + | |||
| + | $newNameIndex = 1 | ||
| + | $newName = $_.Name | ||
| + | |||
| + | while (Test-Path -Path $newFullName) { | ||
| + | $newName = ($_.BaseName + "_$newNameIndex" + $_.Extension) | ||
| + | $newFullName = Join-Path -Path $destinationPath -ChildPath $newName | ||
| + | $newNameIndex += 1 | ||
| + | } | ||
| + | |||
| + | # If we have a new name, then we need to rename in current location before moving it. | ||
| + | if ($newNameIndex -gt 1) { | ||
| + | Rename-Item -Path $_.FullName -NewName $newName | ||
| + | } | ||
| + | |||
| + | Write-Host "Moving $_ to $newFullName" | ||
| + | |||
| + | # Create the destination directory if it doesn't exist | ||
| + | if (!(Test-Path $destinationPath)) { | ||
| + | New-Item -ItemType Directory -Force -Path $destinationPath | ||
| + | } | ||
| + | |||
| + | robocopy $_.DirectoryName $destinationPath $newName /mov | ||
| + | } | ||
| + | } | ||
| + | </sxh> | ||
| + | |||
| + | ==== Lire des informations EXIF dans un fichier image ==== | ||
| + | <sxh powershell> | ||
| + | Function Get-Image | ||
| + | { | ||
| + | begin{ | ||
| + | [void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") |Out-Null | ||
| + | } | ||
| + | process{ | ||
| + | $fi=[System.IO.FileInfo]$_ | ||
| + | if( $fi.Exists){ | ||
| + | $img = [System.Drawing.Image]::FromFile($_) | ||
| + | $img.Clone() | ||
| + | $img.Dispose() | ||
| + | }else{ | ||
| + | Write-Host "File not found: $_" -fore yellow | ||
| + | } | ||
| + | } | ||
| + | end{} | ||
| + | } | ||
| + | |||
| + | Get-ChildItem -Path "F:\Wallpaper" -Filter *.jpg | ForEach-Object { | ||
| + | $image = $_ | Get-Image | ||
| + | New-Object PSObject -Property @{ | ||
| + | File = $_.name | ||
| + | Fullname = $_.Fullname | ||
| + | Height = $image.Height | ||
| + | Width = $image.Width | ||
| + | }; | ||
| + | } | ||
| + | </sxh> | ||
| + | ===== Effacer les dossiers vides ===== | ||
| + | |||
| + | <sxh powershell> | ||
| + | # Set to true to test the script | ||
| + | $whatIf = $false | ||
| + | # Remove hidden files, like thumbs.db | ||
| + | $removeHiddenFiles = $false | ||
| + | # Get hidden files or not. Depending on removeHiddenFiles setting | ||
| + | $getHiddelFiles = !$removeHiddenFiles | ||
| + | # Remove empty directories locally | ||
| + | Function Delete-EmptyFolder($path) | ||
| + | { | ||
| + | # Go through each subfolder, | ||
| + | Foreach ($subFolder in Get-ChildItem -Force -Literal $path -Directory) | ||
| + | { | ||
| + | # Call the function recursively | ||
| + | Delete-EmptyFolder -path $subFolder.FullName | ||
| + | } | ||
| + | # Get all child items | ||
| + | $subItems = Get-ChildItem -Force:$getHiddelFiles -LiteralPath $path | ||
| + | # If there are no items, then we can delete the folder | ||
| + | # Exluce folder: If (($subItems -eq $null) -and (-Not($path.contains("DfsrPrivate")))) | ||
| + | If ($subItems -eq $null) | ||
| + | { | ||
| + | Write-Host "Removing empty folder '${path}'" | ||
| + | Remove-Item -Force -Recurse:$removeHiddenFiles -LiteralPath $Path -WhatIf:$whatIf | ||
| + | } | ||
| + | } | ||
| + | # Run the script | ||
| + | Delete-EmptyFolder -path "E:\_Backup" | ||
| + | </sxh> | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ===== Déplacer les fichiers par date vers un autre dossier ===== | ||
| + | Je n'utilise plus cette version de script, je préfère utiliser le script avec l'utilisation des informations EXIF | ||
| <sxh powershell> | <sxh powershell> | ||
| $Destination = 'F:\Photos\' | $Destination = 'F:\Photos\' | ||
| Line 13: | Line 181: | ||
| } | } | ||
| </sxh> | </sxh> | ||
| - | |||
| - | |||