exiftool

package module
v0.0.0-...-2927b4d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 5, 2016 License: GPL-3.0 Imports: 7 Imported by: 0

README

Description

This library allows you to read and write EXIF tags and to extract a thumbnail for an image.

Dependencies

  • Go 1.5
  • The "exif" tool (exif via Brew on Mac OS X or Apt on Ubuntu).

Example

Excerpt (see exiftooltest for the whole thing):

func main() {
    var imageFilepath string

    o := readOptions()
    imageFilepath = o.ImageFilepath

    // Copy the file.

    f, err := os.Open(imageFilepath)
    if err != nil {
        panic(err)
    }

    of := OutputFilepath
    err = copyToFilepath(f, &of)
    f.Close()

    if err != nil {
        panic(err)
    }

    // Dump the tags (using our visitor).

    fmt.Println("Dumping tags.")
    fmt.Println("")

    et := exiftool.NewExifTool(&of)
//    et.SetShowCommands(true)

    tv := &tagVisitor {}
    err = et.ReadTags(tv)
    if err != nil {
        panic(err)
    }

    fmt.Println("")

    // Update tag.

    fmt.Println("Setting tag.")

    err = et.SetTag("GPS", "GPSLongitude", []string { "80", "1", "6", "1", "6", "1" })
    if err != nil {
        panic(err)
    }

    // If there's a thumbnail, write it.

    ht, err := et.HasThumbnail()
    if err != nil {
        panic(err)
    }

    if ht == true {
        r, err := et.GetThumbnail()
        if err != nil {
            panic(err)
        }

        tf := ThumbnailFilepath
        err = copyToFilepath(r, &tf)
        if err != nil {
            panic(err)
        }

        thumbnailTempFilepath := r.Name()
        r.Close()

        os.Remove(thumbnailTempFilepath)

        fmt.Printf("Wrote thumbnail: [%s]\n", tf)
    } else {
        fmt.Printf("No thumbnail.\n")
    }
}

Output:

Dumping tags.

TAG [Image_Width]=[4128]
TAG [Image_Length]=[2322]
TAG [Manufacturer]=[samsung]
TAG [Model]=[SM-N900V]
TAG [Orientation]=[Right-top]
TAG [X-Resolution]=[72]
TAG [Y-Resolution]=[72]
TAG [Resolution_Unit]=[Inch]
TAG [Software]=[N900VVRUEOF1]
TAG [Date_and_Time]=[2016:01:18 20:36:22]
TAG [YCbCr_Positioning]=[Centered]
TAG [Compression]=[JPEG compression]
TAG [X-Resolution]=[72]
TAG [Y-Resolution]=[72]
TAG [Resolution_Unit]=[Inch]
TAG [F-Number]=[f/2.2]
TAG [Exposure_Program]=[Normal program]
TAG [Exif_Version]=[Exif Version 2.2]
TAG [Date_and_Time__Original_]=[2016:01:18 20:36:22]
TAG [Date_and_Time__Digitized_]=[2016:01:18 20:36:22]
TAG [Maximum_Aperture_Value]=[2.28 EV (f/2.2)]
TAG [Metering_Mode]=[Center-weighted average]
TAG [Focal_Length]=[4.1 mm]
TAG [Color_Space]=[sRGB]
TAG [Pixel_X_Dimension]=[4128]
TAG [Pixel_Y_Dimension]=[2322]
TAG [Exposure_Mode]=[Auto exposure]
TAG [White_Balance]=[Auto white balance]
TAG [Focal_Length_in_35mm_Film]=[31]
TAG [Scene_Capture_Type]=[Night scene]
TAG [Image_Unique_ID]=[837d96106ec1744c0000000000000000]
TAG [FlashPixVersion]=[FlashPix Version 1.0]
TAG [GPS_Tag_Version]=[2.2.0.0]
TAG [North_or_South_Latitude]=[N]
TAG [Latitude]=[26, 33, 44]
TAG [East_or_West_Longitude]=[W]
TAG [Longitude]=[80,  6,  6]
TAG [Altitude_Reference]=[Sea level]

Setting tag.
Wrote thumbnail: [thumb.jpg]

The arguments that are passed to SetTag() depend on the type of value that the tag is supposed to have. If libexif doesn't get what it needs, execution will terminate with a [fairly helpful] error.

For reference, this image is geotagged (several tags describing the geographical location where the picture was taken). We update the Longitude tag (which is actually a nice alias for the standard GPSLongitude name) which takes an unsigned rational (read: "set of fractions") value. Usually this expects a principal longitude (with a denominator of 1) followed by longitudinal minutes and seconds (both having a denominator of 60). However, here we just want to write back the values that were there to begin with. So we just pass { "80", "1", "6", "1", "6", "1" } so that we keep what we had and no division is performed.

Implementation Notes

  • The original plan was to directly integrate the libexif library but it became a non-trivial effort to find the correct libjpeg flavor and version. Then, I started parsing JPEG files (which were the primary use-case, though other image types support EXIF) directly in order to extract and update the EXIF data. However, even though the JPEG file is structured into individually indexed pieces, you can't successfully parse the entire file without being required to decode the image data (most segments, except for the actual image data, have length prefixes). As this library was merely a stepping-stone in a larger effort and the exif command-line tool is available for most environment a decision was made to just call that.

  • For convenience, SetTag() always passes the flag to create an EXIF segment if it doesn't already exist.

  • We won't add an EXIF segment to an image that is missing one if we're just reading tags. So, use the error return to make an assumption about whether one exists.

TODO

  • Add ability to remove a tag or IFD (tag directory).
  • Add ability to remove a thumbnail.
  • Add ability to set a thumbnail.

Documentation

Index

Constants

View Source
const (
	// The name of the *exif* command-line tool.
	ExifToolFilename             = "exif"
	ThumbnailExistsLinePrefix    = "EXIF data contains a thumbnail"
	ThumbnailSearchTailLineCount = 5
)

Variables

This section is empty.

Functions

This section is empty.

Types

type ExifTool

type ExifTool struct {
	// contains filtered or unexported fields
}

func NewExifTool

func NewExifTool(filepath *string) *ExifTool

func (*ExifTool) GetThumbnail

func (et *ExifTool) GetThumbnail() (f *os.File, err error)

Return a thumbnail.

func (*ExifTool) HasThumbnail

func (et *ExifTool) HasThumbnail() (found bool, err error)

Check if there is a thumbnail available.

func (*ExifTool) ReadTags

func (et *ExifTool) ReadTags(ev ExifVisitor) (err error)

Invoke the one visitor callback with each tag found in the image.

func (*ExifTool) SetShowCommands

func (et *ExifTool) SetShowCommands(showCommands bool)

func (*ExifTool) SetTag

func (et *ExifTool) SetTag(ifd string, name string, valueParts []string) (err error)

Set a given tag into the given IFD (tag directory).

type ExifVisitor

type ExifVisitor interface {
	HandleTag(tagName *string, value *string) error
}

Whoever calls ReadTags() must provide an implementation of this.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL