Quiero compartir mi experiencia en ordenar fotos usando un script en PHP
Llega un momento en que no hay muchas fotografías, pero catastróficamente muchas.
Antecedentes
Un día decidí ordenar todo mi archivo de fotos digitales, acumulado durante 20 años, y me di cuenta de que en todo ese tiempo había acumulado 112,000 fotos a 435 gigabytes.
Además, algunas de ellas están más o menos ordenadas, por ejemplo, fotos de una cámara réflex, por carpetas con nombres y fechas, y la otra parte de las fotos que se importaron desde iphone / android no se nombran ni se ordenan, a menudo es solo una carpeta gigante 10 gigabytes, con un par de miles de archivos dentro, y es una pena eliminarlos y ordenarlos.
Comencé a buscar herramientas de clasificación automática y me di cuenta de que todos los buenos servicios, como Picasa, ya habían sido comprados y cerrados por Google, por supuesto, puede cargar todo en Google. Las fotos, sin embargo, tienen problemas allí, no se buscan todas y generalmente faltan la mitad de las funciones estar en Picasa, y si todavía te preocupa que tus fotos sean reconocidas y utilizadas, subir a la web no es lo tuyo.
Como resultado, se decidió escribir un pequeño script que clasificaría todo, al principio pensé en un script de shell, pero al darme cuenta de que lo necesitaría, EXIF decidió volver al buen PHP antiguo.
Tarea No. 1: expandir todos los archivos por fechas
Primero, fui por el camino más simple, tomé todos los archivos, vi la fecha de creación y los dispersé por las rutas anidadas:
$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);
Hubo varios problemas:
- Algunos archivos tenían una fecha de creación incorrecta
- Si copia, la fecha actual crea un nuevo archivo.
- Los archivos pueden tener duplicados con el mismo tiempo de creación
Problema número 2: obtenga la fecha de Exif
Se decidió tomar la fecha de EXIF, cambiar el nombre y tocar los archivos para establecer la fecha de exif, y también verificar los archivos en busca de duplicados usando md5.
En principio, PHP ya tiene una extensión exif en el conjunto de la biblioteca, por lo que no se previó nada sobrenatural
$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());
Todo estaría bien, se ordenaron 500 gigabytes de fotos y se eliminaron los duplicados en un par de horas, pero luego recordé las viejas carpetas que contenían el nombre de la región donde se realizó la sesión de fotos y pensé, ¿por qué no obtener los nombres de las ciudades de los geodatos?
Tarea №3 - Países, ciudades y regiones de geodatos EXIF
Las coordenadas son fáciles de encontrar en los archivos, están en Exif en GPSLongitude y GPSLatitude, pero no debemos olvidar que están almacenadas allí en grados, minutos y segundos, por lo que debe usar las funciones para convertir las coordenadas a decimales.
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 segunda pregunta, ¿qué hacer con las coordenadas, cómo obtener el nombre de la ciudad?
El geocodificador de Yandex viene al rescate, pero tenga cuidado con los límites y los términos de uso.
$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));
Para no matar a Yandex con millones de consultas, almacenamos datos en caché en MySql, redondeando las coordenadas a 3 decimales, es decir, 43.161 - 19.182 es suficiente para determinar la ciudad, y por lo tanto, para 110,000 fotos obtuve solo 1,500 geometrías.
La apariencia de las carpetas es algo como esto:
- D: \ photos \ photos_exif \ Year2019 \ 2019-09-September \ 2019-09-23-Bosnia y Herzegovina, Republika Srpska, Foca \
- D: \ photos \ photos_exif \ Year2019 \ 2019-08-agosto \ 2019-08-25-Albania, región de Durres, Kruja \
- D: \ photos \ photos_exif \ Year2018 \ 2018-10-October \ 2018-10-06-Rusia, Región de Moscú, Balashikha \
En lugar de una conclusión
De hecho, si toma este producto, puede hacerlo durante meses, me llevó un día escribir un guión y optimizar el almacenamiento de fotos.
De los planes: agregar etiquetas geográficas a las fotos existentes, volver a ordenar el archivo actual de fotos, encontrar duplicados entre las imágenes recortadas.
Todos los archivos de proyecto están disponibles en GitHubNo me pegue duro, este es mi primer proyecto de código abierto, si algo se publica o escribe incorrectamente, dígame, y ahora todo está encerrado para el entorno de ejecución de Windows con codificación 1251.