Code Monkey home page Code Monkey logo

Comments (6)

disintegration avatar disintegration commented on July 2, 2024 2

Thank you for the example.

The current behavior of Rotate is to adjust the size of the destination image to fit the entire rotated source image. So changing the anchor point won't change the result.

If i understand you correctly, what you need is: the size of the destination image to stay the same as the original and to crop the parts of the image that are out of these bounds after the rotation. Is that correct?

For example, given the original image:
test

Resulting images after rotation 30 and 60 degrees clockwise with the anchor point (20,20):

rotated-030 rotated-060

Here's the example code using golang.org/x/image/draw and the affine transformation matrix:

package main

import (
	"fmt"
	"image"
	"log"
	"math"

	"github.com/disintegration/imaging"
	"golang.org/x/image/draw"
	"golang.org/x/image/math/f64"
)

func main() {
	src, err := imaging.Open("test.png")
	if err != nil {
		log.Fatal(err)
	}
	for a := float64(0); a < 360; a += 10 {
		dst := rotateAround(src, a, 20, 20)
		err := imaging.Save(dst, fmt.Sprintf("rotated-%03d.png", int(a)))
		if err != nil {
			log.Fatal(err)
		}
	}
}

func rotateAround(src image.Image, angle float64, x, y int) image.Image {
	a := math.Pi * angle / 180
	xf, yf := float64(x), float64(y)
	sin := math.Sin(a)
	cos := math.Cos(a)
	matrix := f64.Aff3{
		cos, -sin, xf - xf*cos + yf*sin,
		sin, cos, yf - xf*sin - yf*cos,
	}
	dst := image.NewRGBA(src.Bounds())
	draw.BiLinear.Transform(dst, matrix, src, src.Bounds(), draw.Src, nil)
	return dst
}

from imaging.

disintegration avatar disintegration commented on July 2, 2024

Hi,
What do you mean by "offset"? Could you provide an example?

from imaging.

christopher-kleine avatar christopher-kleine commented on July 2, 2024

Hi,

yesterday I was too tired to provide an example. And when I thought about it, it seems not everyone uses the same name for what I meant. Some call it offset, other call it origin and some call it anchor.
I'll call it anchor from now on.

Here is the example:
image

Left-Top: No rotation
Right-Top: 45°, anchor at 200,200
Left-Bottom: 45°, anchor at 200, 360
Right-Bottom: 45°, anchor at 200, 40

from imaging.

christopher-kleine avatar christopher-kleine commented on July 2, 2024

Hi and thank you for the code. This REALY helps me out.

But I actually don't need to crop the image after rotating. I'd rather have the size adjusted to fit the entire picture. This can be seen using Natron.

I only added crop so I can show a more "compact" example.

from imaging.

disintegration avatar disintegration commented on July 2, 2024

The resulting images returned by the imaging functions always have min point at (0, 0). Given that we adjust the size of the resulting image to fit the entire image, changing the anchor point won't change the result.

Probably the golang.org/x/image/draw will be a better fit for your use case. Using the affine transformation matrix you can rotate the image around any point and calculate the new bounds after the rotation. Rotation by the same angle around different points will result in the same images but with different bounds.

I've adjusted the example code. It prints out the bounds on each iteration.

package main

import (
	"fmt"
	"image"
	"log"
	"math"

	"github.com/disintegration/imaging"
	"golang.org/x/image/draw"
	"golang.org/x/image/math/f64"
)

func main() {
	src, err := imaging.Open("test.png")
	if err != nil {
		log.Fatal(err)
	}
	for a := float64(0); a < 360; a += 10 {
		dst := rotateAround(src, a, 20, 20)
		fmt.Printf("angle=%03.0f, bounds=%v\n", a, dst.Bounds())
		err := imaging.Save(dst, fmt.Sprintf("rotated-%03.0f.png", a))
		if err != nil {
			log.Fatal(err)
		}
	}
}

func rotateAround(src image.Image, angle float64, x, y int) image.Image {
	xf, yf := float64(x), float64(y)
	sin, cos := math.Sincos(math.Pi * angle / 180)
	aff := f64.Aff3{
		cos, -sin, xf - xf*cos + yf*sin,
		sin, cos, yf - xf*sin - yf*cos,
	}
	dst := image.NewRGBA(calcBounds(aff, src.Bounds()))
	draw.CatmullRom.Transform(dst, aff, src, src.Bounds(), draw.Src, nil)
	return dst
}

func calcBounds(aff f64.Aff3, b image.Rectangle) image.Rectangle {
	points := [...]image.Point{
		{b.Min.X, b.Min.Y},
		{b.Max.X - 1, b.Min.Y},
		{b.Min.X, b.Max.Y - 1},
		{b.Max.X - 1, b.Max.Y - 1},
	}
	var min, max image.Point
	for i, p := range points {
		x0 := float64(p.X) + 0.5
		y0 := float64(p.Y) + 0.5
		x := aff[0]*x0 + aff[1]*y0 + aff[2]
		y := aff[3]*x0 + aff[4]*y0 + aff[5]
		pmin := image.Point{int(math.Floor(x)), int(math.Floor(y))}
		pmax := image.Point{int(math.Ceil(x)), int(math.Ceil(y))}
		if i == 0 {
			min = pmin
			max = pmax
			continue
		}
		if min.X > pmin.X {
			min.X = pmin.X
		}
		if min.Y > pmin.Y {
			min.Y = pmin.Y
		}
		if max.X < pmax.X {
			max.X = pmax.X
		}
		if max.Y < pmax.Y {
			max.Y = pmax.Y
		}

	}
	return image.Rectangle{Min: min, Max: max}
}

from imaging.

disintegration avatar disintegration commented on July 2, 2024

I'm closing the issue for now. Feel free to comment/reopen if you have any further questions.

from imaging.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.