Repository: gohugoio/hugo (language: go)

Issue:
New EXIF library returns an image orientation that doesn't pass (eq $o 6)

I have the following fragment in a render-image.html file to set aspect ratios on images.  This works in hugo prior to the new EXIF library.

```
{{- /* get file that matches the filename as specified as src="" in shortcode */ -}}
{{- $src := .Page.Resources.GetMatch (printf "%s" (.Destination)) -}}
{{- $imgPath := .Destination -}}
{{- if $src -}}

{{- $imgWidth := $src.Width -}}
{{- $imgHeight := $src.Height -}}
{{- with $src.Exif -}}
  {{- $o :=  .Tags.Orientation -}}
  {{- warnf (printf "%s orientation %d width %d height %d" $imgPath $o $imgWidth $imgHeight) }}
  {{- if (or (eq $o 6) (eq $o 8)) -}}
    {{- $imgWidth = $src.Height -}}
    {{- $imgHeight = $src.Width -}}
    {{- warnf "flipping width and height" -}}
  {{- end -}}
{{- end -}}
```

The warnings print out the orientation properly in 0.131, but the eq $o 6 test fails and so the aspect ratio on my image is wrong.  Here are some example warnings where it doesn't flip an image.

```
WARN  birguentrance.jpg orientation 6 width 6960 height 4640
WARN  victoriagate.jpg orientation 1 width 5161 height 4167
```

In hugo 0.131 I have to use the following to get it to work.  It looks like the type returned by .Orientation isn't the same type as before and now fails the eq test.  Converting to a string with printf and comparing strings works in 0.131 and newer.

```
{{- /* get file that matches the filename as specified as src="" in shortcode */ -}}
{{- $src := .Page.Resources.GetMatch (printf "%s" (.Destination)) -}}
{{- $imgPath := .Destination -}}
{{- if $src -}}

{{- $imgWidth := $src.Width -}}
{{- $imgHeight := $src.Height -}}
{{- with $src.Exif -}}
  {{- $o := (printf "%d" .Tags.Orientation) -}}
  {{- warnf (printf "%s orientation %d width %d height %d" $imgPath $o $imgWidth $imgHeight) }}
  {{- if (or (eq $o "6") (eq $o "8")) -}}
    {{- $imgWidth = $src.Height -}}
    {{- $imgHeight = $src.Width -}}
    {{- warnf "flipping width and height" -}}
  {{- end -}}
{{- end -}}
```

These are the example warnings from this changed code that properly flips the aspect ratio:

```
WARN  birguentrance.jpg orientation %!!(MISSING)d(string=6) width 6960 height 4640
WARN  flipping width and height
WARN  victoriagate.jpg orientation %!!(MISSING)d(string=1) width 5161 height 4167
```

What I want is for the same template to work in both systems.  Either document the changes I need to make to my templates to support both types (preferably in the release that breaks it).  Or fix the new library to return types that are compatible with my existing template.




Discussion / hints:
I think you can work around this by:

```
 {{- $o :=  .Tags.Orientation | int -}}
```

A note mostly to myself here:

* In my new library, I have kept the int data types as dictated by their length, e.g. 2 bytes integer => `int16`.
* I have not checked, but I'm guessing the `eq` function considers `eq int16(6) 6` to be falsy, which smells like a bug in itself.

It's tempting to just change the EXIF types to `int`, but that can lead to overflow issues, which is also not great.
```
 {{- $o :=  .Tags.Orientation | int -}}
```

Works in 0.131, and I haven't tested it in versions prior to 0.130 yet, but I suspect that works there as well.  

My hosting provider that runs hugo doesn't let me control when hugo is upgraded, so I need to support the older hugo version till they upgrade with my templates, but like to test with the newest version so I can see what changes I'll need in the future.

I agree that the proper fix is to fix the comparisons so that eq int16(6) 6 is true for the appropriate operators and types.

