go-exif: github.com/dsoprea/go-exif Index | Examples | Files | Directories

package exif

import "github.com/dsoprea/go-exif"

exif parses raw EXIF information given a block of raw EXIF data. It can also construct new EXIF information, and provides tools for doing so. This package is not involved with the parsing of particular file-formats.

The EXIF data must first be extracted and then provided to us. Conversely, when constructing new EXIF data, the caller is responsible for packaging this in whichever format they require.

Index

Examples

Package Files

error.go exif.go gps.go ifd.go ifd_builder.go ifd_builder_encode.go ifd_enumerate.go ifd_tag_entry.go readme.go tags.go tags_data.go tags_unknown.go type.go type_encode.go utility.go

Constants

const (
    // ExifAddressableAreaStart is the absolute offset in the file that all
    // offsets are relative to.
    ExifAddressableAreaStart = uint32(0x0)

    // ExifDefaultFirstIfdOffset is essentially the number of bytes in addition
    // to `ExifAddressableAreaStart` that you have to move in order to escape
    // the rest of the header and get to the earliest point where we can put
    // stuff (which has to be the first IFD). This is the size of the header
    // sequence containing the two-character byte-order, two-character fixed-
    // bytes, and the four bytes describing the first-IFD offset.
    ExifDefaultFirstIfdOffset = uint32(2 + 2 + 4)
)
const (
    IfdStandard = "IFD"
    IfdExif     = "Exif"
    IfdGps      = "GPSInfo"
    IfdIop      = "Iop"

    IfdExifId = 0x8769
    IfdGpsId  = 0x8825
    IfdIopId  = 0xA005

    IfdRootId = 0x0000

    IfdPathStandard        = "IFD"
    IfdPathStandardExif    = "IFD/Exif"
    IfdPathStandardExifIop = "IFD/Exif/Iop"
    IfdPathStandardGps     = "IFD/GPSInfo"
)
const (
    ThumbnailOffsetTagId = 0x0201
    ThumbnailSizeTagId   = 0x0202

    TagVersionId = 0x0000

    TagLatitudeId     = 0x0002
    TagLatitudeRefId  = 0x0001
    TagLongitudeId    = 0x0004
    TagLongitudeRefId = 0x0003

    TagTimestampId = 0x0007
    TagDatestampId = 0x001d

    TagAltitudeId    = 0x0006
    TagAltitudeRefId = 0x0005
)
const (
    TagUnknownType_9298_UserComment_Encoding_ASCII     = iota
    TagUnknownType_9298_UserComment_Encoding_JIS       = iota
    TagUnknownType_9298_UserComment_Encoding_UNICODE   = iota
    TagUnknownType_9298_UserComment_Encoding_UNDEFINED = iota
)
const (
    TagUnknownType_9101_ComponentsConfiguration_Channel_Y  = 0x1
    TagUnknownType_9101_ComponentsConfiguration_Channel_Cb = 0x2
    TagUnknownType_9101_ComponentsConfiguration_Channel_Cr = 0x3
    TagUnknownType_9101_ComponentsConfiguration_Channel_R  = 0x4
    TagUnknownType_9101_ComponentsConfiguration_Channel_G  = 0x5
    TagUnknownType_9101_ComponentsConfiguration_Channel_B  = 0x6
)
const (
    TagUnknownType_9101_ComponentsConfiguration_OTHER = iota
    TagUnknownType_9101_ComponentsConfiguration_RGB   = iota
    TagUnknownType_9101_ComponentsConfiguration_YCBCR = iota
)
const (
    TypeByte           = uint16(1)
    TypeAscii          = uint16(2)
    TypeShort          = uint16(3)
    TypeLong           = uint16(4)
    TypeRational       = uint16(5)
    TypeUndefined      = uint16(7)
    TypeSignedLong     = uint16(9)
    TypeSignedRational = uint16(10)

    // Custom, for our purposes.
    TypeAsciiNoNul = uint16(0xf0)
)
const (
    // Tag-ID + Tag-Type + Unit-Count + Value/Offset.
    IfdTagEntrySize = uint32(2 + 2 + 4 + 4)
)
const (
    UnparseableUnknownTagValuePlaceholder = "!UNPARSEABLE"
)

Variables

var (
    ErrTagNotFound    = errors.New("tag not found")
    ErrTagNotStandard = errors.New("tag not a standard tag")
)
var (

    // EncodeDefaultByteOrder is the default byte-order for encoding operations.
    EncodeDefaultByteOrder = binary.BigEndian

    // Default byte order for tests.
    TestDefaultByteOrder = binary.BigEndian

    BigEndianBoBytes    = [2]byte{'M', 'M'}
    LittleEndianBoBytes = [2]byte{'I', 'I'}

    ByteOrderLookup = map[[2]byte]binary.ByteOrder{
        BigEndianBoBytes:    binary.BigEndian,
        LittleEndianBoBytes: binary.LittleEndian,
    }

    ByteOrderLookupR = map[binary.ByteOrder][2]byte{
        binary.BigEndian:    BigEndianBoBytes,
        binary.LittleEndian: LittleEndianBoBytes,
    }

    ExifFixedBytesLookup = map[binary.ByteOrder][2]byte{
        binary.LittleEndian: [2]byte{0x2a, 0x00},
        binary.BigEndian:    [2]byte{0x00, 0x2a},
    }
)
var (
    ErrNoExif          = errors.New("no exif data")
    ErrExifHeaderError = errors.New("exif header error")
)
var (
    ErrTagEntryNotFound = errors.New("tag entry not found")
    ErrChildIbNotFound  = errors.New("child IB not found")
)
var (
    ErrNoThumbnail = errors.New("no thumbnail")
    ErrNoGpsTags   = errors.New("no gps tags")
)
var (
    TagUnknownType_9298_UserComment_Encoding_Names = map[int]string{
        TagUnknownType_9298_UserComment_Encoding_ASCII:     "ASCII",
        TagUnknownType_9298_UserComment_Encoding_JIS:       "JIS",
        TagUnknownType_9298_UserComment_Encoding_UNICODE:   "UNICODE",
        TagUnknownType_9298_UserComment_Encoding_UNDEFINED: "UNDEFINED",
    }

    TagUnknownType_9298_UserComment_Encodings = map[int][]byte{
        TagUnknownType_9298_UserComment_Encoding_ASCII:     []byte{'A', 'S', 'C', 'I', 'I', 0, 0, 0},
        TagUnknownType_9298_UserComment_Encoding_JIS:       []byte{'J', 'I', 'S', 0, 0, 0, 0, 0},
        TagUnknownType_9298_UserComment_Encoding_UNICODE:   []byte{'U', 'n', 'i', 'c', 'o', 'd', 'e', 0},
        TagUnknownType_9298_UserComment_Encoding_UNDEFINED: []byte{0, 0, 0, 0, 0, 0, 0, 0},
    }

    TagUnknownType_9101_ComponentsConfiguration_Names = map[int]string{
        TagUnknownType_9101_ComponentsConfiguration_OTHER: "OTHER",
        TagUnknownType_9101_ComponentsConfiguration_RGB:   "RGB",
        TagUnknownType_9101_ComponentsConfiguration_YCBCR: "YCBCR",
    }

    TagUnknownType_9101_ComponentsConfiguration_Configurations = map[int][]byte{
        TagUnknownType_9101_ComponentsConfiguration_RGB: []byte{
            TagUnknownType_9101_ComponentsConfiguration_Channel_R,
            TagUnknownType_9101_ComponentsConfiguration_Channel_G,
            TagUnknownType_9101_ComponentsConfiguration_Channel_B,
            0,
        },

        TagUnknownType_9101_ComponentsConfiguration_YCBCR: []byte{
            TagUnknownType_9101_ComponentsConfiguration_Channel_Y,
            TagUnknownType_9101_ComponentsConfiguration_Channel_Cb,
            TagUnknownType_9101_ComponentsConfiguration_Channel_Cr,
            0,
        },
    }
)
var (
    TypeNames = map[uint16]string{
        TypeByte:           "BYTE",
        TypeAscii:          "ASCII",
        TypeShort:          "SHORT",
        TypeLong:           "LONG",
        TypeRational:       "RATIONAL",
        TypeUndefined:      "UNDEFINED",
        TypeSignedLong:     "SLONG",
        TypeSignedRational: "SRATIONAL",

        TypeAsciiNoNul: "_ASCII_NO_NUL",
    }

    TypeNamesR = map[string]uint16{}
)
var (
    // ErrNotEnoughData is used when there isn't enough data to accomodate what
    // we're trying to parse (sizeof(type) * unit_count).
    ErrNotEnoughData = errors.New("not enough data for type")

    // ErrWrongType is used when we try to parse anything other than the
    // current type.
    ErrWrongType = errors.New("wrong type, can not parse")

    // ErrUnhandledUnknownTag is used when we try to parse a tag that's
    // recorded as an "unknown" type but not a documented tag (therefore
    // leaving us not knowning how to read it).
    ErrUnhandledUnknownTypedTag = errors.New("not a standard unknown-typed tag")
)
var (
    ErrChildIfdNotMapped = errors.New("no child-IFD for that tag-ID under parent")
)

func BuildExifHeader Uses

func BuildExifHeader(byteOrder binary.ByteOrder, firstIfdOffset uint32) (headerBytes []byte, err error)

BuildExifHeader constructs the bytes that go in the very beginning.

Code:

headerBytes, err := BuildExifHeader(TestDefaultByteOrder, 0x11223344)
log.PanicIf(err)

eh, err := ParseExifHeader(headerBytes)
log.PanicIf(err)

fmt.Printf("%v\n", eh)

Output:

ExifHeader<BYTE-ORDER=[BigEndian] FIRST-IFD-OFFSET=(0x11223344)>

func Collect Uses

func Collect(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte) (eh ExifHeader, index IfdIndex, err error)

Collect recursively builds a static structure of all IFDs and tags.

func DumpBytes Uses

func DumpBytes(data []byte)

func DumpBytesClause Uses

func DumpBytesClause(data []byte)

func DumpBytesClauseToString Uses

func DumpBytesClauseToString(data []byte) string

func DumpBytesToString Uses

func DumpBytesToString(data []byte) string

func EncodeUnknown_9286 Uses

func EncodeUnknown_9286(uc TagUnknownType_9298_UserComment) (encoded []byte, err error)

func LoadStandardIfds Uses

func LoadStandardIfds(im *IfdMapping) (err error)

func LoadStandardTags Uses

func LoadStandardTags(ti *TagIndex) (err error)

LoadStandardTags registers the tags that all devices/applications should support.

func SearchAndExtractExif Uses

func SearchAndExtractExif(data []byte) (rawExif []byte, err error)

