Skip to content

Instantly share code, notes, and snippets.

@tmichel
Created April 10, 2019 19:14
Show Gist options
  • Save tmichel/aa89883e0a40b49ad527b27d8a1044cb to your computer and use it in GitHub Desktop.
Save tmichel/aa89883e0a40b49ad527b27d8a1044cb to your computer and use it in GitHub Desktop.
Extract Exif info from an image
package main
import (
"bufio"
"bytes"
"encoding/binary"
"errors"
"io"
)
const (
// JPEG APP1 marker
jpegAPP1 = 0xE1
)
var (
errNoExifHeader = errors.New("exif: exif header not found")
exifHeader = append([]byte("Exif"), 0x00, 0x00)
)
func extractExif(r io.Reader) ([]byte, error) {
br := bufio.NewReader(r)
for {
// Find APP1 marker
if _, err := br.ReadBytes(0xFF); err != nil {
return nil, err
}
marker, err := br.ReadByte()
if err != nil {
return nil, err
}
if marker != jpegAPP1 {
continue
}
// Extract section length
dataLenBytes := make([]byte, 2)
io.ReadFull(br, dataLenBytes)
dataLen := int64(binary.BigEndian.Uint16(dataLenBytes)) - 2
if dataLen < int64(len(exifHeader)) {
return nil, errNoExifHeader
}
// Reconstruct APP1 section
var exif bytes.Buffer
exif.WriteByte(0xFF)
exif.WriteByte(jpegAPP1)
exif.Write(dataLenBytes)
_, err = io.CopyN(&exif, br, dataLen)
if err != nil {
return nil, err
}
// Check whether APP1 contains Exif or not
data := exif.Bytes()[4:] // 0xFF + marker + 2 bytes for length
headerBytes := data[:len(exifHeader)]
if !bytes.Equal(headerBytes, exifHeader) {
return nil, errNoExifHeader
}
return exif.Bytes(), nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment