diff options
| author | 2024-08-02 11:46:41 +0000 | |
|---|---|---|
| committer | 2024-08-02 12:46:41 +0100 | |
| commit | 94e87610c4ce9bbb1c614a61bab29c1422fed11b (patch) | |
| tree | 2e06b8ce64212140e796f6077ba841b6cc678501 /vendor/github.com/dsoprea/go-exif/v3/utility.go | |
| parent | [feature] Allow import of following and blocks via CSV (#3150) (diff) | |
| download | gotosocial-94e87610c4ce9bbb1c614a61bab29c1422fed11b.tar.xz | |
[chore] add back exif-terminator and use only for jpeg,png,webp (#3161)
* add back exif-terminator and use only for jpeg,png,webp
* fix arguments passed to terminateExif()
* pull in latest exif-terminator
* fix test
* update processed img
---------
Co-authored-by: tobi <tobi.smethurst@protonmail.com>
Diffstat (limited to 'vendor/github.com/dsoprea/go-exif/v3/utility.go')
| -rw-r--r-- | vendor/github.com/dsoprea/go-exif/v3/utility.go | 237 | 
1 files changed, 237 insertions, 0 deletions
| diff --git a/vendor/github.com/dsoprea/go-exif/v3/utility.go b/vendor/github.com/dsoprea/go-exif/v3/utility.go new file mode 100644 index 000000000..f0b5e6383 --- /dev/null +++ b/vendor/github.com/dsoprea/go-exif/v3/utility.go @@ -0,0 +1,237 @@ +package exif + +import ( +	"fmt" +	"io" +	"math" + +	"github.com/dsoprea/go-logging" +	"github.com/dsoprea/go-utility/v2/filesystem" + +	"github.com/dsoprea/go-exif/v3/common" +	"github.com/dsoprea/go-exif/v3/undefined" +) + +var ( +	utilityLogger = log.NewLogger("exif.utility") +) + +// ExifTag is one simple representation of a tag in a flat list of all of them. +type ExifTag struct { +	// IfdPath is the fully-qualified IFD path (even though it is not named as +	// such). +	IfdPath string `json:"ifd_path"` + +	// TagId is the tag-ID. +	TagId uint16 `json:"id"` + +	// TagName is the tag-name. This is never empty. +	TagName string `json:"name"` + +	// UnitCount is the recorded number of units constution of the value. +	UnitCount uint32 `json:"unit_count"` + +	// TagTypeId is the type-ID. +	TagTypeId exifcommon.TagTypePrimitive `json:"type_id"` + +	// TagTypeName is the type name. +	TagTypeName string `json:"type_name"` + +	// Value is the decoded value. +	Value interface{} `json:"value"` + +	// ValueBytes is the raw, encoded value. +	ValueBytes []byte `json:"value_bytes"` + +	// Formatted is the human representation of the first value (tag values are +	// always an array). +	FormattedFirst string `json:"formatted_first"` + +	// Formatted is the human representation of the complete value. +	Formatted string `json:"formatted"` + +	// ChildIfdPath is the name of the child IFD this tag represents (if it +	// represents any). Otherwise, this is empty. +	ChildIfdPath string `json:"child_ifd_path"` +} + +// String returns a string representation. +func (et ExifTag) String() string { +	return fmt.Sprintf( +		"ExifTag<"+ +			"IFD-PATH=[%s] "+ +			"TAG-ID=(0x%02x) "+ +			"TAG-NAME=[%s] "+ +			"TAG-TYPE=[%s] "+ +			"VALUE=[%v] "+ +			"VALUE-BYTES=(%d) "+ +			"CHILD-IFD-PATH=[%s]", +		et.IfdPath, et.TagId, et.TagName, et.TagTypeName, et.FormattedFirst, +		len(et.ValueBytes), et.ChildIfdPath) +} + +// GetFlatExifData returns a simple, flat representation of all tags. +func GetFlatExifData(exifData []byte, so *ScanOptions) (exifTags []ExifTag, med *MiscellaneousExifData, err error) { +	defer func() { +		if state := recover(); state != nil { +			err = log.Wrap(state.(error)) +		} +	}() + +	sb := rifs.NewSeekableBufferWithBytes(exifData) + +	exifTags, med, err = getFlatExifDataUniversalSearchWithReadSeeker(sb, so, false) +	log.PanicIf(err) + +	return exifTags, med, nil +} + +// RELEASE(dustin): GetFlatExifDataUniversalSearch is a kludge to allow univeral tag searching in a backwards-compatible manner. For the next release, undo this and simply add the flag to GetFlatExifData. + +// GetFlatExifDataUniversalSearch returns a simple, flat representation of all +// tags. +func GetFlatExifDataUniversalSearch(exifData []byte, so *ScanOptions, doUniversalSearch bool) (exifTags []ExifTag, med *MiscellaneousExifData, err error) { +	defer func() { +		if state := recover(); state != nil { +			err = log.Wrap(state.(error)) +		} +	}() + +	sb := rifs.NewSeekableBufferWithBytes(exifData) + +	exifTags, med, err = getFlatExifDataUniversalSearchWithReadSeeker(sb, so, doUniversalSearch) +	log.PanicIf(err) + +	return exifTags, med, nil +} + +// RELEASE(dustin): GetFlatExifDataUniversalSearchWithReadSeeker is a kludge to allow using a ReadSeeker in a backwards-compatible manner. For the next release, drop this and refactor GetFlatExifDataUniversalSearch to take a ReadSeeker. + +// GetFlatExifDataUniversalSearchWithReadSeeker returns a simple, flat +// representation of all tags given a ReadSeeker. +func GetFlatExifDataUniversalSearchWithReadSeeker(rs io.ReadSeeker, so *ScanOptions, doUniversalSearch bool) (exifTags []ExifTag, med *MiscellaneousExifData, err error) { +	defer func() { +		if state := recover(); state != nil { +			err = log.Wrap(state.(error)) +		} +	}() + +	exifTags, med, err = getFlatExifDataUniversalSearchWithReadSeeker(rs, so, doUniversalSearch) +	log.PanicIf(err) + +	return exifTags, med, nil +} + +// getFlatExifDataUniversalSearchWithReadSeeker returns a simple, flat +// representation of all tags given a ReadSeeker. +func getFlatExifDataUniversalSearchWithReadSeeker(rs io.ReadSeeker, so *ScanOptions, doUniversalSearch bool) (exifTags []ExifTag, med *MiscellaneousExifData, err error) { +	defer func() { +		if state := recover(); state != nil { +			err = log.Wrap(state.(error)) +		} +	}() + +	headerData := make([]byte, ExifSignatureLength) +	if _, err = io.ReadFull(rs, headerData); err != nil { +		if err == io.EOF { +			return nil, nil, err +		} + +		log.Panic(err) +	} + +	eh, err := ParseExifHeader(headerData) +	log.PanicIf(err) + +	im, err := exifcommon.NewIfdMappingWithStandard() +	log.PanicIf(err) + +	ti := NewTagIndex() + +	if doUniversalSearch == true { +		ti.SetUniversalSearch(true) +	} + +	ebs := NewExifReadSeeker(rs) +	ie := NewIfdEnumerate(im, ti, ebs, eh.ByteOrder) + +	exifTags = make([]ExifTag, 0) + +	visitor := func(ite *IfdTagEntry) (err error) { +		// This encodes down to base64. Since this an example tool and we do not +		// expect to ever decode the output, we are not worried about +		// specifically base64-encoding it in order to have a measure of +		// control. +		valueBytes, err := ite.GetRawBytes() +		if err != nil { +			if err == exifundefined.ErrUnparseableValue { +				return nil +			} + +			log.Panic(err) +		} + +		value, err := ite.Value() +		if err != nil { +			if err == exifcommon.ErrUnhandledUndefinedTypedTag { +				value = exifundefined.UnparseableUnknownTagValuePlaceholder +			} else if log.Is(err, exifcommon.ErrParseFail) == true { +				utilityLogger.Warningf(nil, +					"Could not parse value for tag [%s] (%04x) [%s].", +					ite.IfdPath(), ite.TagId(), ite.TagName()) + +				return nil +			} else { +				log.Panic(err) +			} +		} + +		et := ExifTag{ +			IfdPath:      ite.IfdPath(), +			TagId:        ite.TagId(), +			TagName:      ite.TagName(), +			UnitCount:    ite.UnitCount(), +			TagTypeId:    ite.TagType(), +			TagTypeName:  ite.TagType().String(), +			Value:        value, +			ValueBytes:   valueBytes, +			ChildIfdPath: ite.ChildIfdPath(), +		} + +		et.Formatted, err = ite.Format() +		log.PanicIf(err) + +		et.FormattedFirst, err = ite.FormatFirst() +		log.PanicIf(err) + +		exifTags = append(exifTags, et) + +		return nil +	} + +	med, err = ie.Scan(exifcommon.IfdStandardIfdIdentity, eh.FirstIfdOffset, visitor, nil) +	log.PanicIf(err) + +	return exifTags, med, nil +} + +// GpsDegreesEquals returns true if the two `GpsDegrees` are identical. +func GpsDegreesEquals(gi1, gi2 GpsDegrees) bool { +	if gi2.Orientation != gi1.Orientation { +		return false +	} + +	degreesRightBound := math.Nextafter(gi1.Degrees, gi1.Degrees+1) +	minutesRightBound := math.Nextafter(gi1.Minutes, gi1.Minutes+1) +	secondsRightBound := math.Nextafter(gi1.Seconds, gi1.Seconds+1) + +	if gi2.Degrees < gi1.Degrees || gi2.Degrees >= degreesRightBound { +		return false +	} else if gi2.Minutes < gi1.Minutes || gi2.Minutes >= minutesRightBound { +		return false +	} else if gi2.Seconds < gi1.Seconds || gi2.Seconds >= secondsRightBound { +		return false +	} + +	return true +} | 