SearchAndExtractExif returns a slice from the beginning of the EXIF data to end of the file (it's not practical to try and calculate where the data actually ends; it needs to be formally parsed).

func SearchFileAndExtractExif Uses

func SearchFileAndExtractExif(filepath string) (rawExif []byte, err error)

SearchFileAndExtractExif returns a slice from the beginning of the EXIF data to the end of the file (it's not practical to try and calculate where the data actually ends).

func TagTypeSize Uses

func TagTypeSize(tagType uint16) int

func UndefinedValue Uses

func UndefinedValue(ifdPath string, tagId uint16, valueContext ValueContext, byteOrder binary.ByteOrder) (value interface{}, err error)

UndefinedValue knows how to resolve the value for most unknown-type tags.

type BuilderTag Uses

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

func NewBuilderTag Uses

func NewBuilderTag(ifdPath string, tagId uint16, typeId uint16, value *IfdBuilderTagValue) *BuilderTag

func NewChildIfdBuilderTag Uses

func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagValue) *BuilderTag

func NewStandardBuilderTag Uses

func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag

NewStandardBuilderTag constructs a `BuilderTag` instance. The type is looked up. `ii` is the type of IFD that owns this tag.

func (*BuilderTag) SetValue Uses

func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (err error)

Code:

filepath := path.Join(assetsPath, "NDM_8901.jpg")

rawExif, err := SearchFileAndExtractExif(filepath)
log.PanicIf(err)

im := NewIfdMapping()

err = LoadStandardIfds(im)
log.PanicIf(err)

ti := NewTagIndex()

_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)

// Create builder.

itevr := NewIfdTagEntryValueResolver(rawExif, index.RootIfd.ByteOrder)
rootIb := NewIfdBuilderFromExistingChain(index.RootIfd, itevr)

// Find tag to update.

exifBt, err := rootIb.FindTagWithName("ExifTag")
log.PanicIf(err)

ucBt, err := exifBt.value.Ib().FindTagWithName("UserComment")
log.PanicIf(err)

// Update the value. Since this is an "undefined"-type tag, we have to use
// its type-specific struct.

// TODO(dustin): !! Add an example for setting a non-unknown value, too.
uc := TagUnknownType_9298_UserComment{
    EncodingType:  TagUnknownType_9298_UserComment_Encoding_ASCII,
    EncodingBytes: []byte("TEST COMMENT"),
}

err = ucBt.SetValue(rootIb.byteOrder, uc)
log.PanicIf(err)

// Encode.

ibe := NewIfdByteEncoder()
updatedExif, err := ibe.EncodeToExif(rootIb)
log.PanicIf(err)

updatedExif = updatedExif

func (*BuilderTag) String Uses

func (bt *BuilderTag) String() string

func (*BuilderTag) Value Uses

func (bt *BuilderTag) Value() (value *IfdBuilderTagValue)

type ByteWriter Uses

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

func NewByteWriter Uses

func NewByteWriter(b *bytes.Buffer, byteOrder binary.ByteOrder) (bw *ByteWriter)

func (ByteWriter) WriteFourBytes Uses

func (bw ByteWriter) WriteFourBytes(value []byte) (err error)

func (ByteWriter) WriteUint16 Uses

func (bw ByteWriter) WriteUint16(value uint16) (err error)

func (ByteWriter) WriteUint32 Uses

func (bw ByteWriter) WriteUint32(value uint32) (err error)

type EncodeableUndefinedValue Uses

type EncodeableUndefinedValue struct {
    IfdPath    string
    TagId      uint16
    Parameters interface{}
}

type EncodedData Uses

type EncodedData struct {
    Type      uint16
    Encoded   []byte
    UnitCount uint32
}

EncodedData encapsulates the compound output of an encoding operation.

func EncodeUndefined Uses

func EncodeUndefined(ifdPath string, tagId uint16, value interface{}) (ed EncodedData, err error)

type ExifHeader Uses

type ExifHeader struct {
    ByteOrder      binary.ByteOrder
    FirstIfdOffset uint32
}

func ParseExifHeader Uses

func ParseExifHeader(data []byte) (eh ExifHeader, err error)

ParseExifHeader parses the bytes at the very top of the header.

This will panic with ErrNoExif on any data errors so that we can double as an EXIF-detection routine.

func Visit Uses

func Visit(rootIfdName string, ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error)

Visit recursively invokes a callback for every tag.

func (ExifHeader) String Uses

func (eh ExifHeader) String() string

type GpsDegrees Uses

type GpsDegrees struct {
    Orientation               byte
    Degrees, Minutes, Seconds int
}

func (GpsDegrees) Decimal Uses

func (d GpsDegrees) Decimal() float64

func (GpsDegrees) String Uses

func (d GpsDegrees) String() string

type GpsInfo Uses

type GpsInfo struct {
    Latitude, Longitude GpsDegrees
    Altitude            int
    Timestamp           time.Time
}

func (*GpsInfo) S2CellId Uses

func (gi *GpsInfo) S2CellId() s2.CellID

func (*GpsInfo) String Uses

func (gi *GpsInfo) String() string

type Ifd Uses

type Ifd struct {
    ByteOrder binary.ByteOrder

    // Name is the name of the IFD (the rightmost name in the path, sans any
    // indices).
    Name string

    // IfdPath is a simple IFD path (e.g. IFD/GPSInfo). No indices.
    IfdPath string

    // FqIfdPath is a fully-qualified IFD path (e.g. IFD0/GPSInfo0). With
    // indices.
    FqIfdPath string

    TagId uint16

    Id  int

    ParentIfd *Ifd

    // ParentTagIndex is our tag position in the parent IFD, if we had a parent
    // (if `ParentIfd` is not nil and we weren't an IFD referenced as a sibling
    // instead of as a child).
    ParentTagIndex int

    // Name   string
    Index  int
    Offset uint32

    Entries        []*IfdTagEntry
    EntriesByTagId map[uint16][]*IfdTagEntry

    Children []*Ifd

    ChildIfdIndex map[string]*Ifd

    NextIfdOffset uint32
    NextIfd       *Ifd
    // contains filtered or unexported fields
}

Ifd represents a single parsed IFD.

func FindIfdFromRootIfd Uses

func FindIfdFromRootIfd(rootIfd *Ifd, ifdPath string) (ifd *Ifd, err error)

func (*Ifd) ChildWithIfdPath Uses

func (ifd *Ifd) ChildWithIfdPath(ifdPath string) (childIfd *Ifd, err error)

func (*Ifd) DumpTags Uses