Fix patch:
diff --git a/tpl/compare/compare.go b/tpl/compare/compare.go
index 907be9b15bf..d6a764c6add 100644
--- a/tpl/compare/compare.go
+++ b/tpl/compare/compare.go
@@ -117,7 +117,12 @@ func (n *Namespace) Eq(first any, others ...any) bool {
 		case reflect.Float32, reflect.Float64:
 			return vv.Float()
 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-			return vv.Uint()
+			i := vv.Uint()
+			// If it can fit in an int, convert it.
+			if i <= math.MaxInt64 {
+				return int64(i)
+			}
+			return i
 		case reflect.String:
 			return vv.String()
 		default:
@@ -237,6 +242,16 @@ func (ns *Namespace) compareGet(a any, b any) (float64, float64) {
 	return ns.compareGetWithCollator(nil, a, b)
 }
 
+func (ns *Namespace) compareTwoUints(a uint64, b uint64) (float64, float64) {
+	if a < b {
+		return 1, 0
+	} else if a == b {
+		return 0, 0
+	} else {
+		return 0, 1
+	}
+}
+
 func (ns *Namespace) compareGetWithCollator(collator *langs.Collator, a any, b any) (float64, float64) {
 	if ac, ok := a.(compare.Comparer); ok {
 		c := ac.Compare(b)
@@ -263,12 +278,22 @@ func (ns *Namespace) compareGetWithCollator(collator *langs.Collator, a any, b a
 	var left, right float64
 	var leftStr, rightStr *string
 	av := reflect.ValueOf(a)
+	bv := reflect.ValueOf(b)
 
 	switch av.Kind() {
 	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
 		left = float64(av.Len())
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if hreflect.IsUint(bv.Kind()) {
+			return ns.compareTwoUints(uint64(av.Int()), bv.Uint())
+		}
 		left = float64(av.Int())
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+		left = float64(av.Uint())
+	case reflect.Uint64:
+		if hreflect.IsUint(bv.Kind()) {
+			return ns.compareTwoUints(av.Uint(), bv.Uint())
+		}
 	case reflect.Float32, reflect.Float64:
 		left = av.Float()
 	case reflect.String:
@@ -290,13 +315,20 @@ func (ns *Namespace) compareGetWithCollator(collator *langs.Collator, a any, b a
 		}
 	}
 
-	bv := reflect.ValueOf(b)
-
 	switch bv.Kind() {
 	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
 		right = float64(bv.Len())
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		if hreflect.IsUint(av.Kind()) {
+			return ns.compareTwoUints(av.Uint(), uint64(bv.Int()))
+		}
 		right = float64(bv.Int())
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
+		right = float64(bv.Uint())
+	case reflect.Uint64:
+		if hreflect.IsUint(av.Kind()) {
+			return ns.compareTwoUints(av.Uint(), bv.Uint())
+		}
 	case reflect.Float32, reflect.Float64:
 		right = bv.Float()
 	case reflect.String:


Test patch:
diff --git a/resources/images/images_integration_test.go b/resources/images/images_integration_test.go
index 156de62592f..caba42e0338 100644
--- a/resources/images/images_integration_test.go
+++ b/resources/images/images_integration_test.go
@@ -34,3 +34,19 @@ W/H rotated: {{ $rotated.Width }}/{{ $rotated.Height }}
 	b := hugolib.Test(t, files)
 	b.AssertFileContent("public/index.html", "W/H original: 80/40\n\nW/H rotated: 40/80")
 }
+
+// Issue 12733.
+func TestOrientationEq(t *testing.T) {
+	files := `
+-- hugo.toml --
+-- assets/rotate270.jpg --
+sourcefilename: ../testdata/exif/orientation6.jpg
+-- layouts/index.html --
+{{ $img := resources.Get "rotate270.jpg" }}
+{{ $orientation := $img.Exif.Tags.Orientation }}
+Orientation: {{ $orientation }}|eq 6: {{ eq $orientation 6 }}|Type: {{ printf "%T" $orientation }}|
+`
+
+	b := hugolib.Test(t, files)
+	b.AssertFileContent("public/index.html", "Orientation: 6|eq 6: true|")
+}
diff --git a/tpl/compare/compare_test.go b/tpl/compare/compare_test.go
index 4c50f5f0f87..6c3f430281d 100644
--- a/tpl/compare/compare_test.go
+++ b/tpl/compare/compare_test.go
@@ -14,6 +14,7 @@
 package compare
 
 import (
+	"math"
 	"path"
 	"reflect"
 	"runtime"
@@ -199,6 +200,16 @@ func doTestCompare(t *testing.T, tp tstCompareType, funcUnderTest func(a, b any)
 		{5, 5, 0},
 		{int(5), int64(5), 0},
 		{int32(5), int(5), 0},
+		{int16(4), 4, 0},
+		{uint8(4), 4, 0},
+		{uint16(4), 4, 0},
+		{uint16(4), 4, 0},
+		{uint32(4), uint16(4), 0},
+		{uint32(4), uint16(3), 1},
+		{uint64(4), 4, 0},
+		{4, uint64(4), 0},
+		{uint64(math.MaxUint32), uint32(math.MaxUint32), 0},
+		{uint64(math.MaxUint16), int(math.MaxUint16), 0},
 		{int16(4), int(5), -1},
 		{uint(15), uint64(15), 0},
 		{-2, 1, -1},