Sunday, 17 March 2019

Python Scripting [4A]: Exif Based Image Renaming

This is now a new scripting project I am starting for Python. I need this script to rename all my photos off the camera, replacing the use of IrfanView which I used on my Windows 10 computer. Whilst I still have that computer and the software, I am looking to do something with Python scripting under Linux to achieve the same outcome automatically.

First thing is to look at the Exif string we use under IrfanView. 
This is the current string:
  • $E36867(%Y%m%d %H%M%S)$E37520 $E272$O
 That is obviously specific to IrfanView in that it incorporates some parameters that are specified in their software design. All parameters start with a $. The breakdown is
  • $E36867 - DateTimeDigitised
  • (%Y%m%d %H%M%S) when following a parameter means to extract the year, month, day, hour, minute and second out of the parameter
  • $E37520 - SubSecTime
  • $E272 - Model
  • $O - original extension of the filename including the period.
When put together that will rename a file to have a name that is based on the date, time and the name of the camera. SubSecTime is something that not all cameras support. It is basically the  millisecond component of the time and my current camera will provide this, but not all of my cameras have been able to provide it.

Then we have to translate these into something that is related to the standard. After doing some investigation, I found a list of tags on the Internet, and it listed tag codes that correspond to the above without the $E characters in front. These codes are in decimal, so every single one of them can be looked up in the list, and it turns out they are all part of the standard, and not manufacturer specific.

The second thing is to look at Exif read support for Python. This is generally implemented using a third party library. To install these libraries, a tool called pip is available. Once I installed that, I was able to install a library called exifread. To edit my script I am using KDevelop, which is the KDE supplied tool for development support, and it recognises Python out of the box.

Looking at exifread, I can start with a sample script that they provide:

import exifread
f = open("/home/xxx/Media/Pictures/Photos/2019/142_0803/IMG_2864.JPG",'rb')
tags = exifread.process_file(f, details=False)
for tag in tags.keys():
        print "Key: %s, value %s" % (tag, tags[tag])

This is a pretty simple example, which is hardcoded with a path to a specific image file I am using as an example. It just gets the tags for that file and outputs them. The exifread.process_file call gets passed a "details=False" parameter, which just limits the tags that come out, such as a thumbnail binary blob, and MakerNotes, which are manufacturer specific. The output looks like this:

Key: EXIF ApertureValue, value 29/8
Key: Image ExifOffset, value 388
Key: EXIF ComponentsConfiguration, value YCbCr
Key: EXIF CustomRendered, value Normal
Key: EXIF FlashPixVersion, value 0100
Key: EXIF RecommendedExposureIndex, value 250
Key: Image DateTime, value 2019:03:08 11:23:29
Key: EXIF ShutterSpeedValue, value 53/16
Key: EXIF ColorSpace, value sRGB
Key: EXIF MeteringMode, value Pattern
Key: EXIF ExifVersion, value 0230
Key: EXIF LensSpecification, value [15, 45, 0, 0]
Key: EXIF ISOSpeedRatings, value 250
Key: Thumbnail YResolution, value 180
Key: EXIF SubSecTime, value 87
Key: Interoperability InteroperabilityVersion, value [48, 49, 48, 48]
Key: Image Model, value <deleted>
Key: Image Orientation, value Horizontal (normal)
Key: EXIF DateTimeOriginal, value 2019:03:08 11:23:29
Key: Image YCbCrPositioning, value Co-sited
Key: EXIF InteroperabilityOffset, value 15836
Key: Thumbnail JPEGInterchangeFormat, value 20468
Key: Interoperability RelatedImageWidth, value 6000
Key: EXIF FNumber, value 7/2
Key: EXIF FileSource, value Digital Camera
Key: EXIF ExifImageLength, value 4000
Key: Image ResolutionUnit, value Pixels/Inch
Key: GPS GPSVersionID, value [2, 3, 0, 0]
Key: EXIF CompressedBitsPerPixel, value 3
Key: Thumbnail XResolution, value 180
Key: EXIF LensSerialNumber, value 000006a8dd
Key: EXIF ExposureProgram, value Program Normal
Key: Image GPSInfo, value 16078
Key: EXIF BodySerialNumber, value 495050000006
Key: Image Copyright, value
Key: Thumbnail JPEGInterchangeFormatLength, value 5322
Key: EXIF Flash, value Flash did not fire, compulsory flash mode
Key: Thumbnail Compression, value JPEG (old-style)
Key: EXIF ExposureMode, value Auto Exposure
Key: EXIF FocalPlaneYResolution, value 2000000/293
Key: EXIF FocalPlaneXResolution, value 2000000/293
Key: EXIF ExifImageWidth, value 6000
Key: Image Artist, value
Key: EXIF SceneCaptureType, value Standard
Key: EXIF SensitivityType, value Recommended Exposure Index
Key: Interoperability RelatedImageLength, value 4000
Key: Image ImageDescription, value                               
Key: EXIF DigitalZoomRatio, value 1
Key: EXIF SubSecTimeOriginal, value 87
Key: EXIF LensModel, value EF-M15-45mm f/3.5-6.3 IS STM
Key: EXIF DateTimeDigitized, value 2019:03:08 11:23:29
Key: EXIF FocalLength, value 15
Key: EXIF ExposureTime, value 1/10
Key: Image XResolution, value 180
Key: Image Make, value Canon
Key: EXIF WhiteBalance, value Manual
Key: Thumbnail ResolutionUnit, value Pixels/Inch
Key: Image YResolution, value 180
Key: EXIF FocalPlaneResolutionUnit, value 2
Key: Interoperability InteroperabilityIndex, value R98
Key: EXIF ExposureBiasValue, value 0
Key: EXIF SensingMethod, value One-chip color area
Key: EXIF SubSecTimeDigitized, value 87

It looks like most of what I am interested in are in those tags. The exact name would have to be flagged in a tag search to get a value, and then the value transcribed from a string into the data that gets fed into a rename algorithm. In practice this will be a call to a filename move because that is the rename allegory in Linux.

There are other libraries that do exif stuff. Some examples I found are:
  • piexif
  • exif
  • Python Imaging Library (PIL)
  • pyexiv2
Out of these examples I  chose to evaluate PIL (using its Pillow fork) as well. Next time around I will make a decision which of the two libraries (Pillow or exifread) will be more useful for my project.