func (ifd *Ifd) DumpTags() []*IfdTagEntry

DumpTags prints the IFD hierarchy.

func (*Ifd) DumpTree Uses

func (ifd *Ifd) DumpTree() []string

DumpTree returns a list of strings describing the IFD hierarchy.

func (*Ifd) EnumerateTagsRecursively Uses

func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error)

Code:

filepath := path.Join(assetsPath, "NDM_8901.jpg")

rawExif, err := SearchFileAndExtractExif(filepath)
log.PanicIf(err)

im := NewIfdMapping()

err = LoadStandardIfds(im)
log.PanicIf(err)

ti := NewTagIndex()

_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)

cb := func(ifd *Ifd, ite *IfdTagEntry) error {

    // Something useful.

    return nil
}

err = index.RootIfd.EnumerateTagsRecursively(cb)
log.PanicIf(err)

func (*Ifd) FindTagWithId Uses

func (ifd *Ifd) FindTagWithId(tagId uint16) (results []*IfdTagEntry, err error)

FindTagWithId returns a list of tags (usually just zero or one) that match the given tag ID. This is efficient.

func (*Ifd) FindTagWithName Uses

func (ifd *Ifd) FindTagWithName(tagName string) (results []*IfdTagEntry, err error)

FindTagWithName returns a list of tags (usually just zero or one) that match the given tag name. This is not efficient (though the labor is trivial).

func (*Ifd) GpsInfo Uses

func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error)

GpsInfo parses and consolidates the GPS info. This can only be called on the GPS IFD.

Code:

filepath := path.Join(assetsPath, "gps.jpg")

rawExif, err := SearchFileAndExtractExif(filepath)
log.PanicIf(err)

im := NewIfdMapping()

err = LoadStandardIfds(im)
log.PanicIf(err)

ti := NewTagIndex()

_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)

ifd, err := index.RootIfd.ChildWithIfdPath(IfdPathStandardGps)
log.PanicIf(err)

gi, err := ifd.GpsInfo()
log.PanicIf(err)

fmt.Printf("%s\n", gi)

Output:

GpsInfo<LAT=(26.58667) LON=(-80.05361) ALT=(0) TIME=[2018-04-29 01:22:57 +0000 UTC]>

func (*Ifd) PrintIfdTree Uses

func (ifd *Ifd) PrintIfdTree()

PrintIfdTree prints the IFD hierarchy.

func (*Ifd) PrintTagTree Uses

func (ifd *Ifd) PrintTagTree(populateValues bool)

PrintTagTree prints the IFD hierarchy.

func (Ifd) String Uses

func (ifd Ifd) String() string

func (*Ifd) TagValue Uses

func (ifd *Ifd) TagValue(ite *IfdTagEntry) (value interface{}, err error)

func (*Ifd) TagValueBytes Uses

func (ifd *Ifd) TagValueBytes(ite *IfdTagEntry) (value []byte, err error)

func (*Ifd) Thumbnail Uses

func (ifd *Ifd) Thumbnail() (data []byte, err error)

Code:

filepath := path.Join(assetsPath, "NDM_8901.jpg")

rawExif, err := SearchFileAndExtractExif(filepath)
log.PanicIf(err)

im := NewIfdMapping()

err = LoadStandardIfds(im)
log.PanicIf(err)

ti := NewTagIndex()

_, index, err := Collect(im, ti, rawExif)
log.PanicIf(err)

thumbnailData, err := index.RootIfd.NextIfd.Thumbnail()
log.PanicIf(err)

thumbnailData = thumbnailData

type IfdBuilder Uses

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

func GetOrCreateIbFromRootIb Uses

func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, fqIfdPath string) (ib *IfdBuilder, err error)

GetOrCreateIbFromRootIb returns an IB representing the requested IFD, even if an IB doesn't already exist for it. This function may call itself recursively.

func NewIfdBuilder Uses

func NewIfdBuilder(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath string, byteOrder binary.ByteOrder) (ib *IfdBuilder)

func NewIfdBuilderFromExistingChain Uses

func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder)

NewIfdBuilderFromExistingChain creates a chain of IB instances from an IFD chain generated from real data.

func NewIfdBuilderWithExistingIfd Uses

func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder)

NewIfdBuilderWithExistingIfd creates a new IB using the same header type information as the given IFD.

func (*IfdBuilder) Add Uses

func (ib *IfdBuilder) Add(bt *BuilderTag) (err error)

func (*IfdBuilder) AddChildIb Uses

func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error)

AddChildIb adds a tag that branches to a new IFD.

func (*IfdBuilder) AddStandard Uses

func (ib *IfdBuilder) AddStandard(tagId uint16, value interface{}) (err error)

AddStandard quickly and easily composes and adds the tag using the information already known about a tag. Only works with standard tags.

func (*IfdBuilder) AddStandardWithName Uses

func (ib *IfdBuilder) AddStandardWithName(tagName string, value interface{}) (err error)

AddStandardWithName quickly and easily composes and adds the tag using the information already known about a tag (using the name). Only works with standard tags.

func (*IfdBuilder) AddTagsFromExisting Uses

func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResolver, includeTagIds []uint16, excludeTagIds []uint16) (err error)

AddTagsFromExisting does a verbatim copy of the entries in `ifd` to this builder. It excludes child IFDs. These must be added explicitly via `AddChildIb()`.

func (*IfdBuilder) ChildWithTagId Uses

func (ib *IfdBuilder) ChildWithTagId(childIfdTagId uint16) (childIb *IfdBuilder, err error)

func (*IfdBuilder) DeleteAll Uses

func (ib *IfdBuilder) DeleteAll(tagId uint16) (n int, err error)

func (*IfdBuilder) DeleteFirst Uses

func (ib *IfdBuilder) DeleteFirst(tagId uint16) (err error)

