Documentation ¶
Overview ¶
exif parses raw EXIF information given a block of raw EXIF data.
v1 of go-exif is now deprecated. Please use v2.
Index ¶
- Constants
- Variables
- func BuildExifHeader(byteOrder binary.ByteOrder, firstIfdOffset uint32) (headerBytes []byte, err error)
- func Collect(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte) (eh ExifHeader, index IfdIndex, err error)
- func DumpBytes(data []byte)
- func DumpBytesClause(data []byte)
- func DumpBytesClauseToString(data []byte) string
- func DumpBytesToString(data []byte) string
- func EncodeStringToBytes(tagType TagTypePrimitive, valueString string) (value interface{}, err error)
- func EncodeUnknown_9286(uc TagUnknownType_9298_UserComment) (encoded []byte, err error)
- func ExifFullTimestampString(t time.Time) (fullTimestampPhrase string)
- func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, ...) (value string, err error)
- func LoadStandardIfds(im *IfdMapping) (err error)
- func LoadStandardTags(ti *TagIndex) (err error)
- func ParseExifFullTimestamp(fullTimestampPhrase string) (timestamp time.Time, err error)
- func SearchAndExtractExif(data []byte) (rawExif []byte, err error)
- func SearchFileAndExtractExif(filepath string) (rawExif []byte, err error)
- func TagTypeSize(tagType TagTypePrimitive) int
- func UndefinedValue(ifdPath string, tagId uint16, valueContext interface{}, ...) (value interface{}, err error)
- type BuilderTag
- func NewBuilderTag(ifdPath string, tagId uint16, typeId TagTypePrimitive, ...) *BuilderTag
- func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagValue) *BuilderTag
- func NewStandardBuilderTag(ifdPath string, it *IndexedTag, byteOrder binary.ByteOrder, value interface{}) *BuilderTag
- type ByteWriter
- type EncodeableUndefinedValue
- type EncodedData
- type ExifHeader
- type ExifTag
- type GpsDegrees
- type GpsInfo
- type Ifd
- func (ifd *Ifd) ChildWithIfdPath(ifdPath string) (childIfd *Ifd, err error)
- func (ifd *Ifd) DumpTags() []*IfdTagEntry
- func (ifd *Ifd) DumpTree() []string
- func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error)
- func (ifd *Ifd) FindTagWithId(tagId uint16) (results []*IfdTagEntry, err error)
- func (ifd *Ifd) FindTagWithName(tagName string) (results []*IfdTagEntry, err error)
- func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *ValueContext
- func (ifd *Ifd) GpsInfo() (gi *GpsInfo, err error)
- func (ifd *Ifd) PrintIfdTree()
- func (ifd *Ifd) PrintTagTree(populateValues bool)
- func (ifd Ifd) String() string
- func (ifd *Ifd) TagValue(ite *IfdTagEntry) (value interface{}, err error)
- func (ifd *Ifd) TagValueBytes(ite *IfdTagEntry) (value []byte, err error)
- func (ifd *Ifd) Thumbnail() (data []byte, err error)
- type IfdBuilder
- func GetOrCreateIbFromRootIb(rootIb *IfdBuilder, fqIfdPath string) (ib *IfdBuilder, err error)
- func NewIfdBuilder(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath string, ...) (ib *IfdBuilder)
- func NewIfdBuilderFromExistingChain(rootIfd *Ifd, itevr *IfdTagEntryValueResolver) (firstIb *IfdBuilder)
- func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder)
- func (ib *IfdBuilder) Add(bt *BuilderTag) (err error)
- func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error)
- func (ib *IfdBuilder) AddStandard(tagId uint16, value interface{}) (err error)
- func (ib *IfdBuilder) AddStandardWithName(tagName string, value interface{}) (err error)
- func (ib *IfdBuilder) AddTagsFromExisting(ifd *Ifd, itevr *IfdTagEntryValueResolver, includeTagIds []uint16, ...) (err error)
- func (ib *IfdBuilder) ChildWithTagId(childIfdTagId uint16) (childIb *IfdBuilder, err error)
- func (ib *IfdBuilder) DeleteAll(tagId uint16) (n int, err error)
- func (ib *IfdBuilder) DeleteFirst(tagId uint16) (err error)
- func (ib *IfdBuilder) DeleteN(tagId uint16, n int) (err error)
- func (ib *IfdBuilder) DumpToStrings() (lines []string)
- func (ib *IfdBuilder) Find(tagId uint16) (position int, err error)
- func (ib *IfdBuilder) FindN(tagId uint16, maxFound int) (found []int, err error)
- func (ib *IfdBuilder) FindTag(tagId uint16) (bt *BuilderTag, err error)
- func (ib *IfdBuilder) FindTagWithName(tagName string) (bt *BuilderTag, err error)
- func (ib *IfdBuilder) NewBuilderTagFromBuilder(childIb *IfdBuilder) (bt *BuilderTag)
- func (ib *IfdBuilder) NextIb() (nextIb *IfdBuilder, err error)
- func (ib *IfdBuilder) PrintIfdTree()
- func (ib *IfdBuilder) PrintTagTree()
- func (ib *IfdBuilder) Replace(tagId uint16, bt *BuilderTag) (err error)
- func (ib *IfdBuilder) ReplaceAt(position int, bt *BuilderTag) (err error)
- func (ib *IfdBuilder) Set(bt *BuilderTag) (err error)
- func (ib *IfdBuilder) SetNextIb(nextIb *IfdBuilder) (err error)
- func (ib *IfdBuilder) SetStandard(tagId uint16, value interface{}) (err error)
- func (ib *IfdBuilder) SetStandardWithName(tagName string, value interface{}) (err error)
- func (ib *IfdBuilder) SetThumbnail(data []byte) (err error)
- func (ib *IfdBuilder) String() string
- func (ib *IfdBuilder) Tags() (tags []*BuilderTag)
- func (ib *IfdBuilder) Thumbnail() []byte
- type IfdBuilderTagValue
- type IfdByteEncoder
- func (ibe *IfdByteEncoder) EncodeToExif(ib *IfdBuilder) (data []byte, err error)
- func (ibe *IfdByteEncoder) EncodeToExifPayload(ib *IfdBuilder) (data []byte, err error)
- func (ibe *IfdByteEncoder) Journal() [][3]string
- func (ibe *IfdByteEncoder) PrintJournal()
- func (ibe *IfdByteEncoder) TableSize(entryCount int) uint32
- type IfdEnumerate
- func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error)
- func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *ValueContext
- func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor interface{}, ...) (nextIfdOffset uint32, entries []*IfdTagEntry, thumbnailData []byte, err error)
- func (ie *IfdEnumerate) Scan(rootIfdName string, ifdOffset uint32, visitor RawTagVisitor, resolveValue bool) (err error)
- type IfdIndex
- type IfdMapping
- func (im *IfdMapping) Add(parentPlacement []uint16, tagId uint16, name string) (err error)
- func (im *IfdMapping) DumpLineages() (output []string, err error)
- func (im *IfdMapping) FqPathPhraseFromLineage(lineage []IfdTagIdAndIndex) (fqPathPhrase string)
- func (im *IfdMapping) Get(parentPlacement []uint16) (childIfd *MappedIfd, err error)
- func (im *IfdMapping) GetChild(parentPathPhrase string, tagId uint16) (mi *MappedIfd, err error)
- func (im *IfdMapping) GetWithPath(pathPhrase string) (mi *MappedIfd, err error)
- func (im *IfdMapping) PathPhraseFromLineage(lineage []IfdTagIdAndIndex) (pathPhrase string)
- func (im *IfdMapping) ResolvePath(pathPhrase string) (lineage []IfdTagIdAndIndex, err error)
- func (im *IfdMapping) StripPathPhraseIndices(pathPhrase string) (strippedPathPhrase string, err error)
- type IfdTagEntry
- func (ite *IfdTagEntry) String() string
- func (ite *IfdTagEntry) Value(addressableData []byte, byteOrder binary.ByteOrder) (value interface{}, err error)
- func (ite *IfdTagEntry) ValueBytes(addressableData []byte, byteOrder binary.ByteOrder) (value []byte, err error)
- func (ite *IfdTagEntry) ValueString(addressableData []byte, byteOrder binary.ByteOrder) (value string, err error)
- type IfdTagEntryValueResolver
- type IfdTagEnumerator
- type IfdTagIdAndIndex
- type IndexedTag
- type MappedIfd
- type ParsedTagVisitor
- type Parser
- func (p *Parser) ParseAscii(data []byte, unitCount uint32) (value string, err error)
- func (p *Parser) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, err error)
- func (p *Parser) ParseBytes(data []byte, unitCount uint32) (value []uint8, err error)
- func (p *Parser) ParseLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint32, err error)
- func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []Rational, err error)
- func (p *Parser) ParseShorts(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []uint16, err error)
- func (p *Parser) ParseSignedLongs(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []int32, err error)
- func (p *Parser) ParseSignedRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []SignedRational, err error)
- type QueuedIfd
- type Rational
- type RawTagVisitor
- type RawTagWalk
- type RawTagWalkLegacyWrapper
- type SignedRational
- type TagIndex
- type TagType
- func (tt TagType) ByteOrder() binary.ByteOrder
- func (tt TagType) Encode(value interface{}) (encoded []byte, err error)
- func (tt TagType) FromString(valueString string) (value interface{}, err error)
- func (tt TagType) Name() string
- func (tt TagType) ParseAscii(data []byte, unitCount uint32) (value string, err error)
- func (tt TagType) ParseAsciiNoNul(data []byte, unitCount uint32) (value string, err error)
- func (tt TagType) ParseBytes(data []byte, unitCount uint32) (value []uint8, err error)
- func (tt TagType) ParseLongs(data []byte, unitCount uint32) (value []uint32, err error)
- func (tt TagType) ParseRationals(data []byte, unitCount uint32) (value []Rational, err error)
- func (tt TagType) ParseShorts(data []byte, unitCount uint32) (value []uint16, err error)
- func (tt TagType) ParseSignedLongs(data []byte, unitCount uint32) (value []int32, err error)
- func (tt TagType) ParseSignedRationals(data []byte, unitCount uint32) (value []SignedRational, err error)
- func (tt TagType) ReadAsciiNoNulValue(valueContext ValueContext) (value string, err error)
- func (tt TagType) ReadAsciiValue(valueContext ValueContext) (value string, err error)
- func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err error)
- func (tt TagType) ReadLongValues(valueContext ValueContext) (value []uint32, err error)
- func (tt TagType) ReadRationalValues(valueContext ValueContext) (value []Rational, err error)
- func (tt TagType) ReadShortValues(valueContext ValueContext) (value []uint16, err error)
- func (tt TagType) ReadSignedLongValues(valueContext ValueContext) (value []int32, err error)
- func (tt TagType) ReadSignedRationalValues(valueContext ValueContext) (value []SignedRational, err error)
- func (tt TagType) Resolve(valueContext *ValueContext) (values interface{}, err error)
- func (tt TagType) ResolveAsString(valueContext ValueContext, justFirst bool) (value string, err error)
- func (tt TagType) Size() int
- func (tt TagType) String() string
- func (tt TagType) Type() TagTypePrimitive
- type TagTypePrimitive
- type TagUnknownType_9101_ComponentsConfiguration
- type TagUnknownType_927C_MakerNote
- type TagUnknownType_9298_UserComment
- type TagUnknownType_GeneralString
- type TagUnknownType_UnknownValue
- type UnknownTagValue
- type ValueContext
- func (vc *ValueContext) AddressableData() []byte
- func (vc *ValueContext) Format() (value string, err error)
- func (vc *ValueContext) FormatFirst() (value string, err error)
- func (vc *ValueContext) RawValueOffset() []byte
- func (vc *ValueContext) ReadAscii() (value string, err error)
- func (vc *ValueContext) ReadAsciiNoNul() (value string, err error)
- func (vc *ValueContext) ReadBytes() (value []byte, err error)
- func (vc *ValueContext) ReadLongs() (value []uint32, err error)
- func (vc *ValueContext) ReadRationals() (value []Rational, err error)
- func (vc *ValueContext) ReadShorts() (value []uint16, err error)
- func (vc *ValueContext) ReadSignedLongs() (value []int32, err error)
- func (vc *ValueContext) ReadSignedRationals() (value []SignedRational, err error)
- func (vc *ValueContext) SetUnknownValueType(tagType TagTypePrimitive)
- func (vc *ValueContext) Undefined() (value interface{}, err error)
- func (vc *ValueContext) UnitCount() uint32
- func (vc *ValueContext) ValueOffset() uint32
- func (vc *ValueContext) Values() (values interface{}, err error)
- type ValueEncoder
Examples ¶
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 ( // Tag-ID + Tag-Type + Unit-Count + Value/Offset. IfdTagEntrySize = uint32(2 + 2 + 4 + 4) )
const (
UnparseableUnknownTagValuePlaceholder = "!UNKNOWN"
)
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: {0x2a, 0x00}, binary.BigEndian: {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") ErrTagTypeNotValid = errors.New("tag type invalid") )
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: {'A', 'S', 'C', 'I', 'I', 0, 0, 0}, TagUnknownType_9298_UserComment_Encoding_JIS: {'J', 'I', 'S', 0, 0, 0, 0, 0}, TagUnknownType_9298_UserComment_Encoding_UNICODE: {'U', 'n', 'i', 'c', 'o', 'd', 'e', 0}, TagUnknownType_9298_UserComment_Encoding_UNDEFINED: {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: { TagUnknownType_9101_ComponentsConfiguration_Channel_R, TagUnknownType_9101_ComponentsConfiguration_Channel_G, TagUnknownType_9101_ComponentsConfiguration_Channel_B, 0, }, TagUnknownType_9101_ComponentsConfiguration_YCBCR: { TagUnknownType_9101_ComponentsConfiguration_Channel_Y, TagUnknownType_9101_ComponentsConfiguration_Channel_Cb, TagUnknownType_9101_ComponentsConfiguration_Channel_Cr, 0, }, } )
var ( // TODO(dustin): Rename TypeNames() to typeNames() and add getter. TypeNames = map[TagTypePrimitive]string{ TypeByte: "BYTE", TypeAscii: "ASCII", TypeShort: "SHORT", TypeLong: "LONG", TypeRational: "RATIONAL", TypeUndefined: "UNDEFINED", TypeSignedLong: "SLONG", TypeSignedRational: "SRATIONAL", TypeAsciiNoNul: "_ASCII_NO_NUL", } TypeNamesR = map[string]TagTypePrimitive{} )
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")
)
var (
ErrGpsCoordinatesNotValid = errors.New("GPS coordinates not valid")
)
var (
ValidGpsVersions = [][4]byte{
{2, 2, 0, 0},
{2, 3, 0, 0},
}
)
Functions ¶
func BuildExifHeader ¶
func BuildExifHeader(byteOrder binary.ByteOrder, firstIfdOffset uint32) (headerBytes []byte, err error)
BuildExifHeader constructs the bytes that go in the very beginning.
Example ¶
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 ¶
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 DumpBytesClause ¶
func DumpBytesClause(data []byte)
func DumpBytesClauseToString ¶
func DumpBytesToString ¶
func EncodeStringToBytes ¶
func EncodeStringToBytes(tagType TagTypePrimitive, valueString string) (value interface{}, err error)
func EncodeUnknown_9286 ¶
func EncodeUnknown_9286(uc TagUnknownType_9298_UserComment) (encoded []byte, err error)
func ExifFullTimestampString ¶
ExifFullTimestampString produces a string like "2018:11:30 13:01:49" from a `time.Time` struct. It will attempt to convert to UTC first.
Example ¶
originalPhrase := "2018:11:30 13:01:49" timestamp, err := ParseExifFullTimestamp(originalPhrase) log.PanicIf(err) restoredPhrase := ExifFullTimestampString(timestamp) fmt.Printf("To EXIF timestamp: [%s]\n", restoredPhrase)
Output: To EXIF timestamp: [2018:11:30 13:01:49]
func Format ¶
func Format(rawBytes []byte, tagType TagTypePrimitive, justFirst bool, byteOrder binary.ByteOrder) (value string, err error)
Format returns a stringified value for the given bytes. Automatically calculates count based on type size.
func LoadStandardIfds ¶
func LoadStandardIfds(im *IfdMapping) (err error)
func LoadStandardTags ¶
LoadStandardTags registers the tags that all devices/applications should support.
func ParseExifFullTimestamp ¶
ParseExifFullTimestamp parses dates like "2018:11:30 13:01:49" into a UTC `time.Time` struct.
Example ¶
originalPhrase := "2018:11:30 13:01:49" timestamp, err := ParseExifFullTimestamp(originalPhrase) log.PanicIf(err) fmt.Printf("To Go timestamp: [%s]\n", timestamp.Format(time.RFC3339))
Output: To Go timestamp: [2018-11-30T13:01:49Z]
func SearchAndExtractExif ¶
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 ¶
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 ¶
func TagTypeSize(tagType TagTypePrimitive) int
Types ¶
type BuilderTag ¶
type BuilderTag struct {
// contains filtered or unexported fields
}
func NewBuilderTag ¶
func NewBuilderTag(ifdPath string, tagId uint16, typeId TagTypePrimitive, value *IfdBuilderTagValue, byteOrder binary.ByteOrder) *BuilderTag
func NewChildIfdBuilderTag ¶
func NewChildIfdBuilderTag(ifdPath string, tagId uint16, value *IfdBuilderTagValue) *BuilderTag
func NewStandardBuilderTag ¶
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 ¶
func (bt *BuilderTag) SetValue(byteOrder binary.ByteOrder, value interface{}) (err error)
Example ¶
rawExif, err := SearchFileAndExtractExif(testImageFilepath) log.PanicIf(err) im := NewIfdMapping() err = LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() _, index, err := Collect(im, ti, rawExif) log.PanicIf(err) // Create builder. rootIb := NewIfdBuilderFromExistingChain(index.RootIfd, nil) // 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
Output:
func (*BuilderTag) String ¶
func (bt *BuilderTag) String() string
func (*BuilderTag) Value ¶
func (bt *BuilderTag) Value() (value *IfdBuilderTagValue)
type ByteWriter ¶
type ByteWriter struct {
// contains filtered or unexported fields
}
func NewByteWriter ¶
func NewByteWriter(b *bytes.Buffer, byteOrder binary.ByteOrder) (bw *ByteWriter)
func (ByteWriter) WriteFourBytes ¶
func (bw ByteWriter) WriteFourBytes(value []byte) (err error)
func (ByteWriter) WriteUint16 ¶
func (bw ByteWriter) WriteUint16(value uint16) (err error)
func (ByteWriter) WriteUint32 ¶
func (bw ByteWriter) WriteUint32(value uint32) (err error)
type EncodedData ¶
type EncodedData struct { Type TagTypePrimitive Encoded []byte // TODO(dustin): Is this really necessary? We might have this just to correlate to the incoming stream format (raw bytes and a unit-count both for incoming and outgoing). UnitCount uint32 }
EncodedData encapsulates the compound output of an encoding operation.
func EncodeUndefined ¶
func EncodeUndefined(ifdPath string, tagId uint16, value interface{}) (ed EncodedData, err error)
type ExifHeader ¶
func ParseExifHeader ¶
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 ¶
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 ¶
func (eh ExifHeader) String() string
type ExifTag ¶
type ExifTag struct { IfdPath string `json:"ifd_path"` TagId uint16 `json:"id"` TagName string `json:"name"` TagTypeId TagTypePrimitive `json:"type_id"` TagTypeName string `json:"type_name"` Value interface{} `json:"value"` ValueBytes []byte `json:"value_bytes"` ChildIfdPath string `json:"child_ifd_path"` }
ExifTag is one simple representation of a tag in a flat list of all of them.
func GetFlatExifData ¶
GetFlatExifData returns a simple, flat representation of all tags.
type GpsDegrees ¶
func (GpsDegrees) Decimal ¶
func (d GpsDegrees) Decimal() float64
func (GpsDegrees) String ¶
func (d GpsDegrees) String() string
type GpsInfo ¶
type GpsInfo struct {
Latitude, Longitude GpsDegrees
Altitude int
Timestamp time.Time
}
type Ifd ¶
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 ¶
func (*Ifd) ChildWithIfdPath ¶
func (*Ifd) EnumerateTagsRecursively ¶
func (ifd *Ifd) EnumerateTagsRecursively(visitor ParsedTagVisitor) (err error)
Example ¶
rawExif, err := SearchFileAndExtractExif(testImageFilepath) 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)
Output:
func (*Ifd) FindTagWithId ¶
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 ¶
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).
Example ¶
rawExif, err := SearchFileAndExtractExif(testImageFilepath) log.PanicIf(err) im := NewIfdMapping() err = LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() _, index, err := Collect(im, ti, rawExif) log.PanicIf(err) tagName := "Model" // We know the tag we want is on IFD0 (the first/root IFD). results, err := index.RootIfd.FindTagWithName(tagName) log.PanicIf(err) // This should never happen. if len(results) != 1 { log.Panicf("there wasn't exactly one result") } ite := results[0] valueRaw, err := index.RootIfd.TagValue(ite) log.PanicIf(err) value := valueRaw.(string) fmt.Println(value)
Output: Canon EOS 5D Mark III
func (*Ifd) GetValueContext ¶
func (ifd *Ifd) GetValueContext(ite *IfdTagEntry) *ValueContext
func (*Ifd) GpsInfo ¶
GpsInfo parses and consolidates the GPS info. This can only be called on the GPS IFD.
Example ¶
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) PrintTagTree ¶
PrintTagTree prints the IFD hierarchy.
func (*Ifd) TagValue ¶
func (ifd *Ifd) TagValue(ite *IfdTagEntry) (value interface{}, err error)
func (*Ifd) TagValueBytes ¶
func (ifd *Ifd) TagValueBytes(ite *IfdTagEntry) (value []byte, err error)
func (*Ifd) Thumbnail ¶
Example ¶
rawExif, err := SearchFileAndExtractExif(testImageFilepath) 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
Output:
type IfdBuilder ¶
type IfdBuilder struct {
// contains filtered or unexported fields
}
func GetOrCreateIbFromRootIb ¶
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 ¶
func NewIfdBuilder(ifdMapping *IfdMapping, tagIndex *TagIndex, fqIfdPath string, byteOrder binary.ByteOrder) (ib *IfdBuilder)
func NewIfdBuilderFromExistingChain ¶
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 ¶
func NewIfdBuilderWithExistingIfd(ifd *Ifd) (ib *IfdBuilder)
NewIfdBuilderWithExistingIfd creates a new IB using the same header type information as the given IFD.
func (*IfdBuilder) Add ¶
func (ib *IfdBuilder) Add(bt *BuilderTag) (err error)
func (*IfdBuilder) AddChildIb ¶
func (ib *IfdBuilder) AddChildIb(childIb *IfdBuilder) (err error)
AddChildIb adds a tag that branches to a new IFD.
func (*IfdBuilder) AddStandard ¶
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 ¶
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 ¶
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 ¶
func (ib *IfdBuilder) ChildWithTagId(childIfdTagId uint16) (childIb *IfdBuilder, err error)
func (*IfdBuilder) DeleteFirst ¶
func (ib *IfdBuilder) DeleteFirst(tagId uint16) (err error)
func (*IfdBuilder) DumpToStrings ¶
func (ib *IfdBuilder) DumpToStrings() (lines []string)
func (*IfdBuilder) FindN ¶
func (ib *IfdBuilder) FindN(tagId uint16, maxFound int) (found []int, err error)
func (*IfdBuilder) FindTag ¶
func (ib *IfdBuilder) FindTag(tagId uint16) (bt *BuilderTag, err error)
func (*IfdBuilder) FindTagWithName ¶
func (ib *IfdBuilder) FindTagWithName(tagName string) (bt *BuilderTag, err error)
func (*IfdBuilder) NewBuilderTagFromBuilder ¶
func (ib *IfdBuilder) NewBuilderTagFromBuilder(childIb *IfdBuilder) (bt *BuilderTag)
func (*IfdBuilder) NextIb ¶
func (ib *IfdBuilder) NextIb() (nextIb *IfdBuilder, err error)
func (*IfdBuilder) PrintIfdTree ¶
func (ib *IfdBuilder) PrintIfdTree()
func (*IfdBuilder) PrintTagTree ¶
func (ib *IfdBuilder) PrintTagTree()
func (*IfdBuilder) Replace ¶
func (ib *IfdBuilder) Replace(tagId uint16, bt *BuilderTag) (err error)
func (*IfdBuilder) ReplaceAt ¶
func (ib *IfdBuilder) ReplaceAt(position int, bt *BuilderTag) (err error)
func (*IfdBuilder) Set ¶
func (ib *IfdBuilder) Set(bt *BuilderTag) (err error)
Set will add a new entry or update an existing entry.
func (*IfdBuilder) SetNextIb ¶
func (ib *IfdBuilder) SetNextIb(nextIb *IfdBuilder) (err error)
func (*IfdBuilder) SetStandard ¶
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 ¶
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.
Example ¶
ExampleIfdBuilder_SetStandardWithName establishes a chain of `IfdBuilder` structs from an existing chain of `Ifd` structs, navigates to the IB representing IFD0, updates the ProcessingSoftware tag to a different value, encodes down to a new EXIF block, reparses, and validates that the value for that tag is what we set it to.
rawExif, err := SearchFileAndExtractExif(testImageFilepath) log.PanicIf(err) // Boilerplate. im := NewIfdMapping() err = LoadStandardIfds(im) log.PanicIf(err) ti := NewTagIndex() // Load current IFDs. _, index, err := Collect(im, ti, rawExif) log.PanicIf(err) ib := NewIfdBuilderFromExistingChain(index.RootIfd, nil) // Read the IFD whose tag we want to change. // Standard: // - "IFD0" // - "IFD0/Exif0" // - "IFD0/Exif0/Iop0" // - "IFD0/GPSInfo0" // // If the numeric indices are not included, (0) is the default. Note that // this isn't strictly necessary in our case since IFD0 is the first IFD anyway, but we're putting it here to show usage. ifdPath := "IFD0" childIb, err := GetOrCreateIbFromRootIb(ib, ifdPath) log.PanicIf(err) // There are a few functions that allow you to surgically change the tags in an // IFD, but we're just gonna overwrite a tag that has an ASCII value. tagName := "ProcessingSoftware" err = childIb.SetStandardWithName(tagName, "alternative software") log.PanicIf(err) // Encode the in-memory representation back down to bytes. ibe := NewIfdByteEncoder() updatedRawExif, err := ibe.EncodeToExif(ib) log.PanicIf(err) // Reparse the EXIF to confirm that our value is there. _, index, err = Collect(im, ti, updatedRawExif) log.PanicIf(err) // This isn't strictly necessary for the same reason as above, but it's here // for documentation. childIfd, err := FindIfdFromRootIfd(index.RootIfd, ifdPath) log.PanicIf(err) results, err := childIfd.FindTagWithName(tagName) log.PanicIf(err) for _, ite := range results { value, err := childIfd.TagValue(ite) log.PanicIf(err) stringValue := value.(string) fmt.Println(stringValue) }
Output: alternative software
func (*IfdBuilder) SetThumbnail ¶
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 ¶
func (ib *IfdBuilder) String() string
func (*IfdBuilder) Tags ¶
func (ib *IfdBuilder) Tags() (tags []*BuilderTag)
func (*IfdBuilder) Thumbnail ¶
func (ib *IfdBuilder) Thumbnail() []byte
type IfdBuilderTagValue ¶
type IfdBuilderTagValue struct {
// contains filtered or unexported fields
}
func NewIfdBuilderTagValueFromBytes ¶
func NewIfdBuilderTagValueFromBytes(valueBytes []byte) *IfdBuilderTagValue
func NewIfdBuilderTagValueFromIfdBuilder ¶
func NewIfdBuilderTagValueFromIfdBuilder(ib *IfdBuilder) *IfdBuilderTagValue
func (IfdBuilderTagValue) Bytes ¶
func (ibtv IfdBuilderTagValue) Bytes() []byte
func (IfdBuilderTagValue) Ib ¶
func (ibtv IfdBuilderTagValue) Ib() *IfdBuilder
func (IfdBuilderTagValue) IsBytes ¶
func (ibtv IfdBuilderTagValue) IsBytes() bool
IsBytes returns true if the bytes are populated. This is always the case when we're loaded from a tag in an existing IFD.
func (IfdBuilderTagValue) IsIb ¶
func (ibtv IfdBuilderTagValue) IsIb() bool
func (IfdBuilderTagValue) String ¶
func (ibtv IfdBuilderTagValue) String() string
type IfdByteEncoder ¶
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 ¶
func NewIfdByteEncoder() (ibe *IfdByteEncoder)
func (*IfdByteEncoder) EncodeToExif ¶
func (ibe *IfdByteEncoder) EncodeToExif(ib *IfdBuilder) (data []byte, err error)
EncodeToExif calls EncodeToExifPayload and then packages the result into a complete EXIF block.
Example ¶
// 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 ¶
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 ¶
func (ibe *IfdByteEncoder) Journal() [][3]string
func (*IfdByteEncoder) PrintJournal ¶
func (ibe *IfdByteEncoder) PrintJournal()
PrintJournal prints a hierarchical representation of the steps taken during encoding.
func (*IfdByteEncoder) TableSize ¶
func (ibe *IfdByteEncoder) TableSize(entryCount int) uint32
type IfdEnumerate ¶
type IfdEnumerate struct {
// contains filtered or unexported fields
}
func NewIfdEnumerate ¶
func NewIfdEnumerate(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, byteOrder binary.ByteOrder) *IfdEnumerate
func (*IfdEnumerate) Collect ¶
func (ie *IfdEnumerate) Collect(rootIfdOffset uint32, resolveValues bool) (index IfdIndex, err error)
Scan enumerates the different EXIF blocks (called IFDs).
func (*IfdEnumerate) GetValueContext ¶
func (ie *IfdEnumerate) GetValueContext(ite *IfdTagEntry) *ValueContext
func (*IfdEnumerate) ParseIfd ¶
func (ie *IfdEnumerate) ParseIfd(fqIfdPath string, ifdIndex int, ite *IfdTagEnumerator, visitor interface{}, 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 ¶
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 IfdMapping ¶
type IfdMapping struct {
// contains filtered or unexported fields
}
IfdMapping describes all of the IFDs that we currently recognize.
func NewIfdMapping ¶
func NewIfdMapping() (ifdMapping *IfdMapping)
func NewIfdMappingWithStandard ¶
func NewIfdMappingWithStandard() (ifdMapping *IfdMapping)
func (*IfdMapping) Add ¶
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 ¶
func (im *IfdMapping) DumpLineages() (output []string, err error)
func (*IfdMapping) FqPathPhraseFromLineage ¶
func (im *IfdMapping) FqPathPhraseFromLineage(lineage []IfdTagIdAndIndex) (fqPathPhrase string)
func (*IfdMapping) Get ¶
func (im *IfdMapping) Get(parentPlacement []uint16) (childIfd *MappedIfd, err error)
func (*IfdMapping) GetChild ¶
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 ¶
func (im *IfdMapping) GetWithPath(pathPhrase string) (mi *MappedIfd, err error)
func (*IfdMapping) PathPhraseFromLineage ¶
func (im *IfdMapping) PathPhraseFromLineage(lineage []IfdTagIdAndIndex) (pathPhrase string)
func (*IfdMapping) ResolvePath ¶
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 ¶
func (im *IfdMapping) StripPathPhraseIndices(pathPhrase string) (strippedPathPhrase string, err error)
StripPathPhraseIndices returns a non-fully-qualified path-phrase (no indices).
type IfdTagEntry ¶
type IfdTagEntry struct { TagId uint16 TagIndex int TagType TagTypePrimitive 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 ¶
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 ¶
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 ¶
func (ite *IfdTagEntry) String() string
func (*IfdTagEntry) Value ¶
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 ¶
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 ¶
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 ¶
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 ¶
func NewIfdTagEntryValueResolver(exifData []byte, byteOrder binary.ByteOrder) (itevr *IfdTagEntryValueResolver)
func (*IfdTagEntryValueResolver) Value ¶
func (itevr *IfdTagEntryValueResolver) Value(ite *IfdTagEntry) (value interface{}, err error)
func (*IfdTagEntryValueResolver) ValueBytes ¶
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 ¶
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 ¶
func NewIfdTagEnumerator(addressableData []byte, byteOrder binary.ByteOrder, ifdOffset uint32) (ite *IfdTagEnumerator)
type IfdTagIdAndIndex ¶
func (IfdTagIdAndIndex) String ¶
func (itii IfdTagIdAndIndex) String() string
type IndexedTag ¶
type IndexedTag struct { Id uint16 Name string IfdPath string Type TagTypePrimitive }
func (*IndexedTag) IsName ¶
func (it *IndexedTag) IsName(ifdPath, name string) bool
func (*IndexedTag) String ¶
func (it *IndexedTag) String() string
type MappedIfd ¶
type MappedIfd struct { ParentTagId uint16 Placement []uint16 Path []string Name string TagId uint16 Children map[uint16]*MappedIfd }
func (*MappedIfd) PathPhrase ¶
type ParsedTagVisitor ¶
type ParsedTagVisitor func(*Ifd, *IfdTagEntry) error
type Parser ¶
type Parser struct { }
func (*Parser) ParseAscii ¶
ParseAscii returns a string and auto-strips the trailing NUL character.
func (*Parser) ParseAsciiNoNul ¶
ParseAsciiNoNul returns a string without any consideration for a trailing NUL character.
func (*Parser) ParseBytes ¶
func (*Parser) ParseLongs ¶
func (*Parser) ParseRationals ¶
func (*Parser) ParseShorts ¶
func (*Parser) ParseSignedLongs ¶
func (*Parser) ParseSignedRationals ¶
type QueuedIfd ¶
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 RawTagVisitor ¶
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).
DEPRECATED(dustin): Use a RawTagWalk instead.
type RawTagWalk ¶
type RawTagWalk interface {
Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext *ValueContext) (err error)
}
RawTagVisitorPtr 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).
This was reimplemented as an interface to allow for simpler change management in the future.
type RawTagWalkLegacyWrapper ¶
type RawTagWalkLegacyWrapper struct {
// contains filtered or unexported fields
}
func (RawTagWalkLegacyWrapper) Visit ¶
func (rtwlw RawTagWalkLegacyWrapper) Visit(fqIfdPath string, ifdIndex int, tagId uint16, tagType TagType, valueContext *ValueContext) (err error)
type SignedRational ¶
type TagIndex ¶
type TagIndex struct {
// contains filtered or unexported fields
}
func NewTagIndex ¶
func NewTagIndex() *TagIndex
func (*TagIndex) Add ¶
func (ti *TagIndex) Add(it *IndexedTag) (err error)
func (*TagIndex) Get ¶
func (ti *TagIndex) Get(ifdPath string, id uint16) (it *IndexedTag, err error)
Get returns information about the non-IFD tag.
func (*TagIndex) GetWithName ¶
func (ti *TagIndex) GetWithName(ifdPath string, name string) (it *IndexedTag, err error)
Get returns information about the non-IFD tag.
type TagType ¶
type TagType struct {
// contains filtered or unexported fields
}
func NewTagType ¶
func NewTagType(tagType TagTypePrimitive, byteOrder binary.ByteOrder) TagType
func (TagType) FromString ¶
func (TagType) ParseAscii ¶
ParseAscii returns a string and auto-strips the trailing NUL character.
func (TagType) ParseAsciiNoNul ¶
ParseAsciiNoNul returns a string without any consideration for a trailing NUL character.
func (TagType) ParseBytes ¶
func (TagType) ParseLongs ¶
func (TagType) ParseRationals ¶
func (TagType) ParseShorts ¶
func (TagType) ParseSignedLongs ¶
func (TagType) ParseSignedRationals ¶
func (tt TagType) ParseSignedRationals(data []byte, unitCount uint32) (value []SignedRational, err error)
func (TagType) ReadAsciiNoNulValue ¶
func (tt TagType) ReadAsciiNoNulValue(valueContext ValueContext) (value string, err error)
func (TagType) ReadAsciiValue ¶
func (tt TagType) ReadAsciiValue(valueContext ValueContext) (value string, err error)
func (TagType) ReadByteValues ¶
func (tt TagType) ReadByteValues(valueContext ValueContext) (value []byte, err error)
func (TagType) ReadLongValues ¶
func (tt TagType) ReadLongValues(valueContext ValueContext) (value []uint32, err error)
func (TagType) ReadRationalValues ¶
func (tt TagType) ReadRationalValues(valueContext ValueContext) (value []Rational, err error)
func (TagType) ReadShortValues ¶
func (tt TagType) ReadShortValues(valueContext ValueContext) (value []uint16, err error)
func (TagType) ReadSignedLongValues ¶
func (tt TagType) ReadSignedLongValues(valueContext ValueContext) (value []int32, err error)
func (TagType) ReadSignedRationalValues ¶
func (tt TagType) ReadSignedRationalValues(valueContext ValueContext) (value []SignedRational, err error)
func (TagType) Resolve ¶
func (tt TagType) Resolve(valueContext *ValueContext) (values interface{}, err error)
Resolve 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 `Undefined()`.
func (TagType) ResolveAsString ¶
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 `Undefined()`.
func (TagType) Type ¶
func (tt TagType) Type() TagTypePrimitive
type TagTypePrimitive ¶
type TagTypePrimitive uint16
const ( TypeByte TagTypePrimitive = 1 TypeAscii TagTypePrimitive = 2 TypeShort TagTypePrimitive = 3 TypeLong TagTypePrimitive = 4 TypeRational TagTypePrimitive = 5 TypeUndefined TagTypePrimitive = 7 TypeSignedLong TagTypePrimitive = 9 TypeSignedRational TagTypePrimitive = 10 // TypeAsciiNoNul is just a pseudo-type, for our own purposes. TypeAsciiNoNul TagTypePrimitive = 0xf0 )
func (TagTypePrimitive) Size ¶
func (tagType TagTypePrimitive) Size() int
func (TagTypePrimitive) String ¶
func (typeType TagTypePrimitive) String() string
type TagUnknownType_9101_ComponentsConfiguration ¶
type TagUnknownType_9101_ComponentsConfiguration struct { ConfigurationId int ConfigurationBytes []byte }
func (TagUnknownType_9101_ComponentsConfiguration) String ¶
func (cc TagUnknownType_9101_ComponentsConfiguration) String() string
func (TagUnknownType_9101_ComponentsConfiguration) ValueBytes ¶
func (uc TagUnknownType_9101_ComponentsConfiguration) ValueBytes() (value []byte, err error)
type TagUnknownType_927C_MakerNote ¶
func (TagUnknownType_927C_MakerNote) String ¶
func (mn TagUnknownType_927C_MakerNote) String() string
func (TagUnknownType_927C_MakerNote) ValueBytes ¶
func (uc TagUnknownType_927C_MakerNote) ValueBytes() (value []byte, err error)
type TagUnknownType_9298_UserComment ¶
func (TagUnknownType_9298_UserComment) String ¶
func (uc TagUnknownType_9298_UserComment) String() string
func (TagUnknownType_9298_UserComment) ValueBytes ¶
func (uc TagUnknownType_9298_UserComment) ValueBytes() (value []byte, err error)
type TagUnknownType_GeneralString ¶
type TagUnknownType_GeneralString string
func (TagUnknownType_GeneralString) ValueBytes ¶
func (gs TagUnknownType_GeneralString) ValueBytes() (value []byte, err error)
type TagUnknownType_UnknownValue ¶
type TagUnknownType_UnknownValue []byte
func (TagUnknownType_UnknownValue) String ¶
func (tutuv TagUnknownType_UnknownValue) String() string
type UnknownTagValue ¶
type ValueContext ¶
type ValueContext struct {
// contains filtered or unexported fields
}
ValueContext describes all of the parameters required to find and extract the actual tag value.
func (*ValueContext) AddressableData ¶
func (vc *ValueContext) AddressableData() []byte
func (*ValueContext) Format ¶
func (vc *ValueContext) Format() (value string, err error)
Format returns a string representation for the value.
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 undefined-type tags (e.g. byte-order, tag-ID, IFD type), it will return an error if attempted. See `Undefined()`.
func (*ValueContext) FormatFirst ¶
func (vc *ValueContext) FormatFirst() (value string, err error)
FormatOne is similar to `Format` but only gets and stringifies the first item.
func (*ValueContext) RawValueOffset ¶
func (vc *ValueContext) RawValueOffset() []byte
func (*ValueContext) ReadAscii ¶
func (vc *ValueContext) ReadAscii() (value string, err error)
func (*ValueContext) ReadAsciiNoNul ¶
func (vc *ValueContext) ReadAsciiNoNul() (value string, err error)
func (*ValueContext) ReadBytes ¶
func (vc *ValueContext) ReadBytes() (value []byte, err error)
func (*ValueContext) ReadLongs ¶
func (vc *ValueContext) ReadLongs() (value []uint32, err error)
func (*ValueContext) ReadRationals ¶
func (vc *ValueContext) ReadRationals() (value []Rational, err error)
func (*ValueContext) ReadShorts ¶
func (vc *ValueContext) ReadShorts() (value []uint16, err error)
func (*ValueContext) ReadSignedLongs ¶
func (vc *ValueContext) ReadSignedLongs() (value []int32, err error)
func (*ValueContext) ReadSignedRationals ¶
func (vc *ValueContext) ReadSignedRationals() (value []SignedRational, err error)
func (*ValueContext) SetUnknownValueType ¶
func (vc *ValueContext) SetUnknownValueType(tagType TagTypePrimitive)
func (*ValueContext) Undefined ¶
func (vc *ValueContext) Undefined() (value interface{}, err error)
Undefined attempts to identify and decode supported undefined-type fields. This is the primary, preferred interface to reading undefined values.
func (*ValueContext) UnitCount ¶
func (vc *ValueContext) UnitCount() uint32
func (*ValueContext) ValueOffset ¶
func (vc *ValueContext) ValueOffset() uint32
func (*ValueContext) Values ¶
func (vc *ValueContext) Values() (values interface{}, err error)
Values knows how to resolve the given value. This value is always a list (undefined-values aside), so we're named accordingly.
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 `Undefined()`.
type ValueEncoder ¶
type ValueEncoder struct {
// contains filtered or unexported fields
}
func NewValueEncoder ¶
func NewValueEncoder(byteOrder binary.ByteOrder) *ValueEncoder
func (*ValueEncoder) Encode ¶
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 ¶
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`.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
This tool dumps EXIF information from images.
|
This tool dumps EXIF information from images. |