mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-09 19:52:30 +02:00
IMG-49: Get rid of global watermark image and fetcher (#1515)
* Get rid of global watermark image * imagedata.Factory, removed global Fetcher
This commit is contained in:
@@ -3,6 +3,7 @@ package processing
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/auximageprovider"
|
||||
"github.com/imgproxy/imgproxy/v3/imagedata"
|
||||
"github.com/imgproxy/imgproxy/v3/imagetype"
|
||||
"github.com/imgproxy/imgproxy/v3/options"
|
||||
@@ -15,6 +16,9 @@ type pipelineContext struct {
|
||||
|
||||
imgtype imagetype.Type
|
||||
|
||||
// The watermark image provider, if any watermarking is to be done.
|
||||
watermarkProvider auximageprovider.Provider
|
||||
|
||||
trimmed bool
|
||||
|
||||
srcWidth int
|
||||
@@ -67,7 +71,13 @@ type pipelineContext struct {
|
||||
type pipelineStep func(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata imagedata.ImageData) error
|
||||
type pipeline []pipelineStep
|
||||
|
||||
func (p pipeline) Run(ctx context.Context, img *vips.Image, po *options.ProcessingOptions, imgdata imagedata.ImageData) error {
|
||||
func (p pipeline) Run(
|
||||
ctx context.Context,
|
||||
img *vips.Image,
|
||||
po *options.ProcessingOptions,
|
||||
imgdata imagedata.ImageData,
|
||||
watermark auximageprovider.Provider,
|
||||
) error {
|
||||
pctx := pipelineContext{
|
||||
ctx: ctx,
|
||||
|
||||
@@ -77,7 +87,8 @@ func (p pipeline) Run(ctx context.Context, img *vips.Image, po *options.Processi
|
||||
dprScale: 1.0,
|
||||
vectorBaseScale: 1.0,
|
||||
|
||||
cropGravity: po.Crop.Gravity,
|
||||
cropGravity: po.Crop.Gravity,
|
||||
watermarkProvider: watermark,
|
||||
}
|
||||
|
||||
if pctx.cropGravity.Type == options.GravityUnknown {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/auximageprovider"
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/imagedata"
|
||||
"github.com/imgproxy/imgproxy/v3/imagetype"
|
||||
@@ -83,6 +84,8 @@ func ProcessImage(
|
||||
ctx context.Context,
|
||||
imgdata imagedata.ImageData,
|
||||
po *options.ProcessingOptions,
|
||||
watermarkProvider auximageprovider.Provider,
|
||||
idf *imagedata.Factory,
|
||||
) (*Result, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
@@ -136,12 +139,12 @@ func ProcessImage(
|
||||
}
|
||||
|
||||
// Transform the image (resize, crop, etc)
|
||||
if err = transformImage(ctx, img, po, imgdata, animated); err != nil {
|
||||
if err = transformImage(ctx, img, po, imgdata, animated, watermarkProvider); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Finalize the image (colorspace conversion, metadata stripping, etc)
|
||||
if err = finalizePipeline.Run(ctx, img, po, imgdata); err != nil {
|
||||
if err = finalizePipeline.Run(ctx, img, po, imgdata, watermarkProvider); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -385,18 +388,20 @@ func transformImage(
|
||||
po *options.ProcessingOptions,
|
||||
imgdata imagedata.ImageData,
|
||||
asAnimated bool,
|
||||
watermark auximageprovider.Provider,
|
||||
) error {
|
||||
if asAnimated {
|
||||
return transformAnimated(ctx, img, po)
|
||||
return transformAnimated(ctx, img, po, watermark)
|
||||
}
|
||||
|
||||
return mainPipeline.Run(ctx, img, po, imgdata)
|
||||
return mainPipeline.Run(ctx, img, po, imgdata, watermark)
|
||||
}
|
||||
|
||||
func transformAnimated(
|
||||
ctx context.Context,
|
||||
img *vips.Image,
|
||||
po *options.ProcessingOptions,
|
||||
watermark auximageprovider.Provider,
|
||||
) error {
|
||||
if po.Trim.Enabled {
|
||||
log.Warning("Trim is not supported for animated images")
|
||||
@@ -450,7 +455,8 @@ func transformAnimated(
|
||||
|
||||
// Transform the frame using the main pipeline.
|
||||
// We don't provide imgdata here to prevent scale-on-load.
|
||||
if err = mainPipeline.Run(ctx, frame, po, nil); err != nil {
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -474,7 +480,7 @@ func transformAnimated(
|
||||
|
||||
// Apply watermark to all frames at once if it was requested.
|
||||
// This is much more efficient than applying watermark to individual frames.
|
||||
if watermarkEnabled && imagedata.Watermark != nil {
|
||||
if watermarkEnabled && watermark != nil {
|
||||
// Get DPR scale to apply watermark correctly on HiDPI images.
|
||||
// `imgproxy-dpr-scale` is set by the pipeline.
|
||||
dprScale, derr := img.GetDoubleDefault("imgproxy-dpr-scale", 1.0)
|
||||
@@ -483,7 +489,7 @@ func transformAnimated(
|
||||
}
|
||||
|
||||
if err = applyWatermark(
|
||||
img, imagedata.Watermark, &po.Watermark, dprScale, framesCount,
|
||||
img, watermark, &po.Watermark, dprScale, framesCount,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -12,14 +12,17 @@ import (
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/imgproxy/imgproxy/v3/config"
|
||||
"github.com/imgproxy/imgproxy/v3/fetcher"
|
||||
"github.com/imgproxy/imgproxy/v3/ierrors"
|
||||
"github.com/imgproxy/imgproxy/v3/imagedata"
|
||||
"github.com/imgproxy/imgproxy/v3/options"
|
||||
"github.com/imgproxy/imgproxy/v3/transport"
|
||||
"github.com/imgproxy/imgproxy/v3/vips"
|
||||
)
|
||||
|
||||
type ProcessingTestSuite struct {
|
||||
suite.Suite
|
||||
idf *imagedata.Factory
|
||||
}
|
||||
|
||||
func (s *ProcessingTestSuite) SetupSuite() {
|
||||
@@ -30,10 +33,19 @@ func (s *ProcessingTestSuite) SetupSuite() {
|
||||
config.MaxAnimationFrames = 100
|
||||
config.MaxAnimationFrameResolution = 10 * 1024 * 1024
|
||||
|
||||
s.Require().NoError(imagedata.Init())
|
||||
s.Require().NoError(vips.Init())
|
||||
|
||||
logrus.SetOutput(io.Discard)
|
||||
|
||||
trc := transport.NewDefaultConfig()
|
||||
tr, err := transport.New(trc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
fc := fetcher.NewDefaultConfig()
|
||||
f, err := fetcher.New(tr, fc)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.idf = imagedata.NewFactory(f)
|
||||
}
|
||||
|
||||
func (s *ProcessingTestSuite) openFile(name string) imagedata.ImageData {
|
||||
@@ -41,7 +53,7 @@ func (s *ProcessingTestSuite) openFile(name string) imagedata.ImageData {
|
||||
s.Require().NoError(err)
|
||||
path := filepath.Join(wd, "..", "testdata", name)
|
||||
|
||||
imagedata, err := imagedata.NewFromPath(path)
|
||||
imagedata, err := s.idf.NewFromPath(path)
|
||||
s.Require().NoError(err)
|
||||
|
||||
return imagedata
|
||||
@@ -82,7 +94,7 @@ func (s *ProcessingTestSuite) TestResizeToFit() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -121,7 +133,7 @@ func (s *ProcessingTestSuite) TestResizeToFitEnlarge() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -165,7 +177,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtend() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -209,7 +221,7 @@ func (s *ProcessingTestSuite) TestResizeToFitExtendAR() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -247,7 +259,7 @@ func (s *ProcessingTestSuite) TestResizeToFill() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -286,7 +298,7 @@ func (s *ProcessingTestSuite) TestResizeToFillEnlarge() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -332,7 +344,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtend() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -378,7 +390,7 @@ func (s *ProcessingTestSuite) TestResizeToFillExtendAR() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -416,7 +428,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDown() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -455,7 +467,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownEnlarge() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -501,7 +513,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtend() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -545,7 +557,7 @@ func (s *ProcessingTestSuite) TestResizeToFillDownExtendAR() {
|
||||
po.Width = tc.width
|
||||
po.Height = tc.height
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
|
||||
@@ -974,7 +986,7 @@ func (s *ProcessingTestSuite) TestResultSizeLimit() {
|
||||
po.Rotate = tc.rotate
|
||||
po.Padding = tc.padding
|
||||
|
||||
result, err := ProcessImage(context.Background(), imgdata, po)
|
||||
result, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
|
||||
s.Require().NoError(err)
|
||||
s.Require().NotNil(result)
|
||||
@@ -989,7 +1001,7 @@ func (s *ProcessingTestSuite) TestImageResolutionTooLarge() {
|
||||
po.SecurityOptions.MaxSrcResolution = 1
|
||||
|
||||
imgdata := s.openFile("test2.jpg")
|
||||
_, err := ProcessImage(context.Background(), imgdata, po)
|
||||
_, err := ProcessImage(context.Background(), imgdata, po, nil, s.idf)
|
||||
|
||||
s.Require().Error(err)
|
||||
s.Require().Equal(422, ierrors.Wrap(err, 0).StatusCode())
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"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"
|
||||
@@ -59,17 +60,14 @@ func prepareWatermark(wm *vips.Image, wmData imagedata.ImageData, opts *options.
|
||||
po.Padding.Bottom = offY - po.Padding.Top
|
||||
}
|
||||
|
||||
if err := watermarkPipeline.Run(context.Background(), wm, po, wmData); err != nil {
|
||||
if err := watermarkPipeline.Run(context.Background(), wm, po, wmData, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.ShouldReplicate() || framesCount > 1 {
|
||||
// We need to copy image if we're going to replicate.
|
||||
// Replication requires image to be read several times, and this requires
|
||||
// random access to pixels
|
||||
if err := wm.CopyMemory(); err != nil {
|
||||
return err
|
||||
}
|
||||
// We need to copy the image to ensure that it is in memory since we will
|
||||
// close it after watermark processing is done.
|
||||
if err := wm.CopyMemory(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if opts.ShouldReplicate() {
|
||||
@@ -82,7 +80,20 @@ func prepareWatermark(wm *vips.Image, wmData imagedata.ImageData, opts *options.
|
||||
return wm.StripAll()
|
||||
}
|
||||
|
||||
func applyWatermark(img *vips.Image, wmData imagedata.ImageData, opts *options.WatermarkOptions, offsetScale float64, framesCount int) error {
|
||||
func applyWatermark(img *vips.Image, watermark auximageprovider.Provider, opts *options.WatermarkOptions, offsetScale float64, framesCount int) error {
|
||||
if watermark == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
wmData, _, err := watermark.Get(context.Background(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if wmData == nil {
|
||||
return nil
|
||||
}
|
||||
defer wmData.Close()
|
||||
|
||||
wm := new(vips.Image)
|
||||
defer wm.Clear()
|
||||
|
||||
@@ -164,9 +175,9 @@ func applyWatermark(img *vips.Image, wmData imagedata.ImageData, opts *options.W
|
||||
}
|
||||
|
||||
func watermark(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata imagedata.ImageData) error {
|
||||
if !po.Watermark.Enabled || imagedata.Watermark == nil {
|
||||
if !po.Watermark.Enabled || pctx.watermarkProvider == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return applyWatermark(img, imagedata.Watermark, &po.Watermark, pctx.dprScale, 1)
|
||||
return applyWatermark(img, pctx.watermarkProvider, &po.Watermark, pctx.dprScale, 1)
|
||||
}
|
||||
|
Reference in New Issue
Block a user