func (*IfdBuilder) DeleteN Uses

func (ib *IfdBuilder) DeleteN(tagId uint16, n int) (err error)

func (*IfdBuilder) DumpToStrings Uses

func (ib *IfdBuilder) DumpToStrings() (lines []string)

func (*IfdBuilder) Find Uses

func (ib *IfdBuilder) Find(tagId uint16) (position int, err error)

func (*IfdBuilder) FindN Uses

func (ib *IfdBuilder) FindN(tagId uint16, maxFound int) (found []int, err error)

func (*IfdBuilder) FindTag Uses

func (ib *IfdBuilder) FindTag(tagId uint16) (bt *BuilderTag, err error)

func (*IfdBuilder) FindTagWithName Uses

func (ib *IfdBuilder) FindTagWithName(tagName string) (bt *BuilderTag, err error)

func (*IfdBuilder) NewBuilderTagFromBuilder Uses

func (ib *IfdBuilder) NewBuilderTagFromBuilder(childIb *IfdBuilder) (bt *BuilderTag)

func (*IfdBuilder) PrintIfdTree Uses

func (ib *IfdBuilder) PrintIfdTree()

func (*IfdBuilder) PrintTagTree Uses

func (ib *IfdBuilder) PrintTagTree()

func (*IfdBuilder) Replace Uses

func (ib *IfdBuilder) Replace(tagId uint16, bt *BuilderTag) (err error)

func (*IfdBuilder) ReplaceAt Uses

func (ib *IfdBuilder) ReplaceAt(position int, bt *BuilderTag) (err error)

func (*IfdBuilder) Set Uses

func (ib *IfdBuilder) Set(bt *BuilderTag) (err error)

Set will add a new entry or update an existing entry.

func (*IfdBuilder) SetNextIb Uses

func (ib *IfdBuilder) SetNextIb(nextIb *IfdBuilder) (err error)

func (*IfdBuilder) SetStandard Uses

func (ib *IfdBuilder) SetStandard(tagId uint16, value interface{}) (err error)

SetStandard quickly and easily composes and adds or replaces the tag using the information already known about a tag. Only works with standard tags.

func (*IfdBuilder) SetStandardWithName Uses

func (ib *IfdBuilder) SetStandardWithName(tagName string, value interface{}) (err error)

SetStandardWithName quickly and easily composes and adds or replaces the tag using the information already known about a tag (using the name). Only works with standard tags.

func (*IfdBuilder) SetThumbnail Uses

func (ib *IfdBuilder) SetThumbnail(data []byte) (err error)

SetThumbnail sets thumbnail data.

NOTES:

- We don't manage any facet of the thumbnail data. This is the

responsibility of the user/developer.

- This method will fail unless the thumbnail is set on a the root IFD.

However, in order to be valid, it must be set on the second one, linked to
by the first, as per the EXIF/TIFF specification.

- We set the offset to (0) now but will allocate the data and properly assign

the offset when the IB is encoded (later).

func (*IfdBuilder) String Uses

func (ib *IfdBuilder) String() string

func (*IfdBuilder) Tags Uses

func (ib *IfdBuilder) Tags() (tags []*BuilderTag)

func (*IfdBuilder) Thumbnail Uses

func (ib *IfdBuilder) Thumbnail() []byte

type IfdBuilderTagValue Uses

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

func NewIfdBuilderTagValueFromBytes Uses

func NewIfdBuilderTagValueFromBytes(valueBytes []byte) *IfdBuilderTagValue

func NewIfdBuilderTagValueFromIfdBuilder Uses

func NewIfdBuilderTagValueFromIfdBuilder(ib *IfdBuilder) *IfdBuilderTagValue

func (IfdBuilderTagValue) Bytes Uses

func (ibtv IfdBuilderTagValue) Bytes() []byte

func (IfdBuilderTagValue) Ib Uses

func (ibtv IfdBuilderTagValue) Ib() *IfdBuilder

func (IfdBuilderTagValue) IsBytes Uses

func (ibtv IfdBuilderTagValue) IsBytes() bool

func (IfdBuilderTagValue) IsIb Uses

func (ibtv IfdBuilderTagValue) IsIb() bool

func (IfdBuilderTagValue) String Uses

func (ibtv IfdBuilderTagValue) String() string

type IfdByteEncoder Uses

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

IfdByteEncoder converts an IB to raw bytes (for writing) while also figuring out all of the allocations and indirection that is required for extended data.

func NewIfdByteEncoder Uses

func NewIfdByteEncoder() (ibe *IfdByteEncoder)

func (*IfdByteEncoder) EncodeToExif Uses

func (ibe *IfdByteEncoder) EncodeToExif(ib *IfdBuilder) (data []byte, err error)

EncodeToExif calls EncodeToExifPayload and then packages the result into a complete EXIF block.

Code:

// Construct an IFD.

im := NewIfdMapping()

err := LoadStandardIfds(im)
log.PanicIf(err)

ti := NewTagIndex()
ib := NewIfdBuilder(im, ti, IfdPathStandard, TestDefaultByteOrder)

err = ib.AddStandardWithName("ProcessingSoftware", "asciivalue")
log.PanicIf(err)

err = ib.AddStandardWithName("DotRange", []uint8{0x11})
log.PanicIf(err)

err = ib.AddStandardWithName("SubfileType", []uint16{0x2233})
log.PanicIf(err)

err = ib.AddStandardWithName("ImageWidth", []uint32{0x44556677})
log.PanicIf(err)

err = ib.AddStandardWithName("WhitePoint", []Rational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err)

err = ib.AddStandardWithName("ShutterSpeedValue", []SignedRational{{Numerator: 0x11112222, Denominator: 0x33334444}})
log.PanicIf(err)

// Encode it.

ibe := NewIfdByteEncoder()

exifData, err := ibe.EncodeToExif(ib)
log.PanicIf(err)

