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-iptc | |
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-iptc')
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/.MODULE_ROOT | 0 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/LICENSE | 21 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/README.md | 3 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/standard.go | 99 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/tag.go | 277 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/testing_common.go | 70 | ||||
-rw-r--r-- | vendor/github.com/dsoprea/go-iptc/utility.go | 25 |
7 files changed, 495 insertions, 0 deletions
diff --git a/vendor/github.com/dsoprea/go-iptc/.MODULE_ROOT b/vendor/github.com/dsoprea/go-iptc/.MODULE_ROOT new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/.MODULE_ROOT diff --git a/vendor/github.com/dsoprea/go-iptc/LICENSE b/vendor/github.com/dsoprea/go-iptc/LICENSE new file mode 100644 index 000000000..d92c04268 --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Dustin Oprea + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/dsoprea/go-iptc/README.md b/vendor/github.com/dsoprea/go-iptc/README.md new file mode 100644 index 000000000..d28e03d0a --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/README.md @@ -0,0 +1,3 @@ +# Overview + +This project provides functionality to parse a series of IPTC records/datasets. It also provides name resolution, but other constraints/validation is not yet implemented (though there is structure present that can accommodate this when desired/required). diff --git a/vendor/github.com/dsoprea/go-iptc/standard.go b/vendor/github.com/dsoprea/go-iptc/standard.go new file mode 100644 index 000000000..41a043f02 --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/standard.go @@ -0,0 +1,99 @@ +package iptc + +import ( + "errors" +) + +type StreamTagInfo struct { + Description string +} + +var ( + standardTags = map[StreamTagKey]StreamTagInfo{ + StreamTagKey{1, 120}: StreamTagInfo{"ARM Identifier"}, + + StreamTagKey{1, 122}: StreamTagInfo{"ARM Version"}, + StreamTagKey{2, 0}: StreamTagInfo{"Record Version"}, + StreamTagKey{2, 3}: StreamTagInfo{"Object Type Reference"}, + StreamTagKey{2, 4}: StreamTagInfo{"Object Attribute Reference"}, + StreamTagKey{2, 5}: StreamTagInfo{"Object Name"}, + StreamTagKey{2, 7}: StreamTagInfo{"Edit Status"}, + StreamTagKey{2, 8}: StreamTagInfo{"Editorial Update"}, + StreamTagKey{2, 10}: StreamTagInfo{"Urgency"}, + StreamTagKey{2, 12}: StreamTagInfo{"Subject Reference"}, + StreamTagKey{2, 15}: StreamTagInfo{"Category"}, + StreamTagKey{2, 20}: StreamTagInfo{"Supplemental Category"}, + StreamTagKey{2, 22}: StreamTagInfo{"Fixture Identifier"}, + StreamTagKey{2, 25}: StreamTagInfo{"Keywords"}, + StreamTagKey{2, 26}: StreamTagInfo{"Content Location Code"}, + StreamTagKey{2, 27}: StreamTagInfo{"Content Location Name"}, + StreamTagKey{2, 30}: StreamTagInfo{"Release Date"}, + StreamTagKey{2, 35}: StreamTagInfo{"Release Time"}, + StreamTagKey{2, 37}: StreamTagInfo{"Expiration Date"}, + StreamTagKey{2, 38}: StreamTagInfo{"Expiration Time"}, + StreamTagKey{2, 40}: StreamTagInfo{"Special Instructions"}, + StreamTagKey{2, 42}: StreamTagInfo{"Action Advised"}, + StreamTagKey{2, 45}: StreamTagInfo{"Reference Service"}, + StreamTagKey{2, 47}: StreamTagInfo{"Reference Date"}, + StreamTagKey{2, 50}: StreamTagInfo{"Reference Number"}, + StreamTagKey{2, 55}: StreamTagInfo{"Date Created"}, + StreamTagKey{2, 60}: StreamTagInfo{"Time Created"}, + StreamTagKey{2, 62}: StreamTagInfo{"Digital Creation Date"}, + StreamTagKey{2, 63}: StreamTagInfo{"Digital Creation Time"}, + StreamTagKey{2, 65}: StreamTagInfo{"Originating Program"}, + StreamTagKey{2, 70}: StreamTagInfo{"Program Version"}, + StreamTagKey{2, 75}: StreamTagInfo{"Object Cycle"}, + StreamTagKey{2, 80}: StreamTagInfo{"By-line"}, + StreamTagKey{2, 85}: StreamTagInfo{"By-line Title"}, + StreamTagKey{2, 90}: StreamTagInfo{"City"}, + StreamTagKey{2, 92}: StreamTagInfo{"Sublocation"}, + StreamTagKey{2, 95}: StreamTagInfo{"Province/State"}, + StreamTagKey{2, 100}: StreamTagInfo{"Country/Primary Location Code"}, + StreamTagKey{2, 101}: StreamTagInfo{"Country/Primary Location Name"}, + StreamTagKey{2, 103}: StreamTagInfo{"Original Transmission Reference"}, + StreamTagKey{2, 105}: StreamTagInfo{"Headline"}, + StreamTagKey{2, 110}: StreamTagInfo{"Credit"}, + StreamTagKey{2, 115}: StreamTagInfo{"Source"}, + StreamTagKey{2, 116}: StreamTagInfo{"Copyright Notice"}, + StreamTagKey{2, 118}: StreamTagInfo{"Contact"}, + StreamTagKey{2, 120}: StreamTagInfo{"Caption/Abstract"}, + StreamTagKey{2, 122}: StreamTagInfo{"Writer/Editor"}, + StreamTagKey{2, 125}: StreamTagInfo{"Rasterized Caption"}, + StreamTagKey{2, 130}: StreamTagInfo{"Image Type"}, + StreamTagKey{2, 131}: StreamTagInfo{"Image Orientation"}, + StreamTagKey{2, 135}: StreamTagInfo{"Language Identifier"}, + StreamTagKey{2, 150}: StreamTagInfo{"Audio Type"}, + StreamTagKey{2, 151}: StreamTagInfo{"Audio Sampling Rate"}, + StreamTagKey{2, 152}: StreamTagInfo{"Audio Sampling Resolution"}, + StreamTagKey{2, 153}: StreamTagInfo{"Audio Duration"}, + StreamTagKey{2, 154}: StreamTagInfo{"Audio Outcue"}, + StreamTagKey{2, 200}: StreamTagInfo{"ObjectData Preview File Format"}, + StreamTagKey{2, 201}: StreamTagInfo{"ObjectData Preview File Format Version"}, + StreamTagKey{2, 202}: StreamTagInfo{"ObjectData Preview Data"}, + StreamTagKey{7, 10}: StreamTagInfo{"Size Mode"}, + StreamTagKey{7, 20}: StreamTagInfo{"Max Subfile Size"}, + StreamTagKey{7, 90}: StreamTagInfo{"ObjectData Size Announced"}, + StreamTagKey{7, 95}: StreamTagInfo{"Maximum ObjectData Size"}, + StreamTagKey{8, 10}: StreamTagInfo{"Subfile"}, + StreamTagKey{9, 10}: StreamTagInfo{"Confirmed ObjectData Size"}, + } +) + +var ( + // ErrTagNotStandard indicates that the given tag is not known among the + // documented standard set. + ErrTagNotStandard = errors.New("not a standard tag") +) + +// GetTagInfo return the info for the given tag. Returns ErrTagNotStandard if +// not known. +func GetTagInfo(recordNumber, datasetNumber int) (sti StreamTagInfo, err error) { + stk := StreamTagKey{uint8(recordNumber), uint8(datasetNumber)} + + sti, found := standardTags[stk] + if found == false { + return sti, ErrTagNotStandard + } + + return sti, nil +} diff --git a/vendor/github.com/dsoprea/go-iptc/tag.go b/vendor/github.com/dsoprea/go-iptc/tag.go new file mode 100644 index 000000000..18afbb897 --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/tag.go @@ -0,0 +1,277 @@ +package iptc + +import ( + "errors" + "fmt" + "io" + "strings" + "unicode" + + "encoding/binary" + + "github.com/dsoprea/go-logging" +) + +var ( + // TODO(dustin): We're still not sure if this is the right endianness. No search to IPTC or IIM seems to state one or the other. + + // DefaultEncoding is the standard encoding for the IPTC format. + defaultEncoding = binary.BigEndian +) + +var ( + // ErrInvalidTagMarker indicates that the tag can not be parsed because the + // tag boundary marker is not the expected value. + ErrInvalidTagMarker = errors.New("invalid tag marker") +) + +// Tag describes one tag read from the stream. +type Tag struct { + recordNumber uint8 + datasetNumber uint8 + dataSize uint64 +} + +// String expresses state as a string. +func (tag *Tag) String() string { + return fmt.Sprintf( + "Tag<DATASET=(%d:%d) DATA-SIZE=(%d)>", + tag.recordNumber, tag.datasetNumber, tag.dataSize) +} + +// DecodeTag parses one tag from the stream. +func DecodeTag(r io.Reader) (tag Tag, err error) { + defer func() { + if state := recover(); state != nil { + err = log.Wrap(state.(error)) + } + }() + + tagMarker := uint8(0) + err = binary.Read(r, defaultEncoding, &tagMarker) + if err != nil { + if err == io.EOF { + return tag, err + } + + log.Panic(err) + } + + if tagMarker != 0x1c { + return tag, ErrInvalidTagMarker + } + + recordNumber := uint8(0) + err = binary.Read(r, defaultEncoding, &recordNumber) + log.PanicIf(err) + + datasetNumber := uint8(0) + err = binary.Read(r, defaultEncoding, &datasetNumber) + log.PanicIf(err) + + dataSize16Raw := uint16(0) + err = binary.Read(r, defaultEncoding, &dataSize16Raw) + log.PanicIf(err) + + var dataSize uint64 + + if dataSize16Raw < 32768 { + // We only had 16-bits (has the MSB set to (0)). + dataSize = uint64(dataSize16Raw) + } else { + // This field is just the length of the length (has the MSB set to (1)). + + // Clear the MSB. + lengthLength := dataSize16Raw & 32767 + + if lengthLength == 4 { + dataSize32Raw := uint32(0) + err := binary.Read(r, defaultEncoding, &dataSize32Raw) + log.PanicIf(err) + + dataSize = uint64(dataSize32Raw) + } else if lengthLength == 8 { + err := binary.Read(r, defaultEncoding, &dataSize) + log.PanicIf(err) + } else { + // No specific sizes or limits are specified in the specification + // so we need to impose our own limits in order to implement. + + log.Panicf("extended data-set tag size is not supported: (%d)", lengthLength) + } + } + + tag = Tag{ + recordNumber: recordNumber, + datasetNumber: datasetNumber, + dataSize: dataSize, + } + + return tag, nil +} + +// StreamTagKey is a convenience type that lets us key our index with a high- +// level type. +type StreamTagKey struct { + // RecordNumber is the major classification of the dataset. + RecordNumber uint8 + + // DatasetNumber is the minor classification of the dataset. + DatasetNumber uint8 +} + +// String returns a descriptive string. +func (stk StreamTagKey) String() string { + return fmt.Sprintf("%d:%d", stk.RecordNumber, stk.DatasetNumber) +} + +// Data is a convenience wrapper around a byte-slice. +type TagData []byte + +// IsPrintable returns true if all characters are printable. +func (tg TagData) IsPrintable() bool { + for _, b := range tg { + r := rune(b) + + // Newline characters aren't considered printable. + if r == 0x0d || r == 0x0a { + continue + } + + if unicode.IsGraphic(r) == false || unicode.IsPrint(r) == false { + return false + } + } + + return true +} + +// String returns a descriptive string. If the data doesn't include any non- +// printable characters, it will include the value itself. +func (tg TagData) String() string { + if tg.IsPrintable() == true { + return string(tg) + } else { + return fmt.Sprintf("BINARY<(%d) bytes>", len(tg)) + } +} + +// ParsedTags is the complete, unordered set of tags parsed from the stream. +type ParsedTags map[StreamTagKey][]TagData + +// ParseStream parses a serial sequence of tags and tag data out of the stream. +func ParseStream(r io.Reader) (tags map[StreamTagKey][]TagData, err error) { + defer func() { + if state := recover(); state != nil { + err = log.Wrap(state.(error)) + } + }() + + tags = make(ParsedTags) + + for { + tag, err := DecodeTag(r) + if err != nil { + if err == io.EOF { + break + } + + log.Panic(err) + } + + raw := make([]byte, tag.dataSize) + + _, err = io.ReadFull(r, raw) + log.PanicIf(err) + + data := TagData(raw) + + stk := StreamTagKey{ + RecordNumber: tag.recordNumber, + DatasetNumber: tag.datasetNumber, + } + + if existing, found := tags[stk]; found == true { + tags[stk] = append(existing, data) + } else { + tags[stk] = []TagData{data} + } + } + + return tags, nil +} + +// GetSimpleDictionaryFromParsedTags returns a dictionary of tag names to tag +// values, where all values are strings and any tag that had a non-printable +// value is omitted. We will also only return the first value, therefore +// dropping any follow-up values for repeatable tags. This will ignore non- +// standard tags. This will trim whitespace from the ends of strings. +// +// This is a convenience function for quickly displaying only the summary IPTC +// metadata that a user might actually be interested in at first glance. +func GetSimpleDictionaryFromParsedTags(pt ParsedTags) (distilled map[string]string) { + distilled = make(map[string]string) + + for stk, dataSlice := range pt { + sti, err := GetTagInfo(int(stk.RecordNumber), int(stk.DatasetNumber)) + if err != nil { + if err == ErrTagNotStandard { + continue + } else { + log.Panic(err) + } + } + + data := dataSlice[0] + + if data.IsPrintable() == false { + continue + } + + // TODO(dustin): Trim leading whitespace, too. + distilled[sti.Description] = strings.Trim(string(data), "\r\n") + } + + return distilled +} + +// GetDictionaryFromParsedTags returns all tags. It will keep non-printable +// values, though will not print a placeholder instead. This will keep non- +// standard tags (and print the fully-qualified dataset ID rather than the +// name). It will keep repeated values (with the counter value appended to the +// end). +func GetDictionaryFromParsedTags(pt ParsedTags) (distilled map[string]string) { + distilled = make(map[string]string) + for stk, dataSlice := range pt { + var keyPhrase string + + sti, err := GetTagInfo(int(stk.RecordNumber), int(stk.DatasetNumber)) + if err != nil { + if err == ErrTagNotStandard { + keyPhrase = fmt.Sprintf("%s (not a standard tag)", stk.String()) + } else { + log.Panic(err) + } + } else { + keyPhrase = sti.Description + } + + for i, data := range dataSlice { + currentKeyPhrase := keyPhrase + if len(dataSlice) > 1 { + currentKeyPhrase = fmt.Sprintf("%s (%d)", currentKeyPhrase, i+1) + } + + var presentable string + if data.IsPrintable() == false { + presentable = fmt.Sprintf("[BINARY] %s", DumpBytesToString(data)) + } else { + presentable = string(data) + } + + distilled[currentKeyPhrase] = presentable + } + } + + return distilled +} diff --git a/vendor/github.com/dsoprea/go-iptc/testing_common.go b/vendor/github.com/dsoprea/go-iptc/testing_common.go new file mode 100644 index 000000000..bb5903fa1 --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/testing_common.go @@ -0,0 +1,70 @@ +package iptc + +import ( + "os" + "path" + + "github.com/dsoprea/go-logging" +) + +var ( + testDataRelFilepath = "iptc.data" +) + +var ( + moduleRootPath = "" + assetsPath = "" +) + +func GetModuleRootPath() string { + if moduleRootPath == "" { + moduleRootPath = os.Getenv("IPTC_MODULE_ROOT_PATH") + if moduleRootPath != "" { + return moduleRootPath + } + + currentWd, err := os.Getwd() + log.PanicIf(err) + + currentPath := currentWd + visited := make([]string, 0) + + for { + tryStampFilepath := path.Join(currentPath, ".MODULE_ROOT") + + _, err := os.Stat(tryStampFilepath) + if err != nil && os.IsNotExist(err) != true { + log.Panic(err) + } else if err == nil { + break + } + + visited = append(visited, tryStampFilepath) + + currentPath = path.Dir(currentPath) + if currentPath == "/" { + log.Panicf("could not find module-root: %v", visited) + } + } + + moduleRootPath = currentPath + } + + return moduleRootPath +} + +func GetTestAssetsPath() string { + if assetsPath == "" { + moduleRootPath := GetModuleRootPath() + assetsPath = path.Join(moduleRootPath, "assets") + } + + return assetsPath +} + +func GetTestDataFilepath() string { + assetsPath := GetTestAssetsPath() + filepath := path.Join(assetsPath, testDataRelFilepath) + + return filepath +} diff --git a/vendor/github.com/dsoprea/go-iptc/utility.go b/vendor/github.com/dsoprea/go-iptc/utility.go new file mode 100644 index 000000000..5a4a10ad3 --- /dev/null +++ b/vendor/github.com/dsoprea/go-iptc/utility.go @@ -0,0 +1,25 @@ +package iptc + +import ( + "bytes" + "fmt" + + "github.com/dsoprea/go-logging" +) + +// DumpBytesToString returns a stringified list of hex-encoded bytes. +func DumpBytesToString(data []byte) string { + b := new(bytes.Buffer) + + for i, x := range data { + _, err := b.WriteString(fmt.Sprintf("%02x", x)) + log.PanicIf(err) + + if i < len(data)-1 { + _, err := b.WriteRune(' ') + log.PanicIf(err) + } + } + + return b.String() +} |