mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-12-23 22:11:10 +02:00
157 lines
4.1 KiB
Go
157 lines
4.1 KiB
Go
package processing
|
|
|
|
import (
|
|
"github.com/imgproxy/imgproxy/v3/options"
|
|
"github.com/imgproxy/imgproxy/v3/options/keys"
|
|
)
|
|
|
|
var gravityTypesRotationMap = map[int]map[GravityType]GravityType{
|
|
90: {
|
|
GravityNorth: GravityWest,
|
|
GravityEast: GravityNorth,
|
|
GravitySouth: GravityEast,
|
|
GravityWest: GravitySouth,
|
|
GravityNorthWest: GravitySouthWest,
|
|
GravityNorthEast: GravityNorthWest,
|
|
GravitySouthWest: GravitySouthEast,
|
|
GravitySouthEast: GravityNorthEast,
|
|
},
|
|
180: {
|
|
GravityNorth: GravitySouth,
|
|
GravityEast: GravityWest,
|
|
GravitySouth: GravityNorth,
|
|
GravityWest: GravityEast,
|
|
GravityNorthWest: GravitySouthEast,
|
|
GravityNorthEast: GravitySouthWest,
|
|
GravitySouthWest: GravityNorthEast,
|
|
GravitySouthEast: GravityNorthWest,
|
|
},
|
|
270: {
|
|
GravityNorth: GravityEast,
|
|
GravityEast: GravitySouth,
|
|
GravitySouth: GravityWest,
|
|
GravityWest: GravityNorth,
|
|
GravityNorthWest: GravityNorthEast,
|
|
GravityNorthEast: GravitySouthEast,
|
|
GravitySouthWest: GravityNorthWest,
|
|
GravitySouthEast: GravitySouthWest,
|
|
},
|
|
}
|
|
|
|
var gravityTypesFlipXMap = map[GravityType]GravityType{
|
|
GravityEast: GravityWest,
|
|
GravityWest: GravityEast,
|
|
GravityNorthWest: GravityNorthEast,
|
|
GravityNorthEast: GravityNorthWest,
|
|
GravitySouthWest: GravitySouthEast,
|
|
GravitySouthEast: GravitySouthWest,
|
|
}
|
|
|
|
var gravityTypesFlipYMap = map[GravityType]GravityType{
|
|
GravityNorth: GravitySouth,
|
|
GravitySouth: GravityNorth,
|
|
GravityNorthWest: GravitySouthWest,
|
|
GravityNorthEast: GravitySouthEast,
|
|
GravitySouthWest: GravityNorthWest,
|
|
GravitySouthEast: GravityNorthEast,
|
|
}
|
|
|
|
type GravityOptions struct {
|
|
Type GravityType
|
|
X, Y float64
|
|
}
|
|
|
|
// NewGravityOptions builds a new [GravityOptions] instance.
|
|
// It fills the [GravityOptions] struct with the options values under the given prefix.
|
|
// If the gravity type is not set in the options,
|
|
// it returns a [GravityOptions] with the provided default type.
|
|
func NewGravityOptions(o *options.Options, prefix string, defType GravityType) GravityOptions {
|
|
gr := GravityOptions{
|
|
Type: options.Get(o, prefix+keys.SuffixType, defType),
|
|
X: o.GetFloat(prefix+keys.SuffixXOffset, 0.0),
|
|
Y: o.GetFloat(prefix+keys.SuffixYOffset, 0.0),
|
|
}
|
|
|
|
return gr
|
|
}
|
|
|
|
// RotateAndFlip rotates and flips the gravity options so that they correspond
|
|
// to the image before rotation and flipping.
|
|
//
|
|
// By design, rotation and flipping are applied before cropping.
|
|
// But for performance reasons, we do cropping before rotation and flipping.
|
|
// So we need to adjust gravity options accordingly.
|
|
// As a result, cropping with the adjusted gravity options
|
|
// and then rotating/flipping the cropped image gives the same result
|
|
// as rotating/flipping the image first and then cropping
|
|
// with the original gravity options.
|
|
func (g *GravityOptions) RotateAndFlip(angle int, flipX, flipY bool) {
|
|
angle %= 360
|
|
|
|
if flipX {
|
|
if gt, ok := gravityTypesFlipXMap[g.Type]; ok {
|
|
g.Type = gt
|
|
}
|
|
|
|
switch g.Type {
|
|
case GravityCenter, GravityNorth, GravitySouth:
|
|
g.X = -g.X
|
|
case GravityFocusPoint:
|
|
g.X = 1.0 - g.X
|
|
}
|
|
}
|
|
|
|
if flipY {
|
|
if gt, ok := gravityTypesFlipYMap[g.Type]; ok {
|
|
g.Type = gt
|
|
}
|
|
|
|
switch g.Type {
|
|
case GravityCenter, GravityEast, GravityWest:
|
|
g.Y = -g.Y
|
|
case GravityFocusPoint:
|
|
g.Y = 1.0 - g.Y
|
|
}
|
|
}
|
|
|
|
if angle > 0 {
|
|
if rotMap := gravityTypesRotationMap[angle]; rotMap != nil {
|
|
if gt, ok := rotMap[g.Type]; ok {
|
|
g.Type = gt
|
|
}
|
|
|
|
switch angle {
|
|
case 90:
|
|
switch g.Type {
|
|
case GravityCenter, GravityEast, GravityWest:
|
|
g.X, g.Y = g.Y, -g.X
|
|
case GravityFocusPoint:
|
|
g.X, g.Y = g.Y, 1.0-g.X
|
|
default:
|
|
g.X, g.Y = g.Y, g.X
|
|
}
|
|
case 180:
|
|
switch g.Type {
|
|
case GravityCenter:
|
|
g.X, g.Y = -g.X, -g.Y
|
|
case GravityNorth, GravitySouth:
|
|
g.X = -g.X
|
|
case GravityEast, GravityWest:
|
|
g.Y = -g.Y
|
|
case GravityFocusPoint:
|
|
g.X, g.Y = 1.0-g.X, 1.0-g.Y
|
|
}
|
|
case 270:
|
|
switch g.Type {
|
|
case GravityCenter, GravityNorth, GravitySouth:
|
|
g.X, g.Y = -g.Y, g.X
|
|
case GravityFocusPoint:
|
|
g.X, g.Y = 1.0-g.Y, g.X
|
|
default:
|
|
g.X, g.Y = g.Y, g.X
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|