exifr

R-CMD-check CRAN_Status_Badge Codecov test coverage

Ever needed to read in EXIF data from images or other files in R? ExifTool by Phil Harvey is the most comprenesive tool available for reading, writing and editing meta information in a wide variety of files. ExifTool supports many different metadata formats including EXIF, GPS, IPTC, XMP, JFIF, GeoTIFF, ICC Profile, Photoshop IRB, FlashPix, AFCP and ID3, as well as the maker notes of many digital cameras by Canon, Casio, FLIR, FujiFilm, GE, HP, JVC/Victor, Kodak, Leaf, Minolta/Konica-Minolta, Motorola, Nikon, Nintendo, Olympus/Epson, Panasonic/Leica, Pentax/Asahi, Phase One, Reconyx, Ricoh, Samsung, Sanyo, Sigma/Foveon and Sony. This package provides a thin wrapper around ExifTool allowing the reading of image file metadata with a single command.

Installation

You will need Perl to use exifr, which may already be installed on your system (Mac, Linux). If you are on Windows you need to install Perl before installing exifr (easily done from Strawberry Perl or Active State Perl. Mac users can also install ExifTool directly from sourceforge, which is not necessary but may be useful if ExifTool is to be used outside of R.

You can install exifr from github with:

# install.packages("devtools")
devtools::install_github("paleolimbot/exifr")

…or from CRAN with:

install.packages("exifr")

If you can load the package, everything should be installed correctly:

library(exifr)
#> Using ExifTool version 12.22

Example

It makes the most sense to use the read_exif() function with list.files(), but it will also process directories (when using recursive = TRUE).

image_files <- list.files(system.file("images", package = "exifr"), full.names = TRUE)
read_exif(image_files)
#> # A tibble: 2 x 275
#>   SourceFile ExifToolVersion FileName Directory FileSize FileModifyDate
#>   <chr>                <dbl> <chr>    <chr>        <int> <chr>         
#> 1 /Library/…            12.2 binary_… /Library…    13726 2021:03:20 10…
#> 2 /Library/…            12.2 Canon.j… /Library…     2697 2021:03:20 10…
#> # … with 269 more variables: FileAccessDate <chr>, FileInodeChangeDate <chr>,
#> #   FilePermissions <int>, FileType <chr>, FileTypeExtension <chr>,
#> #   MIMEType <chr>, JFIFVersion <chr>, ExifByteOrder <chr>, Make <chr>,
#> #   Model <chr>, Orientation <int>, XResolution <int>, YResolution <int>,
#> #   ResolutionUnit <int>, Software <chr>, ModifyDate <chr>, Artist <chr>,
#> #   YCbCrPositioning <int>, ExposureTime <dbl>, FNumber <dbl>,
#> #   ExposureProgram <int>, ISO <int>, SensitivityType <int>, ExifVersion <chr>,
#> #   DateTimeOriginal <chr>, CreateDate <chr>, ComponentsConfiguration <chr>,
#> #   CompressedBitsPerPixel <int>, ExposureCompensation <dbl>,
#> #   MaxApertureValue <dbl>, MeteringMode <int>, LightSource <int>, Flash <int>,
#> #   FocalLength <dbl>, Warning <chr>, ImageQuality <int>,
#> #   FirmwareVersion <chr>, WhiteBalance <int>, FocusMode <int>,
#> #   AFAreaMode <chr>, ImageStabilization <int>, MacroMode <int>,
#> #   ShootingMode <int>, Audio <int>, DataDump <chr>, WhiteBalanceBias <int>,
#> #   FlashBias <int>, InternalSerialNumber <chr>, PanasonicExifVersion <chr>,
#> #   VideoFrameRate <int>, ColorEffect <int>, TimeSincePowerOn <dbl>,
#> #   BurstMode <int>, SequenceNumber <int>, ContrastMode <int>,
#> #   NoiseReduction <int>, SelfTimer <int>, Rotation <int>, AFAssistLamp <int>,
#> #   ColorMode <int>, OpticalZoomMode <int>, ConversionLens <int>,
#> #   TravelDay <int>, BatteryLevel <int>, WorldTimeLocation <int>,
#> #   ProgramISO <int>, AdvancedSceneType <int>, FacesDetected <int>,
#> #   AFPointPosition <chr>, NumFacePositions <int>, Face1Position <chr>,
#> #   Face2Position <chr>, Face3Position <chr>, Face4Position <chr>,
#> #   Face5Position <chr>, IntelligentExposure <int>, FacesRecognized <int>,
#> #   RecognizedFace1Name <chr>, RecognizedFace1Position <chr>,
#> #   RecognizedFace1Age <chr>, RecognizedFace2Name <chr>,
#> #   RecognizedFace2Position <chr>, RecognizedFace2Age <chr>,
#> #   RecognizedFace3Name <chr>, RecognizedFace3Position <chr>,
#> #   RecognizedFace3Age <chr>, FlashWarning <int>, Title <chr>, BabyName <chr>,
#> #   Location <chr>, IntelligentResolution <int>, HDRShot <int>,
#> #   BurstSpeed <int>, ClearRetouch <int>, WBShiftCreativeControl <int>,
#> #   SweepPanoramaDirection <int>, SweepPanoramaFieldOfView <int>,
#> #   InternalNDFilter <dbl>, FilterEffect <chr>, ClearRetouchValue <dbl>, …

You’ll notice there are a lot of columns! You can choose the exact tags you want to extract using the tags argument:

read_exif(image_files, tags = c("filename", "imagesize"))
#> # A tibble: 2 x 3
#>   SourceFile                                               FileName    ImageSize
#>   <chr>                                                    <chr>       <chr>    
#> 1 /Library/Frameworks/R.framework/Versions/4.0/Resources/… binary_tag… 30 25    
#> 2 /Library/Frameworks/R.framework/Versions/4.0/Resources/… Canon.jpg   8 8

Details

In the background, read_exif() is calling exiftool on the console, and reading the results to R. You can see the exact command used by read_exif() by passing quiet = FALSE. This can be useful when debugging, as occasionally images need to get read in that need some kind of special treatment.

read_exif(image_files, tags = c("filename", "imagesize"), quiet = FALSE)
#> Generating command line arguments...
#> Running 1 commands
#> 'perl' '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/exiftool/exiftool.pl' -n -j -q -b -filename -imagesize '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/binary_tag.JPG' '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/Canon.jpg'
#> # A tibble: 2 x 3
#>   SourceFile                                               FileName    ImageSize
#>   <chr>                                                    <chr>       <chr>    
#> 1 /Library/Frameworks/R.framework/Versions/4.0/Resources/… binary_tag… 30 25    
#> 2 /Library/Frameworks/R.framework/Versions/4.0/Resources/… Canon.jpg   8 8

You can also roll-your-own exiftool call by using exiftool_call(). For the previous example, it would look something like this:

exiftool_call(args = c("-n", "-j", "-q", "-filename", "-imagesize"), fnames = image_files)
#> 'perl' '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/exiftool/exiftool.pl' -n -j -q -filename -imagesize '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/binary_tag.JPG' '/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/Canon.jpg'
#> [{
#>   "SourceFile": "/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/binary_tag.JPG",
#>   "FileName": "binary_tag.JPG",
#>   "ImageSize": "30 25"
#> },
#> {
#>   "SourceFile": "/Library/Frameworks/R.framework/Versions/4.0/Resources/library/exifr/images/Canon.jpg",
#>   "FileName": "Canon.jpg",
#>   "ImageSize": "8 8"
#> }]