Files
imgproxy/processing/gravity.go
2025-09-24 00:41:12 +06:00

125 lines
3.7 KiB
Go

package processing
import (
"github.com/imgproxy/imgproxy/v3/options"
"github.com/imgproxy/imgproxy/v3/options/keys"
)
var gravityTypesRotationMap = map[int]map[options.GravityType]options.GravityType{
90: {
options.GravityNorth: options.GravityWest,
options.GravityEast: options.GravityNorth,
options.GravitySouth: options.GravityEast,
options.GravityWest: options.GravitySouth,
options.GravityNorthWest: options.GravitySouthWest,
options.GravityNorthEast: options.GravityNorthWest,
options.GravitySouthWest: options.GravitySouthEast,
options.GravitySouthEast: options.GravityNorthEast,
},
180: {
options.GravityNorth: options.GravitySouth,
options.GravityEast: options.GravityWest,
options.GravitySouth: options.GravityNorth,
options.GravityWest: options.GravityEast,
options.GravityNorthWest: options.GravitySouthEast,
options.GravityNorthEast: options.GravitySouthWest,
options.GravitySouthWest: options.GravityNorthEast,
options.GravitySouthEast: options.GravityNorthWest,
},
270: {
options.GravityNorth: options.GravityEast,
options.GravityEast: options.GravitySouth,
options.GravitySouth: options.GravityWest,
options.GravityWest: options.GravityNorth,
options.GravityNorthWest: options.GravityNorthEast,
options.GravityNorthEast: options.GravitySouthEast,
options.GravitySouthWest: options.GravityNorthWest,
options.GravitySouthEast: options.GravitySouthWest,
},
}
var gravityTypesFlipMap = map[options.GravityType]options.GravityType{
options.GravityEast: options.GravityWest,
options.GravityWest: options.GravityEast,
options.GravityNorthWest: options.GravityNorthEast,
options.GravityNorthEast: options.GravityNorthWest,
options.GravitySouthWest: options.GravitySouthEast,
options.GravitySouthEast: options.GravitySouthWest,
}
type GravityOptions struct {
Type options.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 ProcessingOptions, prefix string, defType options.GravityType) GravityOptions {
gr := GravityOptions{
Type: options.Get(o.Options, prefix+keys.SuffixType, defType),
X: o.GetFloat(prefix+keys.SuffixXOffset, 0.0),
Y: o.GetFloat(prefix+keys.SuffixYOffset, 0.0),
}
return gr
}
func (g *GravityOptions) RotateAndFlip(angle int, flip bool) {
angle %= 360
if flip {
if gt, ok := gravityTypesFlipMap[g.Type]; ok {
g.Type = gt
}
switch g.Type {
case options.GravityCenter, options.GravityNorth, options.GravitySouth:
g.X = -g.X
case options.GravityFocusPoint:
g.X = 1.0 - g.X
}
}
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 options.GravityCenter, options.GravityEast, options.GravityWest:
g.X, g.Y = g.Y, -g.X
case options.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 options.GravityCenter:
g.X, g.Y = -g.X, -g.Y
case options.GravityNorth, options.GravitySouth:
g.X = -g.X
case options.GravityEast, options.GravityWest:
g.Y = -g.Y
case options.GravityFocusPoint:
g.X, g.Y = 1.0-g.X, 1.0-g.Y
}
case 270:
switch g.Type {
case options.GravityCenter, options.GravityNorth, options.GravitySouth:
g.X, g.Y = -g.Y, g.X
case options.GravityFocusPoint:
g.X, g.Y = 1.0-g.Y, g.X
default:
g.X, g.Y = g.Y, g.X
}
}
}
}
}