Viktor Sokolov пре 2 недеља
родитељ
комит
0269bf765a

+ 6 - 1
handlers/processing/request_methods.go

@@ -156,8 +156,13 @@ func (r *request) getFallbackImage(
 
 // processImage calls actual image processing
 func (r *request) processImage(ctx context.Context, originData imagedata.ImageData) (*processing.Result, error) {
+	config, err := processing.LoadConfigFromEnv(nil)
+	if err != nil {
+		return nil, ierrors.Wrap(err, 0, ierrors.WithCategory(handlers.CategoryConfig))
+	}
+
 	defer monitoring.StartProcessingSegment(ctx, r.monitoringMeta.Filter(monitoring.MetaProcessingOptions))()
-	return processing.ProcessImage(ctx, originData, r.po, r.WatermarkImage())
+	return processing.ProcessImage(ctx, originData, r.po, r.WatermarkImage(), config)
 }
 
 // writeDebugHeaders writes debug headers (X-Origin-*, X-Result-*) to the response

+ 61 - 0
processing/config.go

@@ -0,0 +1,61 @@
+package processing
+
+import (
+	"errors"
+
+	"github.com/imgproxy/imgproxy/v3/config"
+	"github.com/imgproxy/imgproxy/v3/ensure"
+	"github.com/imgproxy/imgproxy/v3/imagetype"
+	"github.com/imgproxy/imgproxy/v3/vips"
+	log "github.com/sirupsen/logrus"
+)
+
+// Config holds processing-related configuration.
+type Config struct {
+	PreferredFormats    []imagetype.Type
+	WatermarkOpacity    float64
+	DisableShrinkOnLoad bool
+}
+
+// NewConfig creates a new Config instance with the given parameters.
+func NewDefaultConfig() Config {
+	return Config{
+		WatermarkOpacity: 1,
+	}
+}
+
+// NewConfig creates a new Config instance with the given parameters.
+func LoadConfigFromEnv(c *Config) (*Config, error) {
+	c = ensure.Ensure(c, NewDefaultConfig)
+
+	c.PreferredFormats = config.PreferredFormats
+
+	return c, nil
+}
+
+// Validate checks if the configuration is valid
+func (c *Config) Validate() error {
+	filtered := c.PreferredFormats[:0]
+
+	for _, t := range c.PreferredFormats {
+		if !vips.SupportsSave(t) {
+			log.Warnf("%s can't be a preferred format as it's saving is not supported", t)
+		} else {
+			filtered = append(filtered, t)
+		}
+	}
+
+	if len(filtered) == 0 {
+		return errors.New("no supported preferred formats specified")
+	}
+
+	c.PreferredFormats = filtered
+
+	if c.WatermarkOpacity <= 0 {
+		return errors.New("watermark opacity should be greater than 0")
+	} else if c.WatermarkOpacity > 1 {
+		return errors.New("watermark opacity should be less than or equal to 1")
+	}
+
+	return nil
+}

+ 5 - 1
processing/pipeline.go

@@ -14,6 +14,8 @@ import (
 type pipelineContext struct {
 	ctx context.Context
 
+	config *Config
+
 	imgtype imagetype.Type
 
 	// The watermark image provider, if any watermarking is to be done.
@@ -77,9 +79,11 @@ func (p pipeline) Run(
 	po *options.ProcessingOptions,
 	imgdata imagedata.ImageData,
 	watermark auximageprovider.Provider,
+	config *Config,
 ) error {
 	pctx := pipelineContext{
-		ctx: ctx,
+		ctx:    ctx,
+		config: config,
 
 		wscale: 1.0,
 		hscale: 1.0,

+ 10 - 6
processing/processing.go

@@ -47,6 +47,7 @@ var finalizePipeline = pipeline{
 	stripMetadata,
 }
 
+// NOTE: this should go to Config (already redefined there)
 func ValidatePreferredFormats() error {
 	filtered := config.PreferredFormats[:0]
 
@@ -85,6 +86,7 @@ func ProcessImage(
 	imgdata imagedata.ImageData,
 	po *options.ProcessingOptions,
 	watermarkProvider auximageprovider.Provider,
+	config *Config,
 ) (*Result, error) {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -138,12 +140,12 @@ func ProcessImage(
 	}
 
 	// Transform the image (resize, crop, etc)
-	if err = transformImage(ctx, img, po, imgdata, animated, watermarkProvider); err != nil {
+	if err = transformImage(ctx, img, po, imgdata, animated, watermarkProvider, config); err != nil {
 		return nil, err
 	}
 
 	// Finalize the image (colorspace conversion, metadata stripping, etc)
-	if err = finalizePipeline.Run(ctx, img, po, imgdata, watermarkProvider); err != nil {
+	if err = finalizePipeline.Run(ctx, img, po, imgdata, watermarkProvider, config); err != nil {
 		return nil, err
 	}
 
@@ -388,12 +390,13 @@ func transformImage(
 	imgdata imagedata.ImageData,
 	asAnimated bool,
 	watermark auximageprovider.Provider,
+	config *Config,
 ) error {
 	if asAnimated {
-		return transformAnimated(ctx, img, po, watermark)
+		return transformAnimated(ctx, img, po, watermark, config)
 	}
 
-	return mainPipeline.Run(ctx, img, po, imgdata, watermark)
+	return mainPipeline.Run(ctx, img, po, imgdata, watermark, config)
 }
 
 func transformAnimated(
@@ -401,6 +404,7 @@ func transformAnimated(
 	img *vips.Image,
 	po *options.ProcessingOptions,
 	watermark auximageprovider.Provider,
+	config *Config,
 ) error {
 	if po.Trim.Enabled {
 		log.Warning("Trim is not supported for animated images")
@@ -455,7 +459,7 @@ func transformAnimated(
 		// Transform the frame using the main pipeline.
 		// We don't provide imgdata here to prevent scale-on-load.
 		// Let's skip passing watermark here since in would be applied later to all frames at once.
-		if err = mainPipeline.Run(ctx, frame, po, nil, nil); err != nil {
+		if err = mainPipeline.Run(ctx, frame, po, nil, nil, config); err != nil {
 			return err
 		}
 
@@ -487,7 +491,7 @@ func transformAnimated(
 			dprScale = 1.0
 		}
 
-		if err = applyWatermark(ctx, img, watermark, po, dprScale, framesCount); err != nil {
+		if err = applyWatermark(ctx, img, watermark, po, dprScale, framesCount, config); err != nil {
 			return err
 		}
 	}

+ 26 - 17
processing/processing_test.go

@@ -17,13 +17,15 @@ import (
 	"github.com/imgproxy/imgproxy/v3/imagedata"
 	"github.com/imgproxy/imgproxy/v3/options"
 	"github.com/imgproxy/imgproxy/v3/security"
+	"github.com/imgproxy/imgproxy/v3/testutil"
 	"github.com/imgproxy/imgproxy/v3/vips"
 )
 
 type ProcessingTestSuite struct {
-	suite.Suite
-	idf *imagedata.Factory
-	pof *options.Factory
+	testutil.LazySuite
+	idf              *imagedata.Factory
+	pof              *options.Factory
+	processingConfig testutil.LazyObj[*Config]
 }
 
 func (s *ProcessingTestSuite) SetupSuite() {
@@ -55,6 +57,13 @@ func (s *ProcessingTestSuite) SetupSuite() {
 
 	s.pof, err = options.NewFactory(cfg, security)
 	s.Require().NoError(err)
+
+	s.processingConfig, _ = testutil.NewLazySuiteObj(
+		s,
+		func() (*Config, error) {
+			return LoadConfigFromEnv(nil)
+		},
+	)
 }
 
 func (s *ProcessingTestSuite) openFile(name string) imagedata.ImageData {
@@ -103,7 +112,7 @@ func (s *ProcessingTestSuite) TestResizeToFit() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -142,7 +151,7 @@ func (s *ProcessingTestSuite) TestResizeToFitEnlarge() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -186,7 +195,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtend() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -230,7 +239,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtendAR() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -268,7 +277,7 @@ func (s *ProcessingTestSuite) TestResizeToFill() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -307,7 +316,7 @@ func (s *ProcessingTestSuite) TestResizeToFillEnlarge() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -353,7 +362,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtend() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -399,7 +408,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtendAR() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -437,7 +446,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDown() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -476,7 +485,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownEnlarge() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -522,7 +531,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtend() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -566,7 +575,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtendAR() {
 			po.Width = tc.width
 			po.Height = tc.height
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
 
@@ -995,7 +1004,7 @@ func (s *ProcessingTestSuite) TestResultSizeLimit() {
 			po.Rotate = tc.rotate
 			po.Padding = tc.padding
 
-			result, err := ProcessImage(context.Background(), imgdata, po, nil)
+			result, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 
 			s.Require().NoError(err)
 			s.Require().NotNil(result)
@@ -1010,7 +1019,7 @@ func (s *ProcessingTestSuite) TestImageResolutionTooLarge() {
 	po.SecurityOptions.MaxSrcResolution = 1
 
 	imgdata := s.openFile("test2.jpg")
-	_, err := ProcessImage(context.Background(), imgdata, po, nil)
+	_, err := ProcessImage(context.Background(), imgdata, po, nil, s.processingConfig())
 
 	s.Require().Error(err)
 	s.Require().Equal(422, ierrors.Wrap(err, 0).StatusCode())

+ 1 - 2
processing/scale_on_load.go

@@ -5,7 +5,6 @@ import (
 
 	log "github.com/sirupsen/logrus"
 
-	"github.com/imgproxy/imgproxy/v3/config"
 	"github.com/imgproxy/imgproxy/v3/imagedata"
 	"github.com/imgproxy/imgproxy/v3/imagetype"
 	"github.com/imgproxy/imgproxy/v3/imath"
@@ -22,7 +21,7 @@ func canScaleOnLoad(pctx *pipelineContext, imgdata imagedata.ImageData, scale fl
 		return true
 	}
 
-	if config.DisableShrinkOnLoad || scale >= 1 {
+	if pctx.config.DisableShrinkOnLoad || scale >= 1 {
 		return false
 	}
 

+ 5 - 5
processing/watermark.go

@@ -5,7 +5,6 @@ import (
 	"math"
 
 	"github.com/imgproxy/imgproxy/v3/auximageprovider"
-	"github.com/imgproxy/imgproxy/v3/config"
 	"github.com/imgproxy/imgproxy/v3/imagedata"
 	"github.com/imgproxy/imgproxy/v3/imath"
 	"github.com/imgproxy/imgproxy/v3/options"
@@ -22,7 +21,7 @@ var watermarkPipeline = pipeline{
 	padding,
 }
 
-func prepareWatermark(wm *vips.Image, wmData imagedata.ImageData, po *options.ProcessingOptions, imgWidth, imgHeight int, offsetScale float64, framesCount int) error {
+func prepareWatermark(wm *vips.Image, wmData imagedata.ImageData, po *options.ProcessingOptions, config *Config, imgWidth, imgHeight int, offsetScale float64, framesCount int) error {
 	if err := wm.Load(wmData, 1, 1.0, 1); err != nil {
 		return err
 	}
@@ -62,7 +61,7 @@ func prepareWatermark(wm *vips.Image, wmData imagedata.ImageData, po *options.Pr
 		wmPo.Padding.Bottom = offY - wmPo.Padding.Top
 	}
 
-	if err := watermarkPipeline.Run(context.Background(), wm, wmPo, wmData, nil); err != nil {
+	if err := watermarkPipeline.Run(context.Background(), wm, wmPo, wmData, nil, config); err != nil {
 		return err
 	}
 
@@ -89,6 +88,7 @@ func applyWatermark(
 	po *options.ProcessingOptions,
 	offsetScale float64,
 	framesCount int,
+	config *Config,
 ) error {
 	if watermark == nil {
 		return nil
@@ -112,7 +112,7 @@ func applyWatermark(
 	height := img.Height()
 	frameHeight := height / framesCount
 
-	if err := prepareWatermark(wm, wmData, po, width, frameHeight, offsetScale, framesCount); err != nil {
+	if err := prepareWatermark(wm, wmData, po, config, width, frameHeight, offsetScale, framesCount); err != nil {
 		return err
 	}
 
@@ -195,5 +195,5 @@ func watermark(
 		return nil
 	}
 
-	return applyWatermark(pctx.ctx, img, pctx.watermarkProvider, po, pctx.dprScale, 1)
+	return applyWatermark(pctx.ctx, img, pctx.watermarkProvider, po, pctx.dprScale, 1, pctx.config)
 }