Comments (6)
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:
Resulting images after rotation 30 and 60 degrees clockwise with the anchor point (20,20):
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.
Hi,
What do you mean by "offset"? Could you provide an example?
from imaging.
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.
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.
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.
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.
I'm closing the issue for now. Feel free to comment/reopen if you have any further questions.
from imaging.
Related Issues (20)
- WebP support HOT 2
- How to get image width from imaging HOT 1
- Cannot apply transparency HOT 1
- imaging.Open throw error: image: unknown format HOT 2
- How to get file from postman HOT 2
- how can we resize image HOT 3
- Does imaging support wartermark text?
- Images not get fully processed even if background is filled with base color? HOT 1
- resize image become bigger HOT 1
- What is the different Resize and Thumbnail functions? HOT 1
- How to convert png-24 to png-8? HOT 1
- Support HEIF (.heic) files with AutoOrientation HOT 1
- Panic in the Rotate90 function.
- Export fixOrientation HOT 1
- Paste function panics
- Rotated image background won't blend according to Alpha when pasting
- Specific image will cause the index of the scan function in scanner.go to go out of bounds
- Snyk reports vulnerability HOT 1
- Maybe it's time to release version 1.6.3 so as not to have to go to the master branch for it
- 5 years doesn't update?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from imaging.