Trier les photos par données à partir d'EXIF + PHP

Je souhaite partager mon expérience dans le tri de photos à l'aide d'un script en PHP
Il arrive un moment où il n'y a pas beaucoup de photographies, mais catastrophiquement.

Contexte


Un jour, j'ai décidé de trier toutes mes archives de photos numériques, accumulées sur 20 ans, et j'ai réalisé que pendant tout ce temps, j'avais accumulé 112 000 photos à 435 gigaoctets.

De plus, certains d'entre eux sont plus ou moins triés, par exemple, des photos d'un appareil photo reflex, par dossiers avec des noms et des dates, et l'autre partie des photos qui ont été importées d'iphone / android ne sont pas nommées et triées, c'est souvent juste un dossier géant 10 gigaoctets, avec quelques milliers de fichiers à l'intérieur, et c'est dommage de le supprimer et de le trier.

J'ai commencé à chercher des outils de tri automatique et j'ai réalisé que tous les bons services, comme Picasa, avaient déjà été achetés et fermés par Google, bien sûr, vous pouvez tout télécharger sur Google. Photos, cependant, il y a des problèmes, pas tous sont recherchés et généralement la moitié des fonctions manquent dans être dans Picasa, et si vous avez toujours peur que vos photos soient reconnues et utilisées, le téléchargement sur le Web n'est pas du tout votre chemin.

En conséquence, il a été décidé d'écrire un petit script qui va tout trier, au début j'ai pensé à un script shell, mais réalisant que j'en aurais besoin, EXIF ​​a décidé de revenir au bon vieux PHP.

Tâche n ° 1 - Développer tous les fichiers par date


Tout d'abord, je suis allé de la manière la plus simple, prendre tous les fichiers, voir la date de création et disperser le long des chemins imbriqués:

$file_list = $files->getDirContents($config['photos.unsorted']); foreach ($file_list as $key => $value) { moveImageFile($value); } function moveImageFile($filename) { $dt= new DateTime(); $dt->setTimestamp(filectime($filename)); $start_path = $this->config['photos']; $year = $start_path."\Year".$dt->format('Y'); if (!is_dir($year)) mkdir($year); $month = $year."\\".$dt->format('Ym-F'); if (!is_dir($month)) mkdir($month); $path = $month."\\".$dt->format('Ym-d'); if (!is_dir($path)) mkdir($path); } $full_path = getUniqueFilename($filename, $path, $dt, 0); copy($filename, $full_path); 

Il y avait plusieurs problèmes:

  • Certains fichiers avaient une date de création incorrecte
  • Si vous copiez, un nouveau fichier est créé à la date actuelle
  • Les fichiers peuvent avoir des doublons avec le même temps de création

Problème numéro 2 - Obtenez la date d'Exif


Il a été décidé de prendre la date d'EXIF, de renommer et de toucher les fichiers pour définir la date d'exif, et également de vérifier les fichiers en double à l'aide de md5.

En principe, PHP a déjà une extension exif dans l'ensemble de bibliothèques, donc rien de surnaturel n'était prévu

  $dt = DateTime::createFromFormat('Y:m:d H:i:s', $exif['DateTime']); $start_path = $this->config['photos.exif']; $is_exif = true; if (md5_file($filename) == md5_file($full_path)) return false; rename($filename, $full_path); touch($full_path, $dt->getTimestamp()); 

Tout irait bien, 500 gigaoctets de photos ont été triés et supprimés des doublons en quelques heures, mais je me suis alors souvenu des anciens dossiers qui contenaient le nom de la région où la séance photo a eu lieu, et j'ai pensé, pourquoi ne pas obtenir les noms des villes à partir des géodonnées?

Tâche №3 - Pays, villes et régions des géodonnées EXIF


Les coordonnées sont faciles à trouver dans les fichiers, elles sont dans Exif dans GPSLongitude et GPSLatitude, mais nous ne devons pas oublier qu'elles y sont stockées en degrés, minutes et secondes, vous devez donc utiliser les fonctions pour convertir les coordonnées en décimales.

 function getGps($exifCoord, $hemi) { $degrees = count($exifCoord) > 0 ? $this->gps2Num($exifCoord[0]) : 0; $minutes = count($exifCoord) > 1 ? $this->gps2Num($exifCoord[1]) : 0; $seconds = count($exifCoord) > 2 ? $this->gps2Num($exifCoord[2]) : 0; $flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1; return $flip * ($degrees + $minutes / 60 + $seconds / 3600); } 

La deuxième question, que faire des coordonnées, comment obtenir le nom de la ville?
Geocoder de Yandex vient à la rescousse, mais attention aux limites et conditions d'utilisation.

 $url = "https://geocode-maps.yandex.ru/1.x/"; $apikey = require('../config/apikey.php'); $json = array( 'geocode' => $lon.",".$lat, 'kind' => 'locality', 'apikey' => $apikey, 'results' =>'1', 'skip' => '0', 'format' => 'json' ); $response = file_get_contents($url."?".http_build_query($json)); 

Afin de ne pas tuer Yandex avec des millions de requêtes, nous mettons en cache les données dans MySql, en arrondissant les coordonnées à 3 décimales, c'est-à-dire que 43,161 - 19,182 suffisent pour déterminer la ville, et donc pour 110 000 photos, je n'ai obtenu que 1 500 géométries.

L'apparence des dossiers ressemble à ceci:

  • D: \ photos \ photos_exif \ Année2019 \ 2019-09-septembre \ 2019-09-23-Bosnie-Herzégovine, Republika Srpska, Foca \
  • D: \ photos \ photos_exif \ Année2019 \ 2019-08-août \ 2019-08-25-Albanie, région de Durres, Kruja \
  • D: \ photos \ photos_exif \ Année2018 \ 2018-10-octobre \ 2018-10-06-Russie, région de Moscou, Balashikha \

Au lieu d'une conclusion


En fait, si vous prenez ce produit, vous pouvez le faire pendant des mois, il m'a fallu une journée pour écrire un script et optimiser le stockage des photos.

À partir des plans: ajouter des géotags aux photos existantes, trier à nouveau l'archive actuelle des photos, trouver des doublons parmi les images écrêtées.

Tous les fichiers de projet sont disponibles sur GitHub

Ne me frappez pas fort, c'est mon premier projet complètement open source, si quelque chose est publié ou écrit incorrectement, dites-le-moi, et oui maintenant tout est emprisonné pour le runtime Windows avec l'encodage 1251.

Source: https://habr.com/ru/post/fr470009/


All Articles