A NodeJS library & shell command to rename photos using their EXIF data. It can also be set to watch a directory and automatically process images copied to it.
To use it as a dependency in your Node project, install it locally using:
$ npm install exif-renamer --save
To use it as a command line tool, install it globally using:
$ npm install exif-renamer -g
var exifRenamer = require('exif-renamer')(opts);
exifRenamer.rename('path/to/image.file', '{{datetime "yyyy-mm-dd"}}_{{file}}', function(err, result) {
console.log((err) ? err : 'the file was renamed: ', result.processed.path);
});
$ exif-renamer -h
Usage:
exif-renamer [OPTIONS] [ARGS]
Options:
-c, --no_ctime do not use the filesystem creation time fallback if
no EXIF data is present (also sets require_exif=true)
-d, --dryrun run without performing filesystem changes
-e, --exif get the exif data for the specified image
-f, --filetypes STRING comma-separated list of file extensions to process
(jpg and jpeg are default)
-g, --glob STRING glob pattern to filter files for processing within a
target directory (overrides --recursive)
-l, --list list available template variables
-r, --recursive recursively process the specified directory
-t, --template [STRING]renaming template (Default is {{datetime}}_{{file}})
-w, --watch watch the specified directory for changes and
process automatically
-h, --help Display help and usage details
The following configuration options are available when using exif-renamer as a library (the default values are show below):
{
dryrun: false, // simulate processing without modifying the filesystem
fallback_ctime: true, // fallback to filesystem creation time if no EXIF DateTimeOriginal
require_exif: false, // fail if EXIF data is not found?
path_separator: '/', // the character used to separate paths in templates
formats: {
datetime: 'yyyymmdd-HHMMss', // default formatting for {{datetime}}
date: 'yyyymmdd', // default formatting for {{date}}
time: 'HHMMss' // default formatting for {{time}}
},
valid_extensions: ['jpg','jpeg','tiff'] // supported file extensions for processing
};
To update configuration, do the following:
var exifRenamer = require('exif-renamer');
exifRenamer.config.dryrun = true;
The #process and #rename methods accept a template
argument which is used to determine the new
filename for the renamed image. As the name might suggest, the template is a way for you to format
the filename using values present in the EXIF data.
exif-renamer uses Handlebars for templating, which allows you to easily access the image file metadata to construct just about any filename you could imagine, e.g.:
Prefix the filename with the default datetime format:
{{datetime}}_{{file}}
Prefix the filename with a custom datetime format (see dateformat):
{{datetime "yy-mm"}}_{{file}}
Move the image to a "YYYY-MM" directory:
./{{datetime "yyyy-mm"}}:{{file}}
Prefix the parent directory with the date:
../{{date}} {{dirname}}:{{file}}
Prefix the filename with the file extension and camera model:
{{EXT}}-{{exif.Model}}-{{file}}
Prefix the filename with the F-number:
F{{exif.FNumber}}-{{file}}
Some things to point out:
- The renaming pattern has the format
[<directory_pattern>:]<filename_pattern>
, where<directory_pattern>
is optional and defaults to the image's current directory. Absolute or relative paths can be used in the template. {{datetime}}
is currently the only metadata that supports additional formatting, via the dateformat module as mentioned above.- if a template variable is used that is not found in the image metadata, it is simply ignored and an empty string is used as a replacement.
It is possible to pass your own custom function rather than a handlebars template, giving you total control over the renaming process. Here is an example:
function dogeify(metadata) {
var dogeisms = ['very', 'wow', 'so', 'much'];
return [
dogeisms[Math.floor(Math.random() * dogeisms.length)],
'F' + metadata.exif.FNumber,
metadata.file
].join('_');
}
exifRenamer.process('path/to/image.file', dogeify, function(err, result) {
//...
});
The metadata available to your handlebar template or custom renaming function is a combination of the exif data generated by the exif-parser module, path information, and some other useful stuff:
{
// EXIF data
'exif': <see: https://github.com/bwindels/exif-parser/blob/master/lib/exif-tags.js>,
'gps': <see: https://github.com/bwindels/exif-parser/blob/master/lib/exif-tags.js>,
// path information
'path': <the absolute path to the image>,
'file': <the image filename with extension>,
'name': <the image filename without extension>,
'dir': <the directory path>,
'dirname': <the directory name>,
'ext': <the lowercase image extension>,
'EXT': <the uppercase image extension>,
'stat': <see: http://nodejs.org/api/fs.html#fs_class_fs_stats>,
// other useful stuff
'datetime': <EXIF date or filesystem creation time>,
'date': <EXIF date formatted using the value of config.formats.date>,
'time': <EXIF time formatted using the value of config.formats.time>
}
You can view all the available template variables by using the -l
command-line switch.
Returns the EXIF data for an image.
filepath
the path to the image filecallback
the node-style callback that will receive the response
exifRenamer.exif('path/to/image.file', function(err, exifdata) {
//...
});
Returns an object containing the renaming outcome for the specified image, but does not actually rename the image (see #rename for this).
filepath
the path to the image filetemplate
the renaming template or a custom callback functioncallback
the node-style callback that will receive the response
// using a handlebars template
exifRenamer.process('path/to/image.file', 'renaming-template', function(err, result) {
//...
});
// using a custom function
exifRenamer.process('path/to/image.file', customRenamer, function(err, result) {
//...
});
Renames/moves the specified image using the provided template/callback.
filepath
the path to the image filetemplate
the renaming template or a custom callback functioncallback
the node-style callback that will receive the response
// using a handlebars template
exifRenamer.rename('path/to/image.file', 'renaming-template', function(err, result) {
//...
});
// using a custom function
exifRenamer.rename('path/to/image.file', customRenamer, function(err, result) {
//...
});
Renames/moves all applicable images in the specified directory, using the provided template/callback.
dirpath
the path to the directorytemplate
the renaming template or a custom callback function[recursiveOrGlob=false]
boolean switch to enable recursive processing, defaults to false. Since 1.2.0, it can also accept a glob pattern which is applied to the target directory. Some examples:'**'
is the equivalent oftrue
'*'
is the equivalent offalse
**/*.jpg
would recursively select only.jpg
files*.tiff
would non-recursively select only.tiff
files
[callback]
the node-style callback called once all files have been processed[itemCallback]
the node-style callback called after each file is processed
// using a handlebars template
exifRenamer.rename_dir('path/to/dir', 'renaming-template', function(err, result) {
//...
});
// using a custom function
exifRenamer.rename_dir('path/to/dir', customRenamer, function(err, result) {
//...
});
Watches a specified directory, renaming all images that are added to that directory.
dirpath
the path to the watch directorytemplate
the renaming template or a custom callback functioncallback
the node-style callback that will be called each time a file is detected & processed
exifRenamer.watch('path/to/watch/dir', 'renaming-template', function(err, result) {
//...
});
This software is free and open source and maintained by just one guy who has a day job. If you have a feature request or bug report please open an issue on GitHub or discuss it on Gitter.
If you are a developer please feel free to get involved and send a pull request with your enhancements or bugfix.
- Swap out Grunt for Gulp
- 1.2.2
- Updated dependencies
- 1.2.1
- Updated dependencies
- 1.2.0
- Introduced filename conflict resolution via sequential filenaming in response to #9
- Fixed incorrect calculation of modified time on some systems #10
- Deprecated the
--overwrite
flag - Added support for passing globs to
rename_dir
, exposed via the--glob
cli flag. This option will override--recursive
and allow for greater control of file processing (thanks to @TotallyInformation for the suggestion). - Reduced size of test/demo images
- Upgraded most dependencies
- Swapped out Grunt-based tooling for npm scripts
- 1.1.2
- switched back to fixed
[email protected]
dependency - added test for alternate date parsing
- fixed
npm run test
task
- switched back to fixed
- 1.1.1
- updated incorrect docs [fixed #8]
- 1.1.0
- Added the
-l
command line switch to list metadata, in response to #7
- Added the
- 1.0.0
- No changes from 0.7.0, which was a good RC for 1.0.0
- 0.7.0
- Fixed #3:
#rename_dir
now takes anitemCallback
which is called after each file is processed
- Fixed #4:
- Improved logging and error handling
- improved readability of cli output reporter
- Fixed #5:
- Replaced the EXIF parsing library from exif to
exif-parser to fix issues with date
parsing. This does however change the structure of the metadata object used in
templating (all EXIF tag values now exist within the
exif
andgps
keys only).
- Replaced the EXIF parsing library from exif to
exif-parser to fix issues with date
parsing. This does however change the structure of the metadata object used in
templating (all EXIF tag values now exist within the
- Other improvements:
require_exif
config option now defaults to false-c
cli switch will now also setrequire_exif
to true
- Fixed #3:
- 0.6.1
- fixed dylansmith#1
- 0.6.0
- changed the way the target directory is specified in renaming templates, since the current
approach flattens relative paths when doing recursive renaming. The renaming template now
requires the directory and filename to be separated by a colon, e.g.:
[<directory_template>:]<filename_template>
(the directory is optional and defaults to the source image's directory). - Added TIFF support by default
- changed the way the target directory is specified in renaming templates, since the current
approach flattens relative paths when doing recursive renaming. The renaming template now
requires the directory and filename to be separated by a colon, e.g.:
- 0.5.0
- added mocha specs with instanbul coverage reports
- altered some method signatures
- methods are no longer wrapped with Q internally
- much refactor, so bugfix, wow
- 0.4.0 - added explicit template pathing (breaking changes), overwrite protection, and refactoring
- 0.3.0 - added #rename_dir with recursive option, ctime fallback and a shell interface (commit)
- 0.2.0 - introduced handlebars-based templating (commit)
- 0.1.0 - initial version, work in progress (commit)
Copyright (c) 2014 Dylan Smith Licensed under the MIT license.