diff options
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/exif.go')
-rw-r--r-- | vendor/github.com/dsoprea/go-exif/exif.go | 247 |
1 files changed, 0 insertions, 247 deletions
diff --git a/vendor/github.com/dsoprea/go-exif/exif.go b/vendor/github.com/dsoprea/go-exif/exif.go deleted file mode 100644 index 8d1b848f0..000000000 --- a/vendor/github.com/dsoprea/go-exif/exif.go +++ /dev/null @@ -1,247 +0,0 @@ -package exif - -import ( - "bytes" - "errors" - "fmt" - "os" - - "encoding/binary" - "io/ioutil" - - "github.com/dsoprea/go-logging" -) - -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) -) - -var ( - exifLogger = log.NewLogger("exif.exif") - - // 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") -) - -// 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 SearchAndExtractExif(data []byte) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err := log.Wrap(state.(error)) - log.Panic(err) - } - }() - - // Search for the beginning of the EXIF information. The EXIF is near the - // beginning of our/most JPEGs, so this has a very low cost. - - foundAt := -1 - for i := 0; i < len(data); i++ { - if _, err := ParseExifHeader(data[i:]); err == nil { - foundAt = i - break - } else if log.Is(err, ErrNoExif) == false { - return nil, err - } - } - - if foundAt == -1 { - return nil, ErrNoExif - } - - return data[foundAt:], nil -} - -// 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 SearchFileAndExtractExif(filepath string) (rawExif []byte, err error) { - defer func() { - if state := recover(); state != nil { - err := log.Wrap(state.(error)) - log.Panic(err) - } - }() - - // Open the file. - - f, err := os.Open(filepath) - log.PanicIf(err) - - defer f.Close() - - data, err := ioutil.ReadAll(f) - log.PanicIf(err) - - rawExif, err = SearchAndExtractExif(data) - log.PanicIf(err) - - return rawExif, nil -} - -type ExifHeader struct { - ByteOrder binary.ByteOrder - FirstIfdOffset uint32 -} - -func (eh ExifHeader) String() string { - return fmt.Sprintf("ExifHeader<BYTE-ORDER=[%v] FIRST-IFD-OFFSET=(0x%02x)>", eh.ByteOrder, eh.FirstIfdOffset) -} - -// 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 ParseExifHeader(data []byte) (eh ExifHeader, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - // Good reference: - // - // CIPA DC-008-2016; JEITA CP-3451D - // -> http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf - - if len(data) < 2 { - exifLogger.Warningf(nil, "Not enough data for EXIF header (1): (%d)", len(data)) - return eh, ErrNoExif - } - - byteOrderBytes := [2]byte{data[0], data[1]} - - byteOrder, found := ByteOrderLookup[byteOrderBytes] - if found == false { - // exifLogger.Warningf(nil, "EXIF byte-order not recognized: [%v]", byteOrderBytes) - return eh, ErrNoExif - } - - if len(data) < 4 { - exifLogger.Warningf(nil, "Not enough data for EXIF header (2): (%d)", len(data)) - return eh, ErrNoExif - } - - fixedBytes := [2]byte{data[2], data[3]} - expectedFixedBytes := ExifFixedBytesLookup[byteOrder] - if fixedBytes != expectedFixedBytes { - // exifLogger.Warningf(nil, "EXIF header fixed-bytes should be [%v] but are: [%v]", expectedFixedBytes, fixedBytes) - return eh, ErrNoExif - } - - if len(data) < 2 { - exifLogger.Warningf(nil, "Not enough data for EXIF header (3): (%d)", len(data)) - return eh, ErrNoExif - } - - firstIfdOffset := byteOrder.Uint32(data[4:8]) - - eh = ExifHeader{ - ByteOrder: byteOrder, - FirstIfdOffset: firstIfdOffset, - } - - return eh, nil -} - -// Visit recursively invokes a callback for every tag. -func Visit(rootIfdName string, ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte, visitor RawTagVisitor) (eh ExifHeader, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - eh, err = ParseExifHeader(exifData) - log.PanicIf(err) - - ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder) - - err = ie.Scan(rootIfdName, eh.FirstIfdOffset, visitor, true) - log.PanicIf(err) - - return eh, nil -} - -// Collect recursively builds a static structure of all IFDs and tags. -func Collect(ifdMapping *IfdMapping, tagIndex *TagIndex, exifData []byte) (eh ExifHeader, index IfdIndex, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - eh, err = ParseExifHeader(exifData) - log.PanicIf(err) - - ie := NewIfdEnumerate(ifdMapping, tagIndex, exifData, eh.ByteOrder) - - index, err = ie.Collect(eh.FirstIfdOffset, true) - log.PanicIf(err) - - return eh, index, nil -} - -// BuildExifHeader constructs the bytes that go in the very beginning. -func BuildExifHeader(byteOrder binary.ByteOrder, firstIfdOffset uint32) (headerBytes []byte, err error) { - defer func() { - if state := recover(); state != nil { - err = log.Wrap(state.(error)) - } - }() - - b := new(bytes.Buffer) - - // This is the point in the data that all offsets are relative to. - boBytes := ByteOrderLookupR[byteOrder] - _, err = b.WriteString(string(boBytes[:])) - log.PanicIf(err) - - fixedBytes := ExifFixedBytesLookup[byteOrder] - - _, err = b.Write(fixedBytes[:]) - log.PanicIf(err) - - err = binary.Write(b, byteOrder, firstIfdOffset) - log.PanicIf(err) - - return b.Bytes(), nil -} |