|
@@ -1,7 +1,6 @@
|
|
|
package options
|
|
|
|
|
|
import (
|
|
|
- "encoding/base64"
|
|
|
"maps"
|
|
|
"net/http"
|
|
|
"slices"
|
|
@@ -9,8 +8,6 @@ import (
|
|
|
"strings"
|
|
|
"time"
|
|
|
|
|
|
- log "github.com/sirupsen/logrus"
|
|
|
-
|
|
|
"github.com/imgproxy/imgproxy/v3/ierrors"
|
|
|
"github.com/imgproxy/imgproxy/v3/imagetype"
|
|
|
"github.com/imgproxy/imgproxy/v3/imath"
|
|
@@ -61,6 +58,9 @@ func (wo WatermarkOptions) ShouldReplicate() bool {
|
|
|
}
|
|
|
|
|
|
type ProcessingOptions struct {
|
|
|
+ defaultOptions *ProcessingOptions
|
|
|
+ config *Config
|
|
|
+
|
|
|
ResizingType ResizeType
|
|
|
Width int
|
|
|
Height int
|
|
@@ -115,13 +115,12 @@ type ProcessingOptions struct {
|
|
|
UsedPresets []string
|
|
|
|
|
|
SecurityOptions security.Options
|
|
|
-
|
|
|
- defaultQuality int
|
|
|
- defaultOptions *ProcessingOptions
|
|
|
}
|
|
|
|
|
|
func newDefaultProcessingOptions(config *Config, security *security.Checker) *ProcessingOptions {
|
|
|
po := ProcessingOptions{
|
|
|
+ config: config,
|
|
|
+
|
|
|
ResizingType: ResizeFit,
|
|
|
Width: 0,
|
|
|
Height: 0,
|
|
@@ -153,8 +152,6 @@ func newDefaultProcessingOptions(config *Config, security *security.Checker) *Pr
|
|
|
SkipProcessingFormats: slices.Clone(config.SkipProcessingFormats),
|
|
|
|
|
|
SecurityOptions: security.NewOptions(),
|
|
|
-
|
|
|
- defaultQuality: config.Quality,
|
|
|
}
|
|
|
|
|
|
return &po
|
|
@@ -168,7 +165,7 @@ func (po *ProcessingOptions) GetQuality() int {
|
|
|
}
|
|
|
|
|
|
if q == 0 {
|
|
|
- q = po.defaultQuality
|
|
|
+ q = po.config.Quality
|
|
|
}
|
|
|
|
|
|
return q
|
|
@@ -214,799 +211,6 @@ func (po *ProcessingOptions) clone() *ProcessingOptions {
|
|
|
return &clone
|
|
|
}
|
|
|
|
|
|
-func parseDimension(d *int, name, arg string) error {
|
|
|
- if v, err := strconv.Atoi(arg); err == nil && v >= 0 {
|
|
|
- *d = v
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid %s: %s", name, arg)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func parseBoolOption(str string) bool {
|
|
|
- b, err := strconv.ParseBool(str)
|
|
|
-
|
|
|
- if err != nil {
|
|
|
- log.Warningf("`%s` is not a valid boolean value. Treated as false", str)
|
|
|
- }
|
|
|
-
|
|
|
- return b
|
|
|
-}
|
|
|
-
|
|
|
-func isGravityOffcetValid(gravity GravityType, offset float64) bool {
|
|
|
- return gravity != GravityFocusPoint || (offset >= 0 && offset <= 1)
|
|
|
-}
|
|
|
-
|
|
|
-func parseGravity(g *GravityOptions, name string, args []string, allowedTypes []GravityType) error {
|
|
|
- nArgs := len(args)
|
|
|
-
|
|
|
- if t, ok := gravityTypes[args[0]]; ok && slices.Contains(allowedTypes, t) {
|
|
|
- g.Type = t
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid %s: %s", name, args[0])
|
|
|
- }
|
|
|
-
|
|
|
- switch g.Type {
|
|
|
- case GravitySmart:
|
|
|
- if nArgs > 1 {
|
|
|
- return newOptionArgumentError("Invalid %s arguments: %v", name, args)
|
|
|
- }
|
|
|
- g.X, g.Y = 0.0, 0.0
|
|
|
-
|
|
|
- case GravityFocusPoint:
|
|
|
- if nArgs != 3 {
|
|
|
- return newOptionArgumentError("Invalid %s arguments: %v", name, args)
|
|
|
- }
|
|
|
- fallthrough
|
|
|
-
|
|
|
- default:
|
|
|
- if nArgs > 3 {
|
|
|
- return newOptionArgumentError("Invalid %s arguments: %v", name, args)
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 1 {
|
|
|
- if x, err := strconv.ParseFloat(args[1], 64); err == nil && isGravityOffcetValid(g.Type, x) {
|
|
|
- g.X = x
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid %s X: %s", name, args[1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 2 {
|
|
|
- if y, err := strconv.ParseFloat(args[2], 64); err == nil && isGravityOffcetValid(g.Type, y) {
|
|
|
- g.Y = y
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid %s Y: %s", name, args[2])
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func parseExtend(opts *ExtendOptions, name string, args []string) error {
|
|
|
- if len(args) > 4 {
|
|
|
- return newOptionArgumentError("Invalid %s arguments: %v", name, args)
|
|
|
- }
|
|
|
-
|
|
|
- opts.Enabled = parseBoolOption(args[0])
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return parseGravity(&opts.Gravity, name+" gravity", args[1:], extendGravityTypes)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyWidthOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid width arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- return parseDimension(&po.Width, "width", args[0])
|
|
|
-}
|
|
|
-
|
|
|
-func applyHeightOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid height arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- return parseDimension(&po.Height, "height", args[0])
|
|
|
-}
|
|
|
-
|
|
|
-func applyMinWidthOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid min width arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- return parseDimension(&po.MinWidth, "min width", args[0])
|
|
|
-}
|
|
|
-
|
|
|
-func applyMinHeightOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid min height arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- return parseDimension(&po.MinHeight, " min height", args[0])
|
|
|
-}
|
|
|
-
|
|
|
-func applyEnlargeOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid enlarge arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.Enlarge = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyExtendOption(po *ProcessingOptions, args []string) error {
|
|
|
- return parseExtend(&po.Extend, "extend", args)
|
|
|
-}
|
|
|
-
|
|
|
-func applyExtendAspectRatioOption(po *ProcessingOptions, args []string) error {
|
|
|
- return parseExtend(&po.ExtendAspectRatio, "extend_aspect_ratio", args)
|
|
|
-}
|
|
|
-
|
|
|
-func applySizeOption(po *ProcessingOptions, args []string) (err error) {
|
|
|
- if len(args) > 7 {
|
|
|
- return newOptionArgumentError("Invalid size arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) >= 1 && len(args[0]) > 0 {
|
|
|
- if err = applyWidthOption(po, args[0:1]); err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) >= 2 && len(args[1]) > 0 {
|
|
|
- if err = applyHeightOption(po, args[1:2]); err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) >= 3 && len(args[2]) > 0 {
|
|
|
- if err = applyEnlargeOption(po, args[2:3]); err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) >= 4 && len(args[3]) > 0 {
|
|
|
- if err = applyExtendOption(po, args[3:]); err != nil {
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyResizingTypeOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid resizing type arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if r, ok := resizeTypes[args[0]]; ok {
|
|
|
- po.ResizingType = r
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid resize type: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyResizeOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 8 {
|
|
|
- return newOptionArgumentError("Invalid resize arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if len(args[0]) > 0 {
|
|
|
- if err := applyResizingTypeOption(po, args[0:1]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- if err := applySizeOption(po, args[1:]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyZoomOption(po *ProcessingOptions, args []string) error {
|
|
|
- nArgs := len(args)
|
|
|
-
|
|
|
- if nArgs > 2 {
|
|
|
- return newOptionArgumentError("Invalid zoom arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if z, err := strconv.ParseFloat(args[0], 64); err == nil && z > 0 {
|
|
|
- po.ZoomWidth = z
|
|
|
- po.ZoomHeight = z
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid zoom value: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 1 {
|
|
|
- if z, err := strconv.ParseFloat(args[1], 64); err == nil && z > 0 {
|
|
|
- po.ZoomHeight = z
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid zoom value: %s", args[1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyDprOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid dpr arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if d, err := strconv.ParseFloat(args[0], 64); err == nil && d > 0 {
|
|
|
- po.Dpr = d
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid dpr: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyGravityOption(po *ProcessingOptions, args []string) error {
|
|
|
- return parseGravity(&po.Gravity, "gravity", args, cropGravityTypes)
|
|
|
-}
|
|
|
-
|
|
|
-func applyCropOption(po *ProcessingOptions, args []string) error {
|
|
|
- if w, err := strconv.ParseFloat(args[0], 64); err == nil && w >= 0 {
|
|
|
- po.Crop.Width = w
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid crop width: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- if h, err := strconv.ParseFloat(args[1], 64); err == nil && h >= 0 {
|
|
|
- po.Crop.Height = h
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid crop height: %s", args[1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 2 {
|
|
|
- return parseGravity(&po.Crop.Gravity, "crop gravity", args[2:], cropGravityTypes)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyPaddingOption(po *ProcessingOptions, args []string) error {
|
|
|
- nArgs := len(args)
|
|
|
-
|
|
|
- if nArgs < 1 || nArgs > 4 {
|
|
|
- return newOptionArgumentError("Invalid padding arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.Padding.Enabled = true
|
|
|
-
|
|
|
- if nArgs > 0 && len(args[0]) > 0 {
|
|
|
- if err := parseDimension(&po.Padding.Top, "padding top (+all)", args[0]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- po.Padding.Right = po.Padding.Top
|
|
|
- po.Padding.Bottom = po.Padding.Top
|
|
|
- po.Padding.Left = po.Padding.Top
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 1 && len(args[1]) > 0 {
|
|
|
- if err := parseDimension(&po.Padding.Right, "padding right (+left)", args[1]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- po.Padding.Left = po.Padding.Right
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 2 && len(args[2]) > 0 {
|
|
|
- if err := parseDimension(&po.Padding.Bottom, "padding bottom", args[2]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 3 && len(args[3]) > 0 {
|
|
|
- if err := parseDimension(&po.Padding.Left, "padding left", args[3]); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if po.Padding.Top == 0 && po.Padding.Right == 0 && po.Padding.Bottom == 0 && po.Padding.Left == 0 {
|
|
|
- po.Padding.Enabled = false
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyTrimOption(po *ProcessingOptions, args []string) error {
|
|
|
- nArgs := len(args)
|
|
|
-
|
|
|
- if nArgs > 4 {
|
|
|
- return newOptionArgumentError("Invalid trim arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if t, err := strconv.ParseFloat(args[0], 64); err == nil && t >= 0 {
|
|
|
- po.Trim.Enabled = true
|
|
|
- po.Trim.Threshold = t
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid trim threshold: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 1 && len(args[1]) > 0 {
|
|
|
- if c, err := vips.ColorFromHex(args[1]); err == nil {
|
|
|
- po.Trim.Color = c
|
|
|
- po.Trim.Smart = false
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid trim color: %s", args[1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 2 && len(args[2]) > 0 {
|
|
|
- po.Trim.EqualHor = parseBoolOption(args[2])
|
|
|
- }
|
|
|
-
|
|
|
- if nArgs > 3 && len(args[3]) > 0 {
|
|
|
- po.Trim.EqualVer = parseBoolOption(args[3])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyRotateOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid rotate arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if r, err := strconv.Atoi(args[0]); err == nil && r%90 == 0 {
|
|
|
- po.Rotate = r
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid rotation angle: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyQualityOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid quality arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if q, err := strconv.Atoi(args[0]); err == nil && q >= 0 && q <= 100 {
|
|
|
- po.Quality = q
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid quality: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyFormatQualityOption(po *ProcessingOptions, args []string) error {
|
|
|
- argsLen := len(args)
|
|
|
- if len(args)%2 != 0 {
|
|
|
- return newOptionArgumentError("Missing quality for: %s", args[argsLen-1])
|
|
|
- }
|
|
|
-
|
|
|
- for i := 0; i < argsLen; i += 2 {
|
|
|
- f, ok := imagetype.GetTypeByName(args[i])
|
|
|
- if !ok {
|
|
|
- return newOptionArgumentError("Invalid image format: %s", args[i])
|
|
|
- }
|
|
|
-
|
|
|
- if q, err := strconv.Atoi(args[i+1]); err == nil && q >= 0 && q <= 100 {
|
|
|
- po.FormatQuality[f] = q
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid quality for %s: %s", args[i], args[i+1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxBytesOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_bytes arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if max, err := strconv.Atoi(args[0]); err == nil && max >= 0 {
|
|
|
- po.MaxBytes = max
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_bytes: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyBackgroundOption(po *ProcessingOptions, args []string) error {
|
|
|
- switch len(args) {
|
|
|
- case 1:
|
|
|
- if len(args[0]) == 0 {
|
|
|
- po.Flatten = false
|
|
|
- } else if c, err := vips.ColorFromHex(args[0]); err == nil {
|
|
|
- po.Flatten = true
|
|
|
- po.Background = c
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid background argument: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- case 3:
|
|
|
- po.Flatten = true
|
|
|
-
|
|
|
- if r, err := strconv.ParseUint(args[0], 10, 8); err == nil && r <= 255 {
|
|
|
- po.Background.R = uint8(r)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid background red channel: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if g, err := strconv.ParseUint(args[1], 10, 8); err == nil && g <= 255 {
|
|
|
- po.Background.G = uint8(g)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid background green channel: %s", args[1])
|
|
|
- }
|
|
|
-
|
|
|
- if b, err := strconv.ParseUint(args[2], 10, 8); err == nil && b <= 255 {
|
|
|
- po.Background.B = uint8(b)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid background blue channel: %s", args[2])
|
|
|
- }
|
|
|
-
|
|
|
- default:
|
|
|
- return newOptionArgumentError("Invalid background arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyBlurOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid blur arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if b, err := strconv.ParseFloat(args[0], 32); err == nil && b >= 0 {
|
|
|
- po.Blur = float32(b)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid blur: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applySharpenOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid sharpen arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if s, err := strconv.ParseFloat(args[0], 32); err == nil && s >= 0 {
|
|
|
- po.Sharpen = float32(s)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid sharpen: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyPixelateOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid pixelate arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if p, err := strconv.Atoi(args[0]); err == nil && p >= 0 {
|
|
|
- po.Pixelate = p
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid pixelate: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func (f *Factory) applyPresetOption(po *ProcessingOptions, args []string, usedPresets ...string) error {
|
|
|
- for _, preset := range args {
|
|
|
- if p, ok := f.presets[preset]; ok {
|
|
|
- if slices.Contains(usedPresets, preset) {
|
|
|
- log.Warningf("Recursive preset usage is detected: %s", preset)
|
|
|
- continue
|
|
|
- }
|
|
|
-
|
|
|
- po.UsedPresets = append(po.UsedPresets, preset)
|
|
|
-
|
|
|
- if err := f.applyURLOptions(po, p, true, append(usedPresets, preset)...); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Unknown preset: %s", preset)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyWatermarkOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 7 {
|
|
|
- return newOptionArgumentError("Invalid watermark arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if o, err := strconv.ParseFloat(args[0], 64); err == nil && o >= 0 && o <= 1 {
|
|
|
- po.Watermark.Enabled = o > 0
|
|
|
- po.Watermark.Opacity = o
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid watermark opacity: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 && len(args[1]) > 0 {
|
|
|
- if g, ok := gravityTypes[args[1]]; ok && slices.Contains(watermarkGravityTypes, g) {
|
|
|
- po.Watermark.Position.Type = g
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid watermark position: %s", args[1])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 2 && len(args[2]) > 0 {
|
|
|
- if x, err := strconv.ParseFloat(args[2], 64); err == nil {
|
|
|
- po.Watermark.Position.X = x
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid watermark X offset: %s", args[2])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 3 && len(args[3]) > 0 {
|
|
|
- if y, err := strconv.ParseFloat(args[3], 64); err == nil {
|
|
|
- po.Watermark.Position.Y = y
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid watermark Y offset: %s", args[3])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 4 && len(args[4]) > 0 {
|
|
|
- if s, err := strconv.ParseFloat(args[4], 64); err == nil && s >= 0 {
|
|
|
- po.Watermark.Scale = s
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid watermark scale: %s", args[4])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyFormatOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid format arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if f, ok := imagetype.GetTypeByName(args[0]); ok {
|
|
|
- po.Format = f
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid image format: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyCacheBusterOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid cache buster arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.CacheBuster = args[0]
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applySkipProcessingFormatsOption(po *ProcessingOptions, args []string) error {
|
|
|
- for _, format := range args {
|
|
|
- if f, ok := imagetype.GetTypeByName(format); ok {
|
|
|
- po.SkipProcessingFormats = append(po.SkipProcessingFormats, f)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid image format in skip processing: %s", format)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyRawOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid return_attachment arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.Raw = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyFilenameOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 2 {
|
|
|
- return newOptionArgumentError("Invalid filename arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.Filename = args[0]
|
|
|
-
|
|
|
- if len(args) > 1 && parseBoolOption(args[1]) {
|
|
|
- decoded, err := base64.RawURLEncoding.DecodeString(po.Filename)
|
|
|
- if err != nil {
|
|
|
- return newOptionArgumentError("Invalid filename encoding: %s", err)
|
|
|
- }
|
|
|
-
|
|
|
- po.Filename = string(decoded)
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyExpiresOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid expires arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- timestamp, err := strconv.ParseInt(args[0], 10, 64)
|
|
|
- if err != nil {
|
|
|
- return newOptionArgumentError("Invalid expires argument: %v", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- if timestamp > 0 && timestamp < time.Now().Unix() {
|
|
|
- return newOptionArgumentError("Expired URL")
|
|
|
- }
|
|
|
-
|
|
|
- expires := time.Unix(timestamp, 0)
|
|
|
- po.Expires = &expires
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyStripMetadataOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid strip metadata arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.StripMetadata = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyKeepCopyrightOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid keep copyright arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.KeepCopyright = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyStripColorProfileOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid strip color profile arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.StripColorProfile = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyAutoRotateOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid auto rotate arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.AutoRotate = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyEnforceThumbnailOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid enforce thumbnail arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.EnforceThumbnail = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyReturnAttachmentOption(po *ProcessingOptions, args []string) error {
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid return_attachment arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- po.ReturnAttachment = parseBoolOption(args[0])
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxSrcResolutionOption(po *ProcessingOptions, args []string) error {
|
|
|
- if err := security.IsSecurityOptionsAllowed(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_src_resolution arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if x, err := strconv.ParseFloat(args[0], 64); err == nil && x > 0 {
|
|
|
- po.SecurityOptions.MaxSrcResolution = int(x * 1000000)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_src_resolution: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxSrcFileSizeOption(po *ProcessingOptions, args []string) error {
|
|
|
- if err := security.IsSecurityOptionsAllowed(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_src_file_size arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if x, err := strconv.Atoi(args[0]); err == nil {
|
|
|
- po.SecurityOptions.MaxSrcFileSize = x
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_src_file_size: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxAnimationFramesOption(po *ProcessingOptions, args []string) error {
|
|
|
- if err := security.IsSecurityOptionsAllowed(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_animation_frames arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if x, err := strconv.Atoi(args[0]); err == nil && x > 0 {
|
|
|
- po.SecurityOptions.MaxAnimationFrames = x
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_animation_frames: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxAnimationFrameResolutionOption(po *ProcessingOptions, args []string) error {
|
|
|
- if err := security.IsSecurityOptionsAllowed(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_animation_frame_resolution arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if x, err := strconv.ParseFloat(args[0], 64); err == nil {
|
|
|
- po.SecurityOptions.MaxAnimationFrameResolution = int(x * 1000000)
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_animation_frame_resolution: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-func applyMaxResultDimensionOption(po *ProcessingOptions, args []string) error {
|
|
|
- if err := security.IsSecurityOptionsAllowed(); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
- if len(args) > 1 {
|
|
|
- return newOptionArgumentError("Invalid max_result_dimension arguments: %v", args)
|
|
|
- }
|
|
|
-
|
|
|
- if x, err := strconv.Atoi(args[0]); err == nil {
|
|
|
- po.SecurityOptions.MaxResultDimension = x
|
|
|
- } else {
|
|
|
- return newOptionArgumentError("Invalid max_result_dimension: %s", args[0])
|
|
|
- }
|
|
|
-
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
func (f *Factory) applyURLOption(po *ProcessingOptions, name string, args []string, usedPresets ...string) error {
|
|
|
switch name {
|
|
|
case "resize", "rs":
|
|
@@ -1087,7 +291,7 @@ func (f *Factory) applyURLOption(po *ProcessingOptions, name string, args []stri
|
|
|
return applyReturnAttachmentOption(po, args)
|
|
|
// Presets
|
|
|
case "preset", "pr":
|
|
|
- return f.applyPresetOption(po, args, usedPresets...)
|
|
|
+ return applyPresetOption(f, po, args, usedPresets...)
|
|
|
// Security
|
|
|
case "max_src_resolution", "msr":
|
|
|
return applyMaxSrcResolutionOption(po, args)
|
|
@@ -1163,7 +367,7 @@ func (f *Factory) defaultProcessingOptions(headers http.Header) (*ProcessingOpti
|
|
|
}
|
|
|
|
|
|
if _, ok := f.presets["default"]; ok {
|
|
|
- if err := f.applyPresetOption(po, []string{"default"}); err != nil {
|
|
|
+ if err := applyPresetOption(f, po, []string{"default"}); err != nil {
|
|
|
return po, err
|
|
|
}
|
|
|
}
|
|
@@ -1236,7 +440,7 @@ func (f *Factory) parsePathPresets(parts []string, headers http.Header) (*Proces
|
|
|
presets := strings.Split(parts[0], f.config.ArgumentsSeparator)
|
|
|
urlParts := parts[1:]
|
|
|
|
|
|
- if err = f.applyPresetOption(po, presets); err != nil {
|
|
|
+ if err = applyPresetOption(f, po, presets); err != nil {
|
|
|
return nil, "", err
|
|
|
}
|
|
|
|
|
@@ -1253,3 +457,11 @@ func (f *Factory) parsePathPresets(parts []string, headers http.Header) (*Proces
|
|
|
|
|
|
return po, url, nil
|
|
|
}
|
|
|
+
|
|
|
+func (po *ProcessingOptions) isSecurityOptionsAllowed() error {
|
|
|
+ if po.config.AllowSecurityOptions {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return newSecurityOptionsError()
|
|
|
+}
|