Skip to content

Commit 24db671

Browse files
author
thisisaaronland
committed
add X- fields to supported tags wasm
1 parent 0e36a87 commit 24db671

File tree

9 files changed

+180
-13
lines changed

9 files changed

+180
-13
lines changed

cmd/tags-supported-wasm/main.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,18 @@ func main() {
2020
log.Printf("Failed to derive supported tags, %v", err)
2121
return nil
2222
}
23-
23+
2424
sort.Strings(tags_supported)
2525

26+
x_tags := []string{
27+
"X-Latitude",
28+
"X-Longitude",
29+
}
30+
31+
for _, t := range x_tags {
32+
tags_supported = append(tags_supported, t)
33+
}
34+
2635
enc_supported, err := json.Marshal(tags_supported)
2736

2837
if err != nil {

cmd/update-exif-wasm/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func UpdateFunc() js.Func {
100100
var buf bytes.Buffer
101101
img_wr := bufio.NewWriter(&buf)
102102

103-
err = update.UpdateExif(img_fh, img_wr, exif_data)
103+
err = update.PrepareAndUpdateExif(img_fh, img_wr, exif_data)
104104

105105
if err != nil {
106106
reject.Invoke(fmt.Printf("Failed update EXIF properties, %v", err))

cmd/update-exif/main.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@ import (
88
"github.com/sfomuseum/go-flags/multi"
99
"log"
1010
"os"
11+
"strings"
1112
)
1213

1314
func main() {
1415

1516
var properties multi.KeyValueString
1617
flag.Var(&properties, "property", "One or more {TAG}={VALUE} EXIF properties. {TAG} must be a recognized EXIF tag.")
1718

19+
lat := flag.Float64("latitude", 0.0, "")
20+
lon := flag.Float64("longitude", 0.0, "")
21+
1822
flag.Usage = func() {
1923
fmt.Fprintf(os.Stderr, "Command-line tool for updating the EXIF properties in one or more JPEG images. Images are not updated in place but written to STDOUT.\n\n")
2024
fmt.Fprintf(os.Stderr, "Usage:\n\t%s [options] image(N) image(N) image(N)\n\n", os.Args[0])
@@ -32,19 +36,31 @@ func main() {
3236
k := p.Key()
3337
v := p.Value().(string)
3438

35-
ok, err := tags.IsSupported(k)
39+
if !strings.HasPrefix(k, "X-") {
3640

37-
if err != nil {
38-
log.Fatalf("Failed to determine whether tag '%s' is supported, %v", k, err)
39-
}
41+
ok, err := tags.IsSupported(k)
4042

41-
if !ok {
42-
log.Fatalf("Tag '%s' is not supported by this tool, at this time", k)
43+
if err != nil {
44+
log.Fatalf("Failed to determine whether tag '%s' is supported, %v", k, err)
45+
}
46+
47+
if !ok {
48+
log.Fatalf("Tag '%s' is not supported by this tool, at this time", k)
49+
}
4350
}
4451

4552
exif_props[k] = v
4653
}
4754

55+
if *lat != 0.0 && *lon != 0.0 {
56+
57+
err := update.AppendGPSPropertiesWithLatitudeAndLongitude(exif_props, *lat, *lon)
58+
59+
if err != nil {
60+
log.Fatalf("Failed to append latitude and longitude properties, %v", err)
61+
}
62+
}
63+
4864
for _, path := range paths {
4965

5066
fh, err := os.Open(path)
@@ -55,7 +71,7 @@ func main() {
5571

5672
defer fh.Close()
5773

58-
err = update.UpdateExif(fh, os.Stdout, exif_props)
74+
err = update.PrepareAndUpdateExif(fh, os.Stdout, exif_props)
5975

6076
if err != nil {
6177
log.Fatalf("Failed to update '%s', %v", path, err)

gps.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package update
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func AppendGPSPropertiesWithLatitudeAndLongitude(exif_props map[string]interface{}, lat float64, lon float64) error {
8+
9+
gps_lat, err := PrepareDecimalGPSLatitudeTag(lat)
10+
11+
if err != nil {
12+
return fmt.Errorf("Failed to prepare GPSLatitudeTag, %v", err)
13+
}
14+
15+
gps_lat_ref, err := PrepareDecimalGPSLatitudeRefTag(lat)
16+
17+
if err != nil {
18+
return fmt.Errorf("Failed to prepare GPSLatitudeRefTag, %v", err)
19+
}
20+
21+
gps_lon, err := PrepareDecimalGPSLongitudeTag(lon)
22+
23+
if err != nil {
24+
return fmt.Errorf("Failed to prepare GPSLatitudeTag, %v", err)
25+
}
26+
27+
gps_lon_ref, err := PrepareDecimalGPSLongitudeRefTag(lon)
28+
29+
if err != nil {
30+
return fmt.Errorf("Failed to prepare GPSLatitudeRefTag, %v", err)
31+
}
32+
33+
exif_props["GPSLatitude"] = gps_lat
34+
exif_props["GPSLatitudeRef"] = gps_lat_ref
35+
exif_props["GPSLongitude"] = gps_lon
36+
exif_props["GPSLongitudeRef"] = gps_lon_ref
37+
38+
return nil
39+
}

gps_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package update
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestAppendGPSPropertiesWithLatitudeAndLongitude(t *testing.T) {
8+
9+
lat := 37.61799
10+
lon := -122.384864
11+
12+
props := make(map[string]interface{})
13+
14+
err := AppendGPSPropertiesWithLatitudeAndLongitude(props, lat, lon)
15+
16+
if err != nil {
17+
t.Fatalf("Failed to append GPS properties, %v", err)
18+
}
19+
}

prepare.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import (
44
"fmt"
55
"github.com/dsoprea/go-exif/v3"
66
"github.com/dsoprea/go-exif/v3/common"
7-
"log"
7+
_ "log"
88
"math"
99
)
1010

@@ -100,8 +100,6 @@ func PrepareTag(k string, v string) (interface{}, error) {
100100
return nil, err
101101
}
102102

103-
log.Println("WTF", k, v, v2)
104-
105103
// https://github.com/dsoprea/go-exif/blob/db167117f4830a268022c953f0f521fcc83d031e/v3/common/value_encoder.go#L225
106104

107105
switch v2.(type) {

update.go

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/sfomuseum/go-exif-update/tags"
1010
"io"
1111
_ "log"
12+
"strconv"
1213
)
1314

1415
var ti *exif.TagIndex
@@ -31,9 +32,94 @@ func init() {
3132

3233
}
3334

34-
// UpdateExif updates the EXIF data encoded in r and writes that data to wr.
35+
// PrepareAndUpdateExif attempts to prepare and translate EXIF properties in defined in exif_props
36+
// in to their appropriate dsoprea/go-exif types and format and then updates the EXIF data encoded in
37+
// r and writes that data to wr. This method also supports a handful of custom properties that are
38+
// prefixed with X- and used to populate known EXIF properties. These are:
39+
// * X-Latitude and X-Longitude, which convert and assign decimal latitude and longitude coordinates
40+
// in to their GPSLatitude/Longitude and GPSLatitude/LongitudeRef EXIF properties.
41+
func PrepareAndUpdateExif(r io.Reader, wr io.Writer, exif_props map[string]interface{}) error {
42+
43+
prepared := make(map[string]interface{})
44+
45+
var lat float64
46+
var lon float64
47+
48+
x_lat, has_lat := exif_props["X-Latitude"]
49+
x_lon, has_lon := exif_props["X-Longitude"]
50+
51+
if has_lat && !has_lon {
52+
return fmt.Errorf("Missing X-Longitude property (X-Latitude is set)")
53+
}
54+
55+
if has_lon && !has_lat {
56+
return fmt.Errorf("Missing X-Latitude property (X-Longitude is set)")
57+
}
58+
59+
if has_lat && has_lon {
60+
61+
switch x_lat.(type) {
62+
case float64:
63+
lat = x_lat.(float64)
64+
case string:
65+
66+
l, err := strconv.ParseFloat(x_lat.(string), 64)
67+
68+
if err != nil {
69+
return err
70+
}
71+
72+
lat = l
73+
default:
74+
return fmt.Errorf("Invalid type for latitude, %T", lat)
75+
}
76+
77+
switch x_lon.(type) {
78+
case float64:
79+
lon = x_lon.(float64)
80+
case string:
81+
82+
l, err := strconv.ParseFloat(x_lon.(string), 64)
83+
84+
if err != nil {
85+
return err
86+
}
87+
88+
lon = l
89+
90+
default:
91+
return fmt.Errorf("Invalid type for longitude")
92+
}
93+
94+
err := AppendGPSPropertiesWithLatitudeAndLongitude(prepared, lat, lon)
95+
96+
if err != nil {
97+
return err
98+
}
99+
100+
delete(exif_props, "X-Latitude")
101+
delete(exif_props, "X-Longitude")
102+
}
103+
104+
for k, v := range exif_props {
105+
106+
str_v := fmt.Sprintf("%v", v)
107+
v2, err := PrepareTag(k, str_v)
108+
109+
if err != nil {
110+
return fmt.Errorf("Failed to prepare tag '%s', %v", k, err)
111+
}
112+
113+
prepared[k] = v2
114+
}
115+
116+
return UpdateExif(r, wr, prepared)
117+
}
118+
35119
// This is really nothing more than a thin wrapper around the example code in
36120
// dsoprea's go-jpeg-image-structure package.
121+
122+
// UpdateExif updates the EXIF data encoded in r and writes that data to wr.
37123
func UpdateExif(r io.Reader, wr io.Writer, exif_props map[string]interface{}) error {
38124

39125
img_data, err := io.ReadAll(r)

www/wasm/supported_tags.wasm

646 Bytes
Binary file not shown.

www/wasm/update_exif.wasm

27.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)