editing EXIF data with ExifTool

clearing privacy related data from an image's EXIF data with ExifTool

so what is EXIF?

EXIF (Exchangeable Image File Format) is a standard format maintained by the Japan Electronic and Information Technology Industries Association (JEITA) for metadata in digital images. EXIF is used to tag image files with metadata like image width and height, bits per pixel, camera settings like shutter speed and a whole host of other image specific data like the GPS location where the image was taken, and the date and time when the image was taken. EXIF is supported by almost all modern digital cameras. It is also used to tag other types of files, i.e. sound files, PDFs, OpenOffice/LibreOffice or Word docs.

EXIF data and privacy

EXIF data in images can be a privacy concern. I.e., GPS data and the time when the picture was taken, can reveal the place where a person was at a particular time. A prominent example is John MacAffee, who got caught on his escape because a Vice reporter didn't remove the EXIF data from a picture showing him together with John McAffee during his escape, thus revealing McAffee’s exact location.

In 2022, I walked three donkeys from northern germany to southern germany together with the owner of the donkeys. We came by remote places where the people were very welcoming and offered us shelter and also often food or even an opportunity to take a shower. But they were concerned that the place gets swamped with hikers and tourists if we put the pictures on a blog without stripping the geolocation from the images beforehand. That’s how I came to research on EXIF data, which quickly led me to ExifTool.

ExifTool

ExifTool is a platform independent perl library accompanied by a shell program that allows modification of EXIF tags in all sorts of files. It’s mostly applied to images files like JPG and TIFF, but can also be applied to other types of files.

installing ExifTool

The Debian package for ExifTool is libimage-exiftool-perl.

You can also download ExifTool from exiftool.org or from sourceforge.net

listing EXIF metadata

By default, exiftool does not list metadata with tag names, but tag descriptions:

rudolf@idoru:~/src/exiftest$ exiftool test.jpg ... Digital Zoom Ratio : 1 Scene Capture Type : Standard Subject Distance Range : Unknown GPS Version ID : 2.2.0.0 GPS Latitude Ref : North GPS Longitude Ref : East ...

To list metadata with tag names, use the parameter :

rudolf@idoru:~/src/exiftest$ exiftool -s test.jpg ... DigitalZoomRatio : 1 SceneCaptureType : Standard SubjectDistanceRange : Unknown GPSVersionID : 2.2.0.0 GPSLatitudeRef : North GPSLongitudeRef : East GPSAltitudeRef : Above Sea Level ...
By default, exiftool only lists metadata in “known tags”. Unknown vendor specific tags are omitted. Vendor specific tags –both known and unknown– can as well as standard tags contain sensitive data such as GPS location, time and date, device brand and model, etc.

Unknown tags are listed with the parameters

  • – (lower case u) lists non-binary unknown tags.
  • – (upper case U) additionally lists binary unknown tags.

I’m almost always using the Parameter to make sure that I get listed all metadata in the file.

You can list all EXIF data with .

tag families and tag groups

The docs on the ExifTool website state that “ExifTool classifies tags into groups in various families. Here is a list of the group names in each family”.

The command issued above can be run with an additional parameter to list the tags with their families/groups. In the example below, all tags that have a date/time value are listed, together with their families and groups:

rudolf@idoru:~/src/exiftest$ exiftool -s -U -G0:1:2 test.jpg | egrep -i "date|time" [File:System:Time] FileModifyDate : 2023:10:18 14:48:09+02:00 [File:System:Time] FileAccessDate : 2023:10:18 14:48:39+02:00 [File:System:Time] FileInodeChangeDate : 2023:10:18 14:48:09+02:00 [EXIF:IFD0:Time] ModifyDate : 2021:08:01 16:42:32 [EXIF:ExifIFD:Image] ExposureTime : 1/125 [EXIF:ExifIFD:Time] DateTimeOriginal : 2021:08:01 16:42:32 [EXIF:ExifIFD:Time] CreateDate : 2021:08:01 16:42:32 [EXIF:ExifIFD:Time] SubSecTime : 680514 [EXIF:ExifIFD:Time] SubSecTimeOriginal : 680514 [EXIF:ExifIFD:Time] SubSecTimeDigitized : 680514 [MakerNotes:Sony:Time] SonyDateTime : 2021:08:01 16:42:32 [EXIF:GPS:Time] GPSTimeStamp : 14:42:16 [EXIF:GPS:Time] GPSDateStamp : 2021:08:01 [Composite:Time] GPSDateTime : 2021:08:01 14:42:16Z [Composite:Time] SubSecCreateDate : 2021:08:01 16:42:32.680514 [Composite:Time] SubSecDateTimeOriginal : 2021:08:01 16:42:32.680514 [Composite:Time] SubSecModifyDate : 2021:08:01 16:42:32.680514 rudolf@idoru:~/src/exiftest$

