mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-06 18:03:29 +02:00
Replace WatermarkOptions.Gravity with GravityReplicate
This commit is contained in:
@@ -19,6 +19,9 @@ const (
|
|||||||
GravitySouthEast
|
GravitySouthEast
|
||||||
GravitySmart
|
GravitySmart
|
||||||
GravityFocusPoint
|
GravityFocusPoint
|
||||||
|
|
||||||
|
// Watermark gravity types
|
||||||
|
GravityReplicate
|
||||||
)
|
)
|
||||||
|
|
||||||
var gravityTypes = map[string]GravityType{
|
var gravityTypes = map[string]GravityType{
|
||||||
@@ -33,6 +36,7 @@ var gravityTypes = map[string]GravityType{
|
|||||||
"soea": GravitySouthEast,
|
"soea": GravitySouthEast,
|
||||||
"sm": GravitySmart,
|
"sm": GravitySmart,
|
||||||
"fp": GravityFocusPoint,
|
"fp": GravityFocusPoint,
|
||||||
|
"re": GravityReplicate,
|
||||||
}
|
}
|
||||||
|
|
||||||
var gravityTypesRotationMap = map[int]map[GravityType]GravityType{
|
var gravityTypesRotationMap = map[int]map[GravityType]GravityType{
|
||||||
@@ -95,6 +99,19 @@ func (gt GravityType) MarshalJSON() ([]byte, error) {
|
|||||||
return []byte("null"), nil
|
return []byte("null"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (gt GravityType) OkForCrop() bool {
|
||||||
|
return gt != GravityUnknown && gt != GravityReplicate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gt GravityType) OkForExtend() bool {
|
||||||
|
return gt.OkForCrop() && gt != GravitySmart
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gt GravityType) OkForWatermark() bool {
|
||||||
|
return gt == GravityReplicate ||
|
||||||
|
(gt.OkForExtend() && gt != GravityFocusPoint)
|
||||||
|
}
|
||||||
|
|
||||||
type GravityOptions struct {
|
type GravityOptions struct {
|
||||||
Type GravityType
|
Type GravityType
|
||||||
X, Y float64
|
X, Y float64
|
||||||
|
@@ -54,11 +54,14 @@ type TrimOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WatermarkOptions struct {
|
type WatermarkOptions struct {
|
||||||
Enabled bool
|
Enabled bool
|
||||||
Opacity float64
|
Opacity float64
|
||||||
Replicate bool
|
Gravity GravityOptions
|
||||||
Gravity GravityOptions
|
Scale float64
|
||||||
Scale float64
|
}
|
||||||
|
|
||||||
|
func (wo WatermarkOptions) ShouldReplicate() bool {
|
||||||
|
return wo.Gravity.Type == GravityReplicate
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProcessingOptions struct {
|
type ProcessingOptions struct {
|
||||||
@@ -139,7 +142,7 @@ func NewProcessingOptions() *ProcessingOptions {
|
|||||||
Blur: 0,
|
Blur: 0,
|
||||||
Sharpen: 0,
|
Sharpen: 0,
|
||||||
Dpr: 1,
|
Dpr: 1,
|
||||||
Watermark: WatermarkOptions{Opacity: 1, Replicate: false, Gravity: GravityOptions{Type: GravityCenter}},
|
Watermark: WatermarkOptions{Opacity: 1, Gravity: GravityOptions{Type: GravityCenter}},
|
||||||
StripMetadata: config.StripMetadata,
|
StripMetadata: config.StripMetadata,
|
||||||
KeepCopyright: config.KeepCopyright,
|
KeepCopyright: config.KeepCopyright,
|
||||||
StripColorProfile: config.StripColorProfile,
|
StripColorProfile: config.StripColorProfile,
|
||||||
@@ -264,8 +267,8 @@ func parseExtend(opts *ExtendOptions, name string, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Gravity.Type == GravitySmart {
|
if !opts.Gravity.Type.OkForExtend() {
|
||||||
return fmt.Errorf("%s doesn't support smart gravity", name)
|
return fmt.Errorf("%s doesn't support %s gravity", name, opts.Gravity.Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,7 +431,15 @@ func applyDprOption(po *ProcessingOptions, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applyGravityOption(po *ProcessingOptions, args []string) error {
|
func applyGravityOption(po *ProcessingOptions, args []string) error {
|
||||||
return parseGravity(&po.Gravity, args)
|
if err := parseGravity(&po.Gravity, args); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !po.Gravity.Type.OkForCrop() {
|
||||||
|
return fmt.Errorf("%s gravity type is not applicable to gravity", po.Gravity.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCropOption(po *ProcessingOptions, args []string) error {
|
func applyCropOption(po *ProcessingOptions, args []string) error {
|
||||||
@@ -451,7 +462,12 @@ func applyCropOption(po *ProcessingOptions, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(args) > 2 {
|
if len(args) > 2 {
|
||||||
return parseGravity(&po.Crop.Gravity, args[2:])
|
if err := parseGravity(&po.Crop.Gravity, args[2:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !po.Crop.Gravity.Type.OkForCrop() {
|
||||||
|
return fmt.Errorf("%s gravity type is not applicable to crop", po.Crop.Gravity.Type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -715,9 +731,7 @@ func applyWatermarkOption(po *ProcessingOptions, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(args) > 1 && len(args[1]) > 0 {
|
if len(args) > 1 && len(args[1]) > 0 {
|
||||||
if args[1] == "re" {
|
if g, ok := gravityTypes[args[1]]; ok && g.OkForWatermark() {
|
||||||
po.Watermark.Replicate = true
|
|
||||||
} else if g, ok := gravityTypes[args[1]]; ok && g != GravityFocusPoint && g != GravitySmart {
|
|
||||||
po.Watermark.Gravity.Type = g
|
po.Watermark.Gravity.Type = g
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("Invalid watermark position: %s", args[1])
|
return fmt.Errorf("Invalid watermark position: %s", args[1])
|
||||||
|
@@ -236,6 +236,20 @@ func (s *ProcessingOptionsTestSuite) TestParsePathExtend() {
|
|||||||
s.Require().InDelta(20.0, po.Extend.Gravity.Y, 0.0001)
|
s.Require().InDelta(20.0, po.Extend.Gravity.Y, 0.0001)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathExtendSmartGravity() {
|
||||||
|
path := "/extend:1:sm/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
_, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathExtendReplicateGravity() {
|
||||||
|
path := "/extend:1:re/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
_, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ProcessingOptionsTestSuite) TestParsePathGravity() {
|
func (s *ProcessingOptionsTestSuite) TestParsePathGravity() {
|
||||||
path := "/gravity:soea/plain/http://images.dev/lorem/ipsum.jpg"
|
path := "/gravity:soea/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
po, _, err := ParsePath(path, make(http.Header))
|
po, _, err := ParsePath(path, make(http.Header))
|
||||||
@@ -245,7 +259,7 @@ func (s *ProcessingOptionsTestSuite) TestParsePathGravity() {
|
|||||||
s.Require().Equal(GravitySouthEast, po.Gravity.Type)
|
s.Require().Equal(GravitySouthEast, po.Gravity.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocuspoint() {
|
func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocusPoint() {
|
||||||
path := "/gravity:fp:0.5:0.75/plain/http://images.dev/lorem/ipsum.jpg"
|
path := "/gravity:fp:0.5:0.75/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
po, _, err := ParsePath(path, make(http.Header))
|
po, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
@@ -256,6 +270,46 @@ func (s *ProcessingOptionsTestSuite) TestParsePathGravityFocuspoint() {
|
|||||||
s.Require().InDelta(0.75, po.Gravity.Y, 0.0001)
|
s.Require().InDelta(0.75, po.Gravity.Y, 0.0001)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathGravityReplicate() {
|
||||||
|
path := "/gravity:re/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
_, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathCrop() {
|
||||||
|
path := "/crop:100:200/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
po, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.Require().InDelta(100.0, po.Crop.Width, 0.0001)
|
||||||
|
s.Require().InDelta(200.0, po.Crop.Height, 0.0001)
|
||||||
|
s.Require().Equal(GravityUnknown, po.Crop.Gravity.Type)
|
||||||
|
s.Require().InDelta(0.0, po.Crop.Gravity.X, 0.0001)
|
||||||
|
s.Require().InDelta(0.0, po.Crop.Gravity.Y, 0.0001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathCropGravity() {
|
||||||
|
path := "/crop:100:200:nowe:10:20/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
po, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
s.Require().InDelta(100.0, po.Crop.Width, 0.0001)
|
||||||
|
s.Require().InDelta(200.0, po.Crop.Height, 0.0001)
|
||||||
|
s.Require().Equal(GravityNorthWest, po.Crop.Gravity.Type)
|
||||||
|
s.Require().InDelta(10.0, po.Crop.Gravity.X, 0.0001)
|
||||||
|
s.Require().InDelta(20.0, po.Crop.Gravity.Y, 0.0001)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ProcessingOptionsTestSuite) TestParsePathCropGravityReplicate() {
|
||||||
|
path := "/crop:100:200:re/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
|
_, _, err := ParsePath(path, make(http.Header))
|
||||||
|
|
||||||
|
s.Require().Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ProcessingOptionsTestSuite) TestParsePathQuality() {
|
func (s *ProcessingOptionsTestSuite) TestParsePathQuality() {
|
||||||
path := "/quality:55/plain/http://images.dev/lorem/ipsum.jpg"
|
path := "/quality:55/plain/http://images.dev/lorem/ipsum.jpg"
|
||||||
po, _, err := ParsePath(path, make(http.Header))
|
po, _, err := ParsePath(path, make(http.Header))
|
||||||
|
@@ -36,7 +36,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options
|
|||||||
po.Height = imath.Max(imath.ScaleToEven(imgHeight, opts.Scale), 1)
|
po.Height = imath.Max(imath.ScaleToEven(imgHeight, opts.Scale), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Replicate {
|
if opts.ShouldReplicate() {
|
||||||
var offX, offY int
|
var offX, offY int
|
||||||
|
|
||||||
if math.Abs(opts.Gravity.X) >= 1.0 {
|
if math.Abs(opts.Gravity.X) >= 1.0 {
|
||||||
@@ -62,7 +62,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Replicate || framesCount > 1 {
|
if opts.ShouldReplicate() || framesCount > 1 {
|
||||||
// We need to copy image if we're going to replicate.
|
// We need to copy image if we're going to replicate.
|
||||||
// Replication requires image to be read several times, and this requires
|
// Replication requires image to be read several times, and this requires
|
||||||
// random access to pixels
|
// random access to pixels
|
||||||
@@ -71,7 +71,7 @@ func prepareWatermark(wm *vips.Image, wmData *imagedata.ImageData, opts *options
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Replicate {
|
if opts.ShouldReplicate() {
|
||||||
if err := wm.Replicate(imgWidth, imgHeight); err != nil {
|
if err := wm.Replicate(imgWidth, imgHeight); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ func applyWatermark(img *vips.Image, wmData *imagedata.ImageData, opts *options.
|
|||||||
|
|
||||||
// If we replicated the watermark and need to apply it to an animated image,
|
// If we replicated the watermark and need to apply it to an animated image,
|
||||||
// it is faster to replicate the watermark to all the image and apply it single-pass
|
// it is faster to replicate the watermark to all the image and apply it single-pass
|
||||||
if opts.Replicate && framesCount > 1 {
|
if opts.ShouldReplicate() && framesCount > 1 {
|
||||||
if err := wm.Replicate(width, height); err != nil {
|
if err := wm.Replicate(width, height); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@ func applyWatermark(img *vips.Image, wmData *imagedata.ImageData, opts *options.
|
|||||||
|
|
||||||
left, top := 0, 0
|
left, top := 0, 0
|
||||||
|
|
||||||
if !opts.Replicate {
|
if !opts.ShouldReplicate() {
|
||||||
left, top = calcPosition(width, frameHeight, wm.Width(), wm.Height(), &opts.Gravity, offsetScale, true)
|
left, top = calcPosition(width, frameHeight, wm.Width(), wm.Height(), &opts.Gravity, offsetScale, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user