// Parse it so we can see it.

_, index, err := Collect(im, ti, exifData)
log.PanicIf(err)

// addressableData is the byte-slice where the allocated data can be
// resolved (where position 0x0 will correlate with offset 0x0).
addressableData := exifData[ExifAddressableAreaStart:]

for i, e := range index.RootIfd.Entries {
    value, err := e.Value(addressableData, TestDefaultByteOrder)
    log.PanicIf(err)

    fmt.Printf("%d: %s [%v]\n", i, e, value)
}

Output:

0: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x000b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
1: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
2: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x00ff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
3: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x0100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
4: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x013e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
5: IfdTagEntry<TAG-IFD-PATH=[IFD] TAG-ID=(0x9201) TAG-TYPE=[SRATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]

func (*IfdByteEncoder) EncodeToExifPayload Uses

func (ibe *IfdByteEncoder) EncodeToExifPayload(ib *IfdBuilder) (data []byte, err error)

EncodeToExifPayload is the base encoding step that transcribes the entire IB structure to its on-disk layout.

func (*IfdByteEncoder) Journal Uses

func (ibe *IfdByteEncoder) Journal() [][3]string

func (*IfdByteEncoder) PrintJournal Uses

func (ibe *IfdByteEncoder) PrintJournal()

PrintJournal prints a hierarchical representation of the steps taken during encoding.

func (*IfdByteEncoder) TableSize Uses

func (ibe *IfdByteEncoder) TableSize(entryCount int) uint32

type IfdEnumerate Uses

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

func NewIfdEnumerate Uses

func NewIfdEnumerate(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, byteOrder binary.ByteOrder) *IfdEnumerate

func (*IfdEnumerate) Collect Uses

func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error)

Scan enumerates the different EXIF blocks (called IFDs).

func (*IfdEnumerate) ParseIfd Uses

func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor RawTagVisitor, doDescend bool, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error)

ParseIfd decodes the IFD block that we're currently sitting on the first byte of.

func (*IfdEnumerate) Scan Uses

func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagVisitor, resolveValue bool) (err error)

Scan enumerates the different EXIF blocks (called IFDs). `rootIfdName` will be "IFD" in the TIFF standard.

type IfdIndex Uses

type IfdIndex struct {
    RootIfd *Ifd
    Ifds    []*Ifd
    Tree    map[int]*Ifd
    Lookup  map[string][]*Ifd
}

type IfdMapping Uses

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

IfdMapping describes all of the IFDs that we currently recognize.

func NewIfdMapping Uses

func NewIfdMapping() (ifdMapping *IfdMapping)

func NewIfdMappingWithStandard Uses

func NewIfdMappingWithStandard() (ifdMapping *IfdMapping)

func (*IfdMapping) Add Uses

func (im *IfdMapping) Add(parentPlacement []uint16, tagId uint16, name string) (err error)

Add puts the given IFD at the given position of the tree. The position of the tree is referred to as the placement and is represented by a set of tag-IDs, where the leftmost is the root tag and the tags going to the right are progressive descendants.

func (*IfdMapping) DumpLineages Uses

func (im *IfdMapping) DumpLineages() (output []string, err error)

func (*IfdMapping) FqPathPhraseFromLineage Uses

func (im *IfdMapping) FqPathPhraseFromLineage(lineage []IfdTagIdAndIndex) (fqPathPhrase string)

func (*IfdMapping) Get Uses

func (im *IfdMapping) Get(parentPlacement []uint16) (childIfd *MappedIfd, err error)

func (*IfdMapping) GetChild Uses

func (im *IfdMapping) GetChild(parentPathPhrase string, tagId uint16) (mi *MappedIfd, err error)

GetChild is a convenience function to get the child path for a given parent placement and child tag-ID.

func (*IfdMapping) GetWithPath Uses

func (im *IfdMapping) GetWithPath(pathPhrase string) (mi *MappedIfd, err error)

func (*IfdMapping) PathPhraseFromLineage Uses

func (im *IfdMapping) PathPhraseFromLineage(lineage []IfdTagIdAndIndex) (pathPhrase string)

func (*IfdMapping) ResolvePath Uses

func (im *IfdMapping) ResolvePath(pathPhrase string) (lineage []IfdTagIdAndIndex, err error)

ResolvePath takes a list of names, which can also be suffixed with indices (to identify the second, third, etc.. sibling IFD) and returns a list of tag-IDs and those indices.

Example:

- IFD/Exif/Iop - IFD0/Exif/Iop

This is the only call that supports adding the numeric indices.

func (*IfdMapping) StripPathPhraseIndices Uses

func (im *IfdMapping) StripPathPhraseIndices(pathPhrase string) (strippedPathPhrase string, err error)

StripPathPhraseIndices returns a non-fully-qualified path-phrase (no indices).

type IfdTagEntry Uses

type IfdTagEntry struct {
    TagId          uint16
    TagIndex       int
    TagType        uint16
    UnitCount      uint32
    ValueOffset    uint32
    RawValueOffset []byte

    // ChildIfdName is the right most atom in the IFD-path. We need this to
    // construct the fully-qualified IFD-path.
    ChildIfdName string

    // ChildIfdPath is the IFD-path of the child if this tag represents a child
    // IFD.
    ChildIfdPath string

    // ChildFqIfdPath is the IFD-path of the child if this tag represents a
    // child IFD. Includes indices.
    ChildFqIfdPath string

    // IfdPath is the IFD that this tag belongs to.
    IfdPath string
    // contains filtered or unexported fields
}

func ParseOneIfd Uses

func ParseOneIfd(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, ifdBlock []byte, visitor RawTagVisitor, resolveValues bool) (nextIfdOffset uint32, entries []*IfdTagEntry, err error)