In the line , EXIF is the group in family 0 (Information Type), GPS is the group in family 1 (Specific Location) and Time is the group in family 2 (Category).

I found it easier to wrap my head around the tag classification using the path analogy: In the line , the tag GPSdateStamp is in path exif:gps:time for Information Type:Specific Location:Category.

composite tags

Tags in group Composite are no tags that are stored in EXIF data, but are a compositions of other tags. I.e. the tag Composite:Time:GPSDateTime is a composition of EXIF:GPS:GPSTimeStamp and EXIF:GPS:GPSDateStamp:

rudolf@idoru:~/src/exiftest$ exiftool -s -U -G0:1:2 test.jpg | grep -i gps [EXIF:GPS:Location] GPSVersionID : 2.2.0.0 [EXIF:GPS:Location] GPSLatitudeRef : North [EXIF:GPS:Location] GPSLongitudeRef : East [EXIF:GPS:Location] GPSAltitudeRef : Above Sea Level [EXIF:GPS:Location] GPSStatus : Measurement Active [EXIF:GPS:Location] GPSMapDatum : WGS-84 [EXIF:GPS:Time] GPSTimeStamp : 14:42:16 [EXIF:GPS:Time] GPSDateStamp : 2021:08:01 [Composite:Location] GPSAltitude : 70 m Above Sea Level [Composite:Location] GPSLatitude : 53 deg 40' 26.16" N [Composite:Location] GPSLongitude : 9 deg 50' 21.59" E [Composite:Location] GPSPosition : 53 deg 40' 26.16" N, 9 deg 50' 21.59" E [Composite:Time] GPSDateTime : 2021:08:01 14:42:16Z rudolf@idoru:~/src/exiftest$

If the tags GPSTimeStamp and GPSDateStamp are deleted, the composite tag GPSDateTime is gone as well:

rudolf@idoru:~/src/exiftest$ exiftool -exif:gps:time:*= -overwrite_original test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$ exiftool -s -U -G0:1:2 test.jpg | grep -i gps [EXIF:GPS:Location] GPSVersionID : 2.2.0.0 [EXIF:GPS:Location] GPSLatitudeRef : North [EXIF:GPS:Location] GPSLongitudeRef : East [EXIF:GPS:Location] GPSAltitudeRef : Above Sea Level [EXIF:GPS:Location] GPSStatus : Measurement Active [EXIF:GPS:Location] GPSMapDatum : WGS-84 [Composite:Location] GPSAltitude : 70 m Above Sea Level [Composite:Location] GPSLatitude : 53 deg 40' 26.16" N [Composite:Location] GPSLongitude : 9 deg 50' 21.59" E [Composite:Location] GPSPosition : 53 deg 40' 26.16" N, 9 deg 50' 21.59" E rudolf@idoru:~/src/exiftest$
In the commandline, tag names and their familiy/group (or path) are case insensitive. EXIF:GPS:Location:GPSVersionID and exif:gps:location:gpsversionid denote the same tag.

tags in group file

Tags in the group file are no metadata that is embedded in the EXIF data of the file. Group File:System:Image contains tags for the file name, directory, file size and file permissions. The values of these tags is taken directly from the underlying OS. Group File:Image contains tags for image resolution, bits per sample, color model and a few other related properties of the image.

By the nature of these tags, tags in these two groups can only be read but cannot be modified or deleted.

listing tag names

lists all tag names. With , it lists all writable tags, with all readable tags.

The listing can be confined to a group of tag names, i.e. lists all tag names in group exif:gps.

rudolf@idoru:~/src/exiftest$ exiftool -list -exif:gps:* Available exif:gps tags: GPSAltitude GPSAltitudeRef GPSAreaInformation GPSDOP GPSDateStamp GPSDestBearing GPSDestBearingRef GPSDestDistance GPSDestDistanceRef GPSDestLatitude GPSDestLatitudeRef GPSDestLongitude GPSDestLongitudeRef GPSDifferential GPSHPositioningError GPSImgDirection GPSImgDirectionRef GPSLatitude GPSLatitudeRef GPSLongitude GPSLongitudeRef GPSMapDatum GPSMeasureMode GPSProcessingMethod GPSSatellites GPSSpeed GPSSpeedRef GPSStatus GPSTimeStamp GPSTrack GPSTrackRef GPSVersionID rudolf@idoru:~/src/exiftest$

deleting tags

deleting a single tag

Tags can be deleted without providing the whole tag path, i.e. to delete EXIF:GPS:Time:GPSDateStamp:

rudolf@idoru:~/src/exiftest$ exiftool -GPSDateStamp= -overwrite_original test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

Deletion can be confined to tags with a specific value, i.e. delete all author tags where the value of author is bob

deleting a tag group

Tag groups can be deleting by specifiying the tag group, followed by ‘*’ (asterix symbol) or all, i.e. or for the group exif:gps:

rudolf@idoru:~/src/exiftest$ exiftool -EXIF:GPS:*= -overwrite_original test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

delete all EXIF data

It is worth noting that this command doesn’t delete the read-only tags in the following groups:

  • File:System:Image – contains file name, directory, file size and file permissions.
  • File:System:Time – contains file modification, access and inode change date and time.
  • File:Image – contains image type, mime encoding, image encoding process and colormodel.
  • Composite:Image – contains image with and height and number of megapixels.

With regard to privacy, only the second group File:System:Time is relevant. The file modification time does reveal when the picture was modified.

The option should only be used with caution on raw image types. Raw image formats sometimes store parameters for rendering and/or image conversion as EXIF data.

modifying tags

setting the value of a tag

To set the value of the comment tag (path File:Image:Comment):

setting the value of a tag to an empty string

An alternative to delete a tag is to set the tag value to an empty string.

To write an empty string to a tag, precede the equals sign after the tag with ‘^’ (caret symbol), i.e. .

problems with unknown tags

From my experience, both testing exiftool and using exiftool in real-world scenarios, exiftool sometimes has a problem with modifying and deleting vendor specific tags, aka unknown tags.

here are some examples:

Tag MakerNotes:Sony:Time:SonyDateTime:

  • the tag could not be deleted. Instead I get the error message “Warning: Can’t delete Permanent tag Sony:SonyDateTime Nothing to do." What the heck is a permanent tag?
  • the tag could not be set an empty string.
  • however, I did succeed in setting the date/time value to “January 1st, 1900 at 00:00:00”

Tag group MakerNotes:Sony

I tried to delete the group, which didn’t work but falsely reported that the operation suceeded.

rudolf@idoru:~/src/exiftest$ exiftool -MakerNotes:Sony:*= -overwrite_original test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$ echo $? 0 rudolf@idoru:~/src/exiftest$exiftool -s -MakerNotes:Sony:* -G0:1:2 test.jpg [MakerNotes:Sony:Camera] SoftSkinEffect : Off [MakerNotes:Sony:Image] FaceInfoOffset : 94 [MakerNotes:Sony:Time] SonyDateTime : 2021:08:01 16:42:32 [MakerNotes:Sony:Image] SonyImageHeight : 1536 ... rudolf@idoru:~/src/exiftest$
From exiftool output, deleting the group seems to work, but a quick check reveals that the group and its tags are still there. The example above also indicates that exiftool return codes should be treated with care.

Getting more specific and trying to delete the tag group MakerNotes:Sony:camera, I get the message that the operation didn’t succeed.

rudolf@idoru:~/src/exiftest$ exiftool -MakerNotes:Sony:camera:*= -overwrite_original test.jpg 0 image files updated 1 image files unchanged rudolf@idoru:~/src/exiftest$

When I remove all EXIF tags, the tag group MakerNotes:Sony is gone as well:

rudolf@idoru:~/src/exiftest$ exiftool -all= -overwrite_original test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$ exiftool -s -MakerNotes:Sony:* -G0:1:2 test.jpg rudolf@idoru:~/src/exiftest$

workaround

A workaround for the flaws presented here is to

  • export the EXIF data to JSON, i.e. . Use the option if you want the thumbnail to be included in the JSON export.
  • clear all EXIF data in the file with .
  • re-import the EXIF data from the JSON EXIF data export made in the first step: .

All tags that exiftool cannot handle properly should be gone by now.

Afterwards, check the EXIF data in the file with .

excluding tags and tag groups from operations

To exclude a tag or a tag group from an operation, precede the tag or tag group with a double dash, i.e. to delete all GPS tags but the GPS location tags:

exiftool --exif:gps:location:* -exif:gps:* test.jpg

Note the double dash in .

source and destination files and directories

  • – set output file or output directory. If is used, backup files are needless and not created by exiftool.
  • – recurse into subdirectories. If directories with a directory name beginning with a dot (known in Unix as hidden files or hidden directories) have to be included, use

If a directory tree is processed with exiftool and a target directory is specified with , exiftool dumps all files it creates from processing the input files into the target directory without creating the subdirectories as they exist in the input directory.

To process directory trees, I found it most convenient to copy the whole dierctory tree and process the copy of the directory tree with exiftool.

preserving file date and time

With , the original file date and time is preserved.

setting the backup mode

By default, before write operations on the original input file, exiftool creates a backup file named from the original file.

There two modes available for writing to the original file without creating a backup:

  • -overwrite_original – overwrites the original file when writing information to a file. This option should be used with caution. Backups of the original files should be available.
  • -overwrite_original_in_place – this is like -overwrite_original, with an extra step that causes the original file creation date, type, creator, label color, icon, Finder tags and hard links to the file to be preserved. This extra step decreases the performance of exiftool.

JSON export and import

exiftool can export EXIF data to CSV and JSON and import EXIF data from CSV and JSON as well. I’m only interested in exporting/importing to and from JSON and omit the CSV stuff here.

To list EXIF data in JSON format, you run . To export the EXIF data to a JSON file, you redirect the output to a file, i.e. .

The JSON dump only includes the last part of the tag path:

rudolf@idoru:~/src/exiftest$ exiftool -j test.jpg "SourceFile": "test.jpg", ... "ThumbnailImage": "(Binary data 7328 bytes, use -b option to extract)", "FocalLength35efl": "4.6 mm", "LightValue": 9.3 rudolf@idoru:~/src/exiftest$

This poses no problem when importing such an export back into the image’s EXIF data. On import, the tags are stored into their original path.

To include the thumbnail (which is binary data) into the JSON export, use the parameter : .

When exporting EXIF data, the following does not work:

  • exclusion of tags groups, i.e. with .
  • exporting of binary data in unknwon tags.

putting it all together in a real life scenario

In the following scenario, I want to delete all location and time metadata from an image file EXIF data. I also want to clear all vendor specific tags from the EXIF data. Some vendor specific tags contain binary data of unknown type, which can pose a privacy threat. The non-binary vendor specific data tags are of no use to me.

I want to keep all other tags, i.e. camera settings like shutter speed, focal length and so on. And I don’t care if someone gets it that the image was taken by a sony cell phone.

I have a backup of the image in case I screw up in any step of the procedure.

step 1: remove unknown tags

First, I export the EXIF data in JSON format. With I also export the binary data of the standard EXIF tags to keep the image thumbnail.

The JSON export doesn’t contain any unknown vendor specific tags, which exiftool doesn’t always handle properly.

I remove all EXIF tags and re-import the JSON export I created before:

rudolf@idoru:~/src/exiftest$ exiftool -j -b test.jpg > test.out.json rudolf@idoru:~/src/exiftest$ exiftool -all= test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$exiftool -j=test.out.json test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

By now, the EXIF data in the image is stripped of any unknown non-binary and binary vendor specific tags. exiftool should be able to handle the remaining tags.

step 2: remove GPS data

I proceed with clearing all GPS data from the image EXIF data:

rudolf@idoru:~/src/exiftest$ exiftool -EXIF:GPS:*= test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

step 3: remove default date/time tags

I remove all default date and time tags:

rudolf@idoru:~/src/exiftest$ exiftool -EXIF:ExifIFD:Time:*= test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

step 4: check for and remove any remaining date/time data

Date and time data is often contained several independent tags. This time there’s still an XMP:XMP-exif:Time:GPSDateTime tag around, containing the date and time when the image was shot. I also delete this tag.

rudolf@idoru:~/src/exiftest$ exiftool -s -G0:1:2 test.jpg | egrep -i "date|time" [File:System:Time] FileModifyDate : 2023:10:18 11:54:15+02:00 [File:System:Time] FileAccessDate : 2023:10:18 11:54:15+02:00 [File:System:Time] FileInodeChangeDate : 2023:10:18 11:54:15+02:00 [EXIF:ExifIFD:Image] ExposureTime : 1/125 [XMP:XMP-exif:Time] GPSDateTime : 2021:08:01 14:42:16Z rudolf@idoru:~/src/exiftest$ exiftool -s -XMP:XMP-exif:Time:*= test.jpg 1 image files updated rudolf@idoru:~/src/exiftest$

step 5: check the remaining EXIF data

A final thorough check should be done with .

The image EXIF data is now cleared from

  • all vendor specific tags, both “known” and “unknown”.
  • all GPS data.
  • all date and time data.

reference

ExifTool man page

exiftool.org, Tag Groups

Recent Posts

Categories

Tags