summaryrefslogtreecommitdiff
path: root/vendor/github.com/superseriousbusiness/exifremove/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/superseriousbusiness/exifremove/pkg')
-rw-r--r--vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/exifremove.go140
-rw-r--r--vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/png_crc_fix.go104
2 files changed, 244 insertions, 0 deletions
diff --git a/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/exifremove.go b/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/exifremove.go
new file mode 100644
index 000000000..d9e7e2ad1
--- /dev/null
+++ b/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/exifremove.go
@@ -0,0 +1,140 @@
+package exifremove
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "image/jpeg"
+ "image/png"
+
+ "github.com/dsoprea/go-exif"
+ jpegstructure "github.com/dsoprea/go-jpeg-image-structure"
+ pngstructure "github.com/dsoprea/go-png-image-structure"
+ "github.com/h2non/filetype"
+)
+
+func Remove(data []byte) ([]byte, error) {
+
+ const (
+ JpegMediaType = "jpeg"
+ PngMediaType = "png"
+ OtherMediaType = "other"
+ StartBytes = 0
+ EndBytes = 0
+ )
+
+ type MediaContext struct {
+ MediaType string
+ RootIfd *exif.Ifd
+ RawExif []byte
+ Media interface{}
+ }
+
+ filtered := []byte{}
+
+ head := make([]byte, 261)
+ _, err := bytes.NewReader(data).Read(head)
+ if err != nil {
+ return nil, fmt.Errorf("could not read first 261 bytes of data: %s", err)
+ }
+ imagetype, err := filetype.Match(head)
+ if err != nil {
+ return nil, fmt.Errorf("error matching first 261 bytes of image to valid type: %s", err)
+ }
+
+ switch imagetype.MIME.Subtype {
+ case "jpeg":
+ jmp := jpegstructure.NewJpegMediaParser()
+ sl, err := jmp.ParseBytes(data)
+ if err != nil {
+ return nil, err
+ }
+
+ _, rawExif, err := sl.Exif()
+ if err != nil {
+ return data, nil
+ }
+
+ startExifBytes := StartBytes
+ endExifBytes := EndBytes
+
+ if bytes.Contains(data, rawExif) {
+ for i := 0; i < len(data)-len(rawExif); i++ {
+ if bytes.Compare(data[i:i+len(rawExif)], rawExif) == 0 {
+ startExifBytes = i
+ endExifBytes = i + len(rawExif)
+ break
+ }
+ }
+ fill := make([]byte, len(data[startExifBytes:endExifBytes]))
+ copy(data[startExifBytes:endExifBytes], fill)
+ }
+
+ filtered = data
+
+ _, err = jpeg.Decode(bytes.NewReader(filtered))
+ if err != nil {
+ return nil, errors.New("EXIF removal corrupted " + err.Error())
+ }
+ case "png":
+ pmp := pngstructure.NewPngMediaParser()
+ cs, err := pmp.ParseBytes(data)
+ if err != nil {
+ return nil, err
+ }
+
+ _, rawExif, err := cs.Exif()
+ if err != nil {
+ return data, nil
+ }
+
+ startExifBytes := StartBytes
+ endExifBytes := EndBytes
+
+ if bytes.Contains(data, rawExif) {
+ for i := 0; i < len(data)-len(rawExif); i++ {
+ if bytes.Compare(data[i:i+len(rawExif)], rawExif) == 0 {
+ startExifBytes = i
+ endExifBytes = i + len(rawExif)
+ break
+ }
+ }
+ fill := make([]byte, len(data[startExifBytes:endExifBytes]))
+ copy(data[startExifBytes:endExifBytes], fill)
+ }
+
+ filtered = data
+
+ chunks := readPNGChunks(bytes.NewReader(filtered))
+
+ for _, chunk := range chunks {
+ if !chunk.CRCIsValid() {
+ offset := int(chunk.Offset) + 8 + int(chunk.Length)
+ crc := chunk.CalculateCRC()
+
+ buf := new(bytes.Buffer)
+ binary.Write(buf, binary.BigEndian, crc)
+ crcBytes := buf.Bytes()
+
+ copy(filtered[offset:], crcBytes)
+ }
+ }
+
+ chunks = readPNGChunks(bytes.NewReader(filtered))
+ for _, chunk := range chunks {
+ if !chunk.CRCIsValid() {
+ return nil, errors.New("EXIF removal failed CRC")
+ }
+ }
+
+ _, err = png.Decode(bytes.NewReader(filtered))
+ if err != nil {
+ return nil, errors.New("EXIF removal corrupted " + err.Error())
+ }
+ default:
+ return nil, errors.New("filetype not recognised")
+ }
+
+ return filtered, nil
+}
diff --git a/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/png_crc_fix.go b/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/png_crc_fix.go
new file mode 100644
index 000000000..390e5e515
--- /dev/null
+++ b/vendor/github.com/superseriousbusiness/exifremove/pkg/exifremove/png_crc_fix.go
@@ -0,0 +1,104 @@
+package exifremove
+
+// borrowed heavily from https://github.com/landaire/png-crc-fix/blob/master/main.go
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "hash/crc32"
+ "io"
+ "os"
+)
+
+const chunkStartOffset = 8
+const endChunk = "IEND"
+
+type pngChunk struct {
+ Offset int64
+ Length uint32
+ Type [4]byte
+ Data []byte
+ CRC uint32
+}
+
+func (p pngChunk) String() string {
+ return fmt.Sprintf("%s@%x - %X - Valid CRC? %v", p.Type, p.Offset, p.CRC, p.CRCIsValid())
+}
+
+func (p pngChunk) Bytes() []byte {
+ var buffer bytes.Buffer
+
+ binary.Write(&buffer, binary.BigEndian, p.Type)
+ buffer.Write(p.Data)
+
+ return buffer.Bytes()
+}
+
+func (p pngChunk) CRCIsValid() bool {
+ return p.CRC == p.CalculateCRC()
+}
+
+func (p pngChunk) CalculateCRC() uint32 {
+ crcTable := crc32.MakeTable(crc32.IEEE)
+
+ return crc32.Checksum(p.Bytes(), crcTable)
+}
+
+func (p pngChunk) CRCOffset() int64 {
+ return p.Offset + int64(8+p.Length)
+}
+
+func readPNGChunks(reader io.ReadSeeker) []pngChunk {
+ chunks := []pngChunk{}
+
+ reader.Seek(chunkStartOffset, os.SEEK_SET)
+
+ readChunk := func() (*pngChunk, error) {
+ var chunk pngChunk
+ chunk.Offset, _ = reader.Seek(0, os.SEEK_CUR)
+
+ binary.Read(reader, binary.BigEndian, &chunk.Length)
+
+ chunk.Data = make([]byte, chunk.Length)
+
+ err := binary.Read(reader, binary.BigEndian, &chunk.Type)
+ if err != nil {
+ goto read_error
+ }
+
+ if read, err := reader.Read(chunk.Data); read == 0 || err != nil {
+ goto read_error
+ }
+
+ err = binary.Read(reader, binary.BigEndian, &chunk.CRC)
+ if err != nil {
+ goto read_error
+ }
+
+ return &chunk, nil
+
+ read_error:
+ return nil, fmt.Errorf("Read error")
+ }
+
+ chunk, err := readChunk()
+ if err != nil {
+ return chunks
+ }
+
+ chunks = append(chunks, *chunk)
+
+ // Read the first chunk
+ for string(chunks[len(chunks)-1].Type[:]) != endChunk {
+
+ chunk, err := readChunk()
+ if err != nil {
+ break
+ }
+
+ chunks = append(chunks, *chunk)
+ }
+
+ return chunks
+}