按EXIF + PHP中的数据对照片排序

我想分享我使用PHP脚本对照片进行排序的经验
有一瞬间,没有多少照片,但灾难性的是很多。

背景知识


有一天,我决定对我的整个数码照片档案库进行分类,这些档案库积累了20多年,并且意识到在这段时间内,我已经累积了112,000张照片(435 GB)。

此外,其中一些照片或多或少被排序,例如,单反相机中的照片按带有名称和日期的文件夹分类,而从iphone / android导入的照片的另一部分则没有命名和分类,通常只是一个巨大的文件夹10 GB,里面有成千上万个文件,很遗憾删除并整理出来。

我开始寻找自动分类工具,并意识到Google已经购买并关闭了Picasa之类的所有优质服务,您当然可以将所有内容上传到Google上,但是照片存在问题,并不是所有内容都被搜索到了,而且通常其中一半功能都缺失了放在Picasa中,并且如果您仍然担心照片会被识别和使用,则根本不希望将照片上传到网络。

结果,决定编写一个可以对所有内容进行排序的小脚本,起初我想到了一个shell脚本,但是意识到自己需要它,EXIF决定返回到旧的PHP。

任务1-按日期展开所有文件


首先,我采用最简单的方法,获取所有文件,查看创建日期并沿着嵌套路径进行分散:

$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); 

有几个问题:

  • 某些文件的创建日期不正确
  • 如果您要复制,则会在当前日期之前创建一个新文件。
  • 文件可以具有相同的创建时间重复项

问题编号2-从Exif获取日期


决定从EXIF中获取日期,重命名并触摸文件以从exif中设置日期,并使用md5检查文件是否重复。

原则上,PHP在库集中已经有一个exif扩展,因此没有预见到任何超自然现象

  $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()); 

一切都会好起来,在几个小时内对500 GB的照片进行了排序并清除了重复项,但是后来我想起了旧文件夹,其中包含拍摄照片的区域的名称,然后想一想,为什么不从地理数据中获取城市的名称?

任务№3-EXIF地理数据中的国家,城市和地区


坐标很容易在文件中找到,它们位于GPSLongitude和GPSLatitude中的Exif中,但是我们不能忘记它们以度,分和秒的形式存储在其中,因此您需要使用函数将坐标转换为十进制。

 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); } 

第二个问题,如何处理坐标,如何获得城市名称?
Yandex的Geocoder可以助您一臂之力,但请注意使用限制和使用条款。

 $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)); 

为了避免用数百万个查询杀死Yandex,我们将数据缓存在MySql中,将坐标四舍五入到小数点后三位,即43.161-19.182足以确定城市,因此,对于110,000张照片,我只有1500个几何图形。

文件夹的外观如下所示:

  • D:\ photos \ photos_exif \ Year2019 \ 2019-09-9 \ 2019-09-23-波斯尼亚和黑塞哥维那,斯普斯卡共和国,福卡\
  • D:\ photos \ photos_exif \ Year2019 \ 2019-08-八月\ 2019-08-25-Albania,Durres region,Kruja \
  • D:\ photos \ photos_exif \ Year2018 \ 2018-10- 10 \ 2018-10-06-俄罗斯,莫斯科地区,巴拉希哈\

而不是结论


实际上,如果您使用此产品,则可以使用数月之久,我花了一天的时间来编写脚本并优化照片的存储。

从计划中:将地理标签添加到现有照片中,对当前照片档案进行重新排序,在剪切的图像中查找重复项。

所有项目文件都可以在GitHub上找到

别打我,这是我的第一个完全开放源代码项目,如果张贴或编写的内容有误,请告诉我,现在所有使用1251编码的Windows运行时环境都被监禁了。

Source: https://habr.com/ru/post/zh-CN470009/


All Articles