---
author:
email: mail@petermolnar.net
image: https://petermolnar.net/favicon.jpg
name: Peter Molnar
url: https://petermolnar.net
copies:
- http://web.archive.org/web/20190624125547/https://petermolnar.net/how-to-build-an-exif-database-to-understand-your-photography/
lang: en
published: '2015-05-30T16:18:39+00:00'
summary: Some bits of code to get stats from the EXIF data from your photos.
tags:
- photography
title: How to build an EXIF database to understand your photography
---
I'm a linux user and Adobe had shut me out from their products - we
don't even have and official Flash nowadays - but I wanted to examine
which focal length, aperture, etc. I use the most in my photos. There is
a fair amount of them ( tens of thousands) so I needed something fast &
flexible. digiKam[^1] probably offers a solution for this, but it's a
bit too heavy for my taste, so I went for a different approach.
## exiftool[^2] {#exiftool1}
There is program, called exiftool which can eat nearly any kind for
image format, and it's pretty easy to use, even if it's a command line
utility.
To install it on Ubuntu, run `sudo apt-get install exiftool` On debian
it's `sudo apt-get install libimage-exiftool-perl`.
## Database
I could have used SQLite, which would make things pretty
straightforward, but I went with MySQL since I had one running on the
webserver. Note: for production things, use InnoDB, but writes can be
slow with that. Since I do mostly writes here and it is not critical at
all, I went with MyISAM.
``` {.sql}
CREATE TABLE `files` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fname` text NOT NULL, PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `exif` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ename` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
CREATE TABLE `data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fid` int(11) NOT NULL,
`eid` int(11) NOT NULL,
`value` text NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8
```
## The parser
Yes, I know, I should have given up PHP a long time ago, but I'm lazy.
``` {.php}
connect_error) exit('Database connection failed: ' . $conn->connect_error);
$SourceFile = $conn->real_escape_string($SourceFile);
echo "Checking existence of ${SourceFile}\n";
$sql="SELECT ID FROM files WHERE fname='${SourceFile}'";
$rs=$conn->query($sql);
// in case the file was parsed already, quit this execution
if($rs === false) exit('Wrong SQL: ' . $sql . ' Error: ' . $conn->error );
if ( $rs->num_rows > 0 ) exit ('File exists in db already');
// otherwise insert it into the files db
$sql = "INSERT INTO files (fname) VALUES('${SourceFile}')";
if($conn->query($sql) === false) exit ('Wrong SQL: ' . $sql . ' Error: ' . $conn->error );
$fid = $conn->insert_id;
echo "\tStarting inserting values for ${SourceFile}\n";
foreach ( $exif as $key => $value ):
// I don't want to store every exif parameter name every time
// so the parameter names are in a separate table
$key = $conn->real_escape_string($key);
$sql = "SELECT id FROM exif WHERE ename='${key}' LIMIT 1";
$rs=$conn->query($sql);
if($rs === false) exit('Wrong SQL: ' . $sql . ' Error: ' . $conn->error );
if ( $rs->num_rows > 0 ) {
$arr = $rs->fetch_all(MYSQLI_ASSOC);
$eid = $arr[0]['id'];
}
else {
echo "\tadding new exif param: ${key}\n";
$sql = "INSERT INTO exif (ename) VALUES('${key}') ";
if($conn->query($sql) === false) exit ('Wrong SQL: ' . $sql . ' Error: ' . $conn->error );
$eid = $conn->insert_id;
}
// adding the exif value itself
if (is_array($value) || is_object($value)) $value = json_encode($value);
$value = $conn->real_escape_string($value);
$sql = "INSERT INTO data (fid, eid, value) VALUES('${fid}','${eid}','${value}')";
if($conn->query($sql) === false) exit ('Wrong SQL: ' . $sql . ' Error: ' . $conn->error );
endforeach;
echo "\t${SourceFile} added to the DB\n";
```
## Glue it together
Replace \*.jpg with whatever files you want to search for and there is
an -iregex option to use regex to match patterns.
``` {.bash}
cd directory/of/photos
find . -iname *.jpg -exec bash -c "/usr/bin/exiftool -json '{}' | php /path/to/exifdb.php" \;
```
## Getting results
``` {.sql}
# Your most commonly used focal lengths:
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`192.168.%` SQL SECURITY DEFINER VIEW `top_10_focallength` AS select `data`.`value` AS `value`,count(0) AS `count` from `data` where (`data`.`eid` = (select `id` from `exif` where (`ename` = 'FocalLength'))) group by `data`.`value` order by `count` desc limit 10;
# Your most commonly used aperture:
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`192.168.%` SQL SECURITY DEFINER VIEW `top_10_aperture` AS select `data`.`value` AS `value`,count(0) AS `count` from `data` where (`data`.`eid` = (select `id` from `exif` where (`ename` = 'Aperture'))) group by `data`.`value` order by `count` desc limit 10;
# Your lens:
CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`192.168.%` SQL SECURITY DEFINER VIEW `lens` AS select `data`.`value` AS `value`,count(0) AS `count` from `data` where (`data`.`eid` = (select `id` from `exif` where (`ename` = 'LensID'))) group by `data`.`value` order by `count` desc;
```
And of course, any other query you can think about.
[^1]:
[^2]: