Skip to content
Perform surgical operations on EXIF data at the command-line.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
assets
command/go-exif-knife
handler
.travis.yml
LICENSE
README.md
TODO
common_test.go
exif.go
exif_test.go
utility.go

README.md

Build Status Coverage Status GoDoc

Overview

This is a command-line tool to perform a multitude of surgical operations on the EXIF data in any file that contains it.

This tool has been written on top of go-exif, a complete EXIF implementation.

Image Support

JPEG, PNG, and TIFF (naturally, since EXIF takes the TIFF structure) are well supported. A byte-by-byte search will be performed for all other types of file. Writes are only supported for JEPG and PNG.

$ ./go-exif-knife write --filepath image.png --set-tag=ifd0,Make,testing --output-filepath /tmp/updated.png

$ ./go-exif-knife read --filepath /tmp/updated.png
 IFD: Ifd<ID=(0) PARENT-IFD=[] IFD=[IFD] INDEX=(0) COUNT=(1) OFF=(0x0008) CHILDREN=(0) PARENT=(0x0000) NEXT-IFD=(0x0000)>
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x010f) TAG-TYPE=[ASCII] UNIT-COUNT=(8)> NAME=[Make] VALUE=[testing]

Install

Get

  • Get via Github Releases
  • Get via go-get and build: "go get github.com/dsoprea/go-exif-knife"

Install

  1. Make the file executable ("chmod 755 [filename]")
  2. Put the binary in your path.

Usage

This tool is comprised of one tool with multiple subcommands. The root tool and the various subcommands provide complete command-line help.

Examples

Read

Print All Tags

Output (shortened for succinctness):

$ ./go-exif-knife read --filepath image.jpg
 IFD: Ifd<ID=(0) PARENT-IFD=[] IFD=[IFD] INDEX=(0) COUNT=(11) OFF=(0x0008) CHILDREN=(2) PARENT=(0x0000) NEXT-IFD=(0x039e)>
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x010f) TAG-TYPE=[ASCII] UNIT-COUNT=(8)> NAME=[Make] VALUE=[samsung]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0110) TAG-TYPE=[ASCII] UNIT-COUNT=(9)> NAME=[Model] VALUE=[SM-N920T]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0112) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[Orientation] VALUE=[[1]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0131) TAG-TYPE=[ASCII] UNIT-COUNT=(12)> NAME=[Software] VALUE=[GIMP 2.8.20]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0132) TAG-TYPE=[ASCII] UNIT-COUNT=(20)> NAME=[DateTime] VALUE=[2018:06:09 01:07:30]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0213) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[YCbCrPositioning] VALUE=[[1]]
 - TAG: IfdTagEntry<TAG-IFD=[Exif] TAG-ID=(0x8769) TAG-TYPE=[LONG] UNIT-COUNT=(1)>
   IFD: Ifd<ID=(1) PARENT-IFD=[IFD] IFD=[Exif] INDEX=(0) COUNT=(26) OFF=(0x00d4) CHILDREN=(1) PARENT=(0x0008) NEXT-IFD=(0x0000)>
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x829a) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[ExposureTime] VALUE=[[{1 13}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x829d) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[FNumber] VALUE=[[{19 10}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x8822) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[ExposureProgram] VALUE=[[2]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9209) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[Flash] VALUE=[[0]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x920a) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[FocalLength] VALUE=[[{430 100}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x9286) TAG-TYPE=[UNDEFINED] UNIT-COUNT=(21)> NAME=[UserComment] VALUE=[UserComment<SIZE=(13) ENCODING=[ASCII] V=[0 0 0 73 73 67 83 65]... LEN=(13)>]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xa000) TAG-TYPE=[UNDEFINED] UNIT-COUNT=(4)> NAME=[FlashpixVersion] VALUE=[0100]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xa001) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[ColorSpace] VALUE=[[1]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xa002) TAG-TYPE=[LONG] UNIT-COUNT=(1)> NAME=[PixelXDimension] VALUE=[[920]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0xa003) TAG-TYPE=[LONG] UNIT-COUNT=(1)> NAME=[PixelYDimension] VALUE=[[570]]
   - TAG: IfdTagEntry<TAG-IFD=[Iop] TAG-ID=(0xa005) TAG-TYPE=[LONG] UNIT-COUNT=(1)>
     IFD: Ifd<ID=(4) PARENT-IFD=[Exif] IFD=[Iop] INDEX=(0) COUNT=(2) OFF=(0x02b2) CHILDREN=(0) PARENT=(0x00d4) NEXT-IFD=(0x0000)>
     - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0001) TAG-TYPE=[ASCII] UNIT-COUNT=(4)> NAME=[InteroperabilityIndex] VALUE=[R98]
     - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0002) TAG-TYPE=[UNDEFINED] UNIT-COUNT=(4)> NAME=[InteroperabilityVersion] VALUE=[0100]
 - TAG: IfdTagEntry<TAG-IFD=[GPSInfo] TAG-ID=(0x8825) TAG-TYPE=[LONG] UNIT-COUNT=(1)>
   IFD: Ifd<ID=(2) PARENT-IFD=[IFD] IFD=[GPSInfo] INDEX=(0) COUNT=(9) OFF=(0x02d0) CHILDREN=(0) PARENT=(0x0008) NEXT-IFD=(0x0000)>
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0000) TAG-TYPE=[BYTE] UNIT-COUNT=(4)> NAME=[GPSVersionID] VALUE=[[2 2 0 0]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0001) TAG-TYPE=[ASCII] UNIT-COUNT=(2)> NAME=[GPSLatitudeRef] VALUE=[N]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0002) TAG-TYPE=[RATIONAL] UNIT-COUNT=(3)> NAME=[GPSLatitude] VALUE=[[{26 1} {35 1} {12 1}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0006) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[GPSAltitude] VALUE=[[{0 1}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0007) TAG-TYPE=[RATIONAL] UNIT-COUNT=(3)> NAME=[GPSTimeStamp] VALUE=[[{1 1} {22 1} {57 1}]]
   - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x001d) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> NAME=[GPSDateStamp] VALUE=[2018:04:29]
>IFD: Ifd<ID=(3) PARENT-IFD=[] IFD=[IFD] INDEX=(1) COUNT=(4) OFF=(0x039e) CHILDREN=(0) PARENT=(0x0000) NEXT-IFD=(0x0000)>
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0103) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[Compression] VALUE=[[6]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x011a) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[XResolution] VALUE=[[{72 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x011b) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[YResolution] VALUE=[[{72 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0128) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> NAME=[ResolutionUnit] VALUE=[[2]]

Print Specific Tags in All IFDs Using Name

$ ./go-exif-knife read --filepath image.jpg --tag Model
Model: SM-N920T

"--tag" can be provided multiple times.

Print Tag With Name and IFD

$ ./go-exif-knife read --filepath "assets/image.jpg" --tag Model --ifd ifd0
Model: Canon EOS 5D Mark III

"--tag" can be provided multiple times.

Print All Tags in IFD

$ ./go-exif-knife read --filepath image.jpg --ifd gps
 IFD: Ifd<ID=(2) PARENT-IFD=[IFD] IFD=[GPSInfo] INDEX=(0) COUNT=(9) OFF=(0x02d0) CHILDREN=(0) PARENT=(0x0008) NEXT-IFD=(0x0000)>
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0000) TAG-TYPE=[BYTE] UNIT-COUNT=(4)> NAME=[GPSVersionID] VALUE=[[2 2 0 0]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0001) TAG-TYPE=[ASCII] UNIT-COUNT=(2)> NAME=[GPSLatitudeRef] VALUE=[N]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0002) TAG-TYPE=[RATIONAL] UNIT-COUNT=(3)> NAME=[GPSLatitude] VALUE=[[{26 1} {35 1} {12 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0003) TAG-TYPE=[ASCII] UNIT-COUNT=(2)> NAME=[GPSLongitudeRef] VALUE=[W]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0004) TAG-TYPE=[RATIONAL] UNIT-COUNT=(3)> NAME=[GPSLongitude] VALUE=[[{80 1} {3 1} {13 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0005) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> NAME=[GPSAltitudeRef] VALUE=[[1]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0006) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> NAME=[GPSAltitude] VALUE=[[{0 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0007) TAG-TYPE=[RATIONAL] UNIT-COUNT=(3)> NAME=[GPSTimeStamp] VALUE=[[{1 1} {22 1} {57 1}]]
 - TAG: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x001d) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> NAME=[GPSDateStamp] VALUE=[2018:04:29]

Print as JSON

$ ./go-exif-knife read --filepath image.jpg --ifd gps --json
{
    "gpsinfo": {
        "GPSAltitude": [
            {
                "Numerator": 0,
                "Denominator": 1
            }
        ],
        "GPSAltitudeRef": "AQ==",
        "GPSDateStamp": "2018:04:29",
        "GPSLatitude": [
            {
                "Numerator": 26,
                "Denominator": 1
            },
            {
                "Numerator": 35,
                "Denominator": 1
            },
            {
                "Numerator": 12,
                "Denominator": 1
            }
        ],
        "GPSLatitudeRef": "N",
        "GPSLongitude": [
            {
                "Numerator": 80,
                "Denominator": 1
            },
            {
                "Numerator": 3,
                "Denominator": 1
            },
            {
                "Numerator": 13,
                "Denominator": 1
            }
        ],
        "GPSLongitudeRef": "W",
        "GPSTimeStamp": [
            {
                "Numerator": 1,
                "Denominator": 1
            },
            {
                "Numerator": 22,
                "Denominator": 1
            },
            {
                "Numerator": 57,
                "Denominator": 1
            }
        ],
        "GPSVersionID": "AgIAAA=="
    }
}

Just Print Value(s)

$ ./go-exif-knife read --filepath image.jpg --tag Model --just-values
SM-N920T

"--tag" can be provided multiple times.

GPS

$ ./go-exif-knife gps --filepath image.jpg
GpsInfo<LAT=(26.58667) LON=(-80.05361) ALT=(0) TIME=[2018-04-29 01:22:57 +0000 UTC]>
$ ./go-exif-knife gps --filepath image.jpg --json
{
    "Altitude": 0,
    "LatitudeDecimal": 26.586666666666666,
    "LongitudeDecimal": -80.05361111111111,
    "Timestamp": "2018-04-29T01:22:57Z",
    "TimestampUnix": 1524964977
}

Include a geohash calculated with the Google S2 (Hilbert Curve) algorithm:

$ ./go-exif-knife gps --filepath image.jpg --json --google-s2
{
    "Altitude": 0,
    "LatitudeDecimal": 26.586666666666666,
    "LongitudeDecimal": -80.05361111111111,
    "S2LocationId": 6542766593732284747,
    "Timestamp": "2018-04-29T01:22:57Z",
    "TimestampUnix": 1524964977
}

Thumbnail

$ ./go-exif-knife thumbnail --filepath image.jpg --output-filepath /tmp/thumbnail.jpg

Write

$ ./go-exif-knife read --filepath image.jpg --tag Make
Make: samsung

$ ./go-exif-knife write --filepath image.jpg --set-tag=ifd0,Make,testing --output-filepath /tmp/updated.jpg

$ ./go-exif-knife read --filepath /tmp/updated.jpg --tag Make
Make: testing
You can’t perform that action at this time.