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 (
    // The root IFD types (ifd0, ifd1).
    IfdStandard = "IFD"

    // Child IFD types.
    IfdExif = "Exif"
    IfdGps  = "GPSInfo"
    IfdIop  = "Iop"

    // Tag IDs for child IFDs.
    IfdExifId = 0x8769
    IfdGpsId  = 0x8825
    IfdIopId  = 0xA005
)
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 (

    // A lookup for IFDs by their parents.
    // TODO(dustin): !! We should switch to indexing by their unique integer IDs (defined below) rather than exposing ourselves to non-unique IFD names (even if we *do* manage the naming ourselves).
    IfdTagIds = map[string]map[string]uint16{
        "": map[string]uint16{

            IfdStandard: 0x0,
        },

        IfdStandard: map[string]uint16{
            IfdExif: IfdExifId,
            IfdGps:  IfdGpsId,
        },

        IfdExif: map[string]uint16{
            IfdIop: IfdIopId,
        },
    }

    // IfdTagNames contains the tag ID-to-name mappings and is populated by
    // init().
    IfdTagNames = map[string]map[uint16]string{}

    // The NULL-type instance for search misses and empty responses.
    ZeroIi = IfdIdentity{}

    RootIi    = IfdIdentity{IfdName: IfdStandard}
    ExifIi    = IfdIdentity{ParentIfdName: IfdStandard, IfdName: IfdExif}
    GpsIi     = IfdIdentity{ParentIfdName: IfdStandard, IfdName: IfdGps}
    ExifIopIi = IfdIdentity{ParentIfdName: IfdExif, IfdName: IfdIop}

    // Produce a list of unique IDs for each IFD that we can pass around (so we
    // don't always have to be comparing parent and child names).
    //
    // For lack of need, this is just static.
    //
    // (0) is reserved for not-found/miss responses.
    IfdIds = map[IfdIdentity]int{
        RootIi:    1,
        ExifIi:    2,
        GpsIi:     3,
        ExifIopIi: 4,
    }

    IfdDesignations = map[string]IfdNameAndIndex{
        "ifd0": {RootIi, 0},
        "ifd1": {RootIi, 1},
        "exif": {ExifIi, 0},
        "gps":  {GpsIi, 0},
        "iop":  {ExifIopIi, 0},
    }

    IfdDesignationsR = make(map[IfdNameAndIndex]string)
)
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")
)

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 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 IfdDesignation Uses

func IfdDesignation(ii IfdIdentity, index int) string

func IfdIdWithIdentity Uses

func IfdIdWithIdentity(ii IfdIdentity) int

func IfdIdWithIdentityOrFail Uses

func IfdIdWithIdentityOrFail(ii IfdIdentity) int

func IfdTagIdWithIdentity Uses

func IfdTagIdWithIdentity(ii IfdIdentity) (tagId uint16, found bool)

IfdTagIdWithIdentity returns true if the given tag points to a child IFD block.

func IfdTagIdWithIdentityOrFail Uses

func IfdTagIdWithIdentityOrFail(ii IfdIdentity) (tagId uint16)

func IfdTagNameWithId Uses

func IfdTagNameWithId(parentIfdName string, tagId uint16) (name string, found bool)

func IfdTagNameWithIdOrFail Uses

func IfdTagNameWithIdOrFail(parentIfdName string, tagId uint16) string

IfdTagWithId returns true if the given tag points to a child IFD block.

func ParseOneIfd Uses

func ParseOneIfd(ii IfdIdentity, 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 SearchAndExtractExif Uses

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

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

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(ii IfdIdentity, 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(ii IfdIdentity, tagId uint16, typeId uint16, value *IfdBuilderTagValue) *BuilderTag

func NewChildIfdBuilderTag Uses

func NewChildIfdBuilderTag(ii IfdIdentity, tagId uint16, value *IfdBuilderTagValue) *BuilderTag

func NewStandardBuilderTag Uses

func NewStandardBuilderTag(ii IfdIdentity, tagId uint16, 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 NewStandardBuilderTagWithName Uses

func NewStandardBuilderTagWithName(ii IfdIdentity, tagName string, byteOrder binary.ByteOrder, value interface{}) *BuilderTag

NewStandardBuilderTagWithName allows us to easily generate solid, consistent tags for testing with. `ii` is the type of IFD that owns this tag. This can not be an IFD (IFDs are not associated with standardized, official names).

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)

_, index, err := Collect(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 {
    Ii         IfdIdentity
    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(ii IfdIdentity, tagId uint16, value interface{}) (ed EncodedData, err error)

type ExifHeader Uses

type ExifHeader struct {
    ByteOrder      binary.ByteOrder
    FirstIfdOffset uint32
}

func Collect Uses

func Collect(exifData []byte) (eh ExifHeader, index IfdIndex, err error)

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

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(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

    Ii    IfdIdentity
    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, ifdDesignation string) (ifd *Ifd, err error)

func (*Ifd) ChildWithIfdIdentity Uses

func (ifd *Ifd) ChildWithIfdIdentity(ii IfdIdentity) (childIfd *Ifd, err error)

func (*Ifd) ChildWithName Uses

func (ifd *Ifd) ChildWithName(ifdName 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)

_, index, err := Collect(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)

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

ifd, err := index.RootIfd.ChildWithIfdIdentity(GpsIi)
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) Identity Uses

func (ifd *Ifd) Identity() IfdIdentity

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)

_, index, err := Collect(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, ifdDesignation string) (ib *IfdBuilder, err error)

func NewIfdBuilder Uses

func NewIfdBuilder(ii IfdIdentity, 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) ChildWithIfdIdentity Uses

func (ib *IfdBuilder) ChildWithIfdIdentity(ii IfdIdentity) (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.

ib := NewIfdBuilder(RootIi, 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(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=[] TAG-ID=(0x000b) TAG-TYPE=[ASCII] UNIT-COUNT=(11)> [asciivalue]
1: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0150) TAG-TYPE=[BYTE] UNIT-COUNT=(1)> [[17]]
2: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x00ff) TAG-TYPE=[SHORT] UNIT-COUNT=(1)> [[8755]]
3: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x0100) TAG-TYPE=[LONG] UNIT-COUNT=(1)> [[1146447479]]
4: IfdTagEntry<TAG-IFD=[] TAG-ID=(0x013e) TAG-TYPE=[RATIONAL] UNIT-COUNT=(1)> [[{286335522 858997828}]]
5: IfdTagEntry<TAG-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(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(ii IfdIdentity, 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(ifdOffset uint32, visitor RawTagVisitor, resolveValue bool) (err error)

Scan enumerates the different EXIF blocks (called IFDs).

type IfdIdentity Uses

type IfdIdentity struct {
    ParentIfdName string
    IfdName       string
}

func IfdId Uses

func IfdId(parentIfdName, ifdName string) (ii IfdIdentity, id int)

func IfdIdOrFail Uses

func IfdIdOrFail(parentIfdName, ifdName string) (ii IfdIdentity, id int)

func (IfdIdentity) Id Uses

func (ii IfdIdentity) Id() int

func (IfdIdentity) String Uses

func (ii IfdIdentity) String() string

type IfdIndex Uses

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

type IfdNameAndIndex Uses

type IfdNameAndIndex struct {
    Ii    IfdIdentity
    Index int
}

type IfdTagEntry Uses

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

    // ChildIfdName is a name if this tag represents a child IFD.
    ChildIfdName string

    // IfdName is the IFD that this tag belongs to.
    Ii  IfdIdentity
    // contains filtered or unexported fields
}

func ParseOneTag Uses

func ParseOneTag(ii IfdIdentity, 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 IndexedTag Uses

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

func (IndexedTag) Is Uses

func (it IndexedTag) Is(ifd string, id uint16) bool

func (IndexedTag) IsName Uses

func (it IndexedTag) IsName(ifd, name string) bool

func (IndexedTag) String Uses

func (it IndexedTag) String() string

type ParsedTagVisitor Uses

type ParsedTagVisitor func(*Ifd, *IfdTagEntry) error

type QueuedIfd Uses

type QueuedIfd struct {
    Ii    IfdIdentity
    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(ii IfdIdentity, 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) Get Uses

func (ti *TagIndex) Get(ii IfdIdentity, id uint16) (it *IndexedTag, err error)

Get returns information about the non-IFD tag.

func (*TagIndex) GetWithName Uses

func (ti *TagIndex) GetWithName(ii IfdIdentity, 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-06-18. Refresh now. Tools for package owners.