ParseOneIfd is a hack to use an IE to parse a raw IFD block. Can be used for testing.

func ParseOneTag Uses

func ParseOneTag(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath, ifdPath string, byteOrder binary.ByteOrder, tagBlock []byte, resolveValue bool) (tag *IfdTagEntry, err error)

ParseOneTag is a hack to use an IE to parse a raw tag block.

func (IfdTagEntry) String Uses

func (ite IfdTagEntry) String() string

func (IfdTagEntry) Value Uses

func (ite IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder) (value interface{}, err error)

Value returns the specific, parsed, typed value from the tag.

func (IfdTagEntry) ValueBytes Uses

func (ite IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteOrder) (value []byte, err error)

ValueBytes renders a specific list of bytes from the value in this tag.

func (IfdTagEntry) ValueString Uses

func (ite IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (value string, err error)

ValueString renders a string from whatever the value in this tag is.

type IfdTagEntryValueResolver Uses

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

IfdTagEntryValueResolver instances know how to resolve the values for any tag for a particular EXIF block.

func NewIfdTagEntryValueResolver Uses

func NewIfdTagEntryValueResolver(exifData []byte, byteOrder binary.ByteOrder) (itevr *IfdTagEntryValueResolver)

func (*IfdTagEntryValueResolver) ValueBytes Uses

func (itevr *IfdTagEntryValueResolver) ValueBytes(ite *IfdTagEntry) (value []byte, err error)

ValueBytes will resolve embedded or allocated data from the tag and return the raw bytes.

type IfdTagEnumerator Uses

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

IfdTagEnumerator knows how to decode an IFD and all of the tags it describes.

The IFDs and the actual values can float throughout the EXIF block, but the IFD itself is just a minor header followed by a set of repeating, statically-sized records. So, the tags (though notnecessarily their values) are fairly simple to enumerate.

func NewIfdTagEnumerator Uses

func NewIfdTagEnumerator(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (ite *IfdTagEnumerator)

type IfdTagIdAndIndex Uses

type IfdTagIdAndIndex struct {
    Name  string
    TagId uint16
    Index int
}

func (IfdTagIdAndIndex) String Uses

func (itii IfdTagIdAndIndex) String() string

type IndexedTag Uses

type IndexedTag struct {
    Id      uint16
    Name    string
    IfdPath string
    Type    uint16
}

func (*IndexedTag) Is Uses

func (it *IndexedTag) Is(ifdPath string, id uint16) bool

func (*IndexedTag) IsName Uses

func (it *IndexedTag) IsName(ifdPath, name string) bool

func (*IndexedTag) String Uses

func (it *IndexedTag) String() string

type MappedIfd Uses

type MappedIfd struct {
    ParentTagId uint16
    Placement   []uint16
    Path        []string

    Name     string
    TagId    uint16
    Children map[uint16]*MappedIfd
}

func (*MappedIfd) PathPhrase Uses

func (mi *MappedIfd) PathPhrase() string

func (*MappedIfd) String Uses

func (mi *MappedIfd) String() string

type ParsedTagVisitor Uses

type ParsedTagVisitor func(*Ifd, *IfdTagEntry) error

type QueuedIfd Uses

type QueuedIfd struct {
    Name      string
    IfdPath   string
    FqIfdPath string

    TagId uint16

    Index  int
    Offset uint32
    Parent *Ifd

    // ParentTagIndex is our tag position in the parent IFD, if we had a parent
    // (if `ParentIfd` is not nil and we weren't an IFD referenced as a sibling
    // instead of as a child).
    ParentTagIndex int
}

type Rational Uses

type Rational struct {
    Numerator   uint32
    Denominator uint32
}

type RawTagVisitor Uses

type RawTagVisitor func(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext ValueContext) (err error)

RawTagVisitor is an optional callback that can get hit for every tag we parse through. `addressableData` is the byte array startign after the EXIF header (where the offsets of all IFDs and values are calculated from).

type SignedRational Uses

type SignedRational struct {
    Numerator   int32
    Denominator int32
}

type TagIndex Uses

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

func NewTagIndex Uses

func NewTagIndex() *TagIndex

func (*TagIndex) Add Uses

func (ti *TagIndex) Add(it *IndexedTag) (err error)

func (*TagIndex) Get Uses

func (ti *TagIndex) Get(ifdPath string, id uint16) (it *IndexedTag, err error)

Get returns information about the non-IFD tag.

func (*TagIndex) GetWithName Uses

func (ti *TagIndex) GetWithName(ifdPath string, name string) (it *IndexedTag, err error)

Get returns information about the non-IFD tag.

type TagType Uses

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

func NewTagType Uses

func NewTagType(tagType uint16, byteOrder binary.ByteOrder) TagType

func (TagType) ByteOrder Uses

func (tt TagType) ByteOrder() binary.ByteOrder

func (TagType) Encode Uses

func (tt TagType) Encode(value interface{}) (encoded []byte, err error)

Encode knows how to encode the given value to a byte slice.

func (TagType) FromString Uses

func (tt TagType) FromString(valueString string) (value interface{}, err error)

func (TagType) Name Uses

func (tt TagType) Name() string

func (TagType) ParseAscii Uses

func (tt TagType) ParseAscii(data []byte, unitCount uint32) (value string, err error)

ParseAscii returns a string and auto-strips the trailing NUL character.

func (TagType) ParseAsciiNoNul Uses

func (tt TagType) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, err error)

ParseAsciiNoNul returns a string without any consideration for a trailing NUL character.

func (TagType) ParseBytes Uses

func (tt TagType) ParseBytes(data []byte, unitCount uint32) (value []uint8, err error)

func (TagType) ParseLongs Uses

func (tt TagType) ParseLongs(data []byte, unitCount uint32) (value []uint32, err error)

func (TagType) ParseRationals Uses

func (tt TagType) ParseRationals(data []byte, unitCount uint32) (value []Rational, err error)

func (TagType) ParseShorts Uses

func (tt TagType) ParseShorts(data []byte, unitCount uint32) (value []uint16, err error)

func (TagType) ParseSignedLongs Uses

func (tt TagType) ParseSignedLongs(data []byte, unitCount uint32) (value []int32, err error)

func (TagType) ParseSignedRationals Uses

func (tt TagType) ParseSignedRationals(data []byte, unitCount uint32) (value []SignedRational, err error)

func (TagType) ReadAsciiNoNulValue Uses

func (tt TagType) ReadAsciiNoNulValue(valueContext ValueContext) (value string, err error)

func (TagType) ReadAsciiValue Uses

func (tt TagType) ReadAsciiValue(valueContext ValueContext) (value string, err error)

func (TagType) ReadByteValues Uses

func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err error)

