diff --git a/resources/rotate.TestTransform_AutoRotateReal.golden.jpg b/resources/rotate.TestTransform_AutoRotateReal.golden.jpg new file mode 100644 index 00000000..f5bb5340 Binary files /dev/null and b/resources/rotate.TestTransform_AutoRotateReal.golden.jpg differ diff --git a/resources/rotated.TestTransform_AutoRotateRealFlipped.golden.jpg b/resources/rotated.TestTransform_AutoRotateRealFlipped.golden.jpg new file mode 100644 index 00000000..aafd7bcf Binary files /dev/null and b/resources/rotated.TestTransform_AutoRotateRealFlipped.golden.jpg differ diff --git a/resources/rotated.jpg b/resources/rotated.jpg new file mode 100644 index 00000000..d0932af0 Binary files /dev/null and b/resources/rotated.jpg differ diff --git a/vips/image.go b/vips/image.go index c2224229..066ef353 100644 --- a/vips/image.go +++ b/vips/image.go @@ -309,14 +309,50 @@ func (r *ImageRef) Linear1(a, b float64) error { return nil } -// Autorot executes the 'autorot' operation -func (r *ImageRef) AutoRotate() error { - out, err := vipsAutoRotate(r.image) - if err != nil { - return err +func getZeroedAngle(angle Angle) Angle { + switch angle { + case Angle0: + return Angle0 + case Angle90: + return Angle270 + case Angle180: + return Angle180 + case Angle270: + return Angle90 } - r.setImage(out) - return nil + return Angle0 +} + +func GetRotationAngleFromExif(orientation int) (Angle, bool) { + + switch orientation { + case 0, 1, 2: + return Angle0, orientation == 2 + case 3, 4: + return Angle180, orientation == 4 + case 5, 8: + return Angle90, orientation == 5 + case 6, 7: + return Angle270, orientation == 7 + } + + return Angle0, false +} + +// Autorot do auto rotation +func (r *ImageRef) AutoRotate() error { + // this is a full implementation of auto rotate as vips doesn't support auto rotating of mirrors exifs + // https://jcupitt.github.io/libvips/API/current/libvips-conversion.html#vips-autorot + angle, flipped := GetRotationAngleFromExif(r.GetOrientation()) + if flipped { + err := r.Flip(DirectionHorizontal) + if err != nil { + return err + } + } + + zeroAngle := getZeroedAngle(angle) + return r.Rotate(zeroAngle) } // ExtractArea executes the 'extract_area' operation diff --git a/vips/transform.go b/vips/transform.go index 9c21a971..12a52981 100644 --- a/vips/transform.go +++ b/vips/transform.go @@ -378,6 +378,19 @@ func (t *Transform) Apply(image *ImageRef) (*ImageRef, error) { return newBlackboard(image, t.transformParams).execute() } +func (t *Transform) MatchOrientation(orientation int) *Transform { + angle, flipped := GetRotationAngleFromExif(orientation) + t.Rotate(angle) + + if flipped { + t.Flip(FlipHorizontal) + } + + t.SetOverwriteOrientation(orientation) + + return t +} + // Return the formatted buffer of the transformed image, and its metadata func (t *Transform) ApplyAndExport(image *ImageRef) ([]byte, *ImageMetadata, error) { i, err := t.Apply(image) diff --git a/vips/transform_test.go b/vips/transform_test.go index 4c0a26d9..6c64e270 100644 --- a/vips/transform_test.go +++ b/vips/transform_test.go @@ -125,6 +125,18 @@ func TestTransform_AutoRotate(t *testing.T) { }) } +func TestTransform_AutoRotateReal(t *testing.T) { + goldenTest(t, resources+"rotate.jpg", func(tx *Transform) { + tx.AutoRotate() + }) +} + +func TestTransform_AutoRotateRealFlipped(t *testing.T) { + goldenTest(t, resources+"rotated.jpg", func(tx *Transform) { + tx.AutoRotate() + }) +} + func TestTransform_Scale3x(t *testing.T) { goldenTest(t, resources+"tomatoes.png", func(tx *Transform) { tx.Scale(3.0)