func (TagType) ReadLongValues Uses

func (tt TagType) ReadLongValues(valueContext ValueContext) (value []uint32, err error)

func (TagType) ReadRationalValues Uses

func (tt TagType) ReadRationalValues(valueContext ValueContext) (value []Rational, err error)

func (TagType) ReadShortValues Uses

func (tt TagType) ReadShortValues(valueContext ValueContext) (value []uint16, err error)

func (TagType) ReadSignedLongValues Uses

func (tt TagType) ReadSignedLongValues(valueContext ValueContext) (value []int32, err error)

func (TagType) ReadSignedRationalValues Uses

func (tt TagType) ReadSignedRationalValues(valueContext ValueContext) (value []SignedRational, err error)

func (TagType) Resolve Uses

func (tt TagType) Resolve(valueContext ValueContext) (value interface{}, err error)

Value knows how to resolve the given value.

Since this method lacks the information to process unknown-type tags (e.g. byte-order, tag-ID, IFD type), it will return an error if attempted. See `UndefinedValue()`.

func (TagType) ResolveAsString Uses

func (tt TagType) ResolveAsString(valueContext ValueContext, justFirst bool) (value string, err error)

ResolveAsString resolves the given value and returns a flat string.

Where the type is not ASCII, `justFirst` indicates whether to just stringify the first item in the slice (or return an empty string if the slice is empty).

Since this method lacks the information to process unknown-type tags (e.g. byte-order, tag-ID, IFD type), it will return an error if attempted. See `UndefinedValue()`.

func (TagType) Size Uses

func (tt TagType) Size() int

func (TagType) String Uses

func (tt TagType) String() string

func (TagType) Type Uses

func (tt TagType) Type() uint16

func (TagType) ValueIsEmbedded Uses

func (tt TagType) ValueIsEmbedded(unitCount uint32) bool

ValueIsEmbedded will return a boolean indicating whether the value should be found directly within the IFD entry or an offset to somewhere else.

type TagUnknownType_9101_ComponentsConfiguration Uses

type TagUnknownType_9101_ComponentsConfiguration struct {
    ConfigurationId    int
    ConfigurationBytes []byte
}

func (TagUnknownType_9101_ComponentsConfiguration) String Uses

func (cc TagUnknownType_9101_ComponentsConfiguration) String() string

func (TagUnknownType_9101_ComponentsConfiguration) ValueBytes Uses

func (uc TagUnknownType_9101_ComponentsConfiguration) ValueBytes() (value []byte, err error)

type TagUnknownType_927C_MakerNote Uses

type TagUnknownType_927C_MakerNote struct {
    MakerNoteType  []byte
    MakerNoteBytes []byte
}

func (TagUnknownType_927C_MakerNote) String Uses

func (mn TagUnknownType_927C_MakerNote) String() string

func (TagUnknownType_927C_MakerNote) ValueBytes Uses

func (uc TagUnknownType_927C_MakerNote) ValueBytes() (value []byte, err error)

type TagUnknownType_9298_UserComment Uses

type TagUnknownType_9298_UserComment struct {
    EncodingType  int
    EncodingBytes []byte
}

func (TagUnknownType_9298_UserComment) String Uses

func (uc TagUnknownType_9298_UserComment) String() string

func (TagUnknownType_9298_UserComment) ValueBytes Uses

func (uc TagUnknownType_9298_UserComment) ValueBytes() (value []byte, err error)

type TagUnknownType_GeneralString Uses

type TagUnknownType_GeneralString string

func (TagUnknownType_GeneralString) ValueBytes Uses

func (gs TagUnknownType_GeneralString) ValueBytes() (value []byte, err error)

type UnknownTagValue Uses

type UnknownTagValue interface {
    ValueBytes() ([]byte, error)
}

type ValueContext Uses

type ValueContext struct {
    UnitCount       uint32
    ValueOffset     uint32
    RawValueOffset  []byte
    AddressableData []byte
}

ValueContext describes all of the parameters required to find and extract the actual tag value.

type ValueEncoder Uses

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

func NewValueEncoder Uses

func NewValueEncoder(byteOrder binary.ByteOrder) *ValueEncoder

func (*ValueEncoder) Encode Uses

func (ve *ValueEncoder) Encode(value interface{}) (ed EncodedData, err error)

Encode returns bytes for the given value, infering type from the actual value. This does not support `TypeAsciiNoNull` (all strings are encoded as `TypeAscii`).

func (*ValueEncoder) EncodeWithType Uses

func (ve *ValueEncoder) EncodeWithType(tt TagType, value interface{}) (ed EncodedData, err error)

EncodeWithType returns bytes for the given value, using the given `TagType` value to determine how to encode. This supports `TypeAsciiNoNul`.

Directories

PathSynopsis
exif-read-toolThis tool dumps EXIF information from images.

Package exif imports 14 packages (graph) and is imported by 4 packages. Updated 2018-11-15. Refresh now. Tools for package owners.