Browse Source

Remove the `IMGPROXY_SVG_FIX_UNSUPPORTED` config. The problem it was solving is now fixed in librsvg

DarthSim 2 weeks ago
parent
commit
3c4a75a709
5 changed files with 3 additions and 178 deletions
  1. 3 0
      CHANGELOG.md
  2. 0 3
      config/config.go
  3. 0 15
      processing_handler.go
  4. 0 133
      svg/svg.go
  5. 0 27
      svg/svg_test.go

+ 3 - 0
CHANGELOG.md

@@ -27,6 +27,9 @@
 - (pro) Fix BlurHash generation when the `IMGPROXY_USE_LINEAR_COLORSPACE` config is set to `true`.
 - (pro) Fix detection of PDF files with a header offset.
 
+### Removed
+- Remove the `IMGPROXY_SVG_FIX_UNSUPPORTED` config. The problem it was solving is now fixed in librsvg.
+
 ## [3.28.0] - 2025-03-31
 ### Added
 - Add [IMGPROXY_BASE64_URL_INCLUDES_FILENAME](https://docs.imgproxy.net/latest/configuration/options#IMGPROXY_BASE64_URL_INCLUDES_FILENAME) config.

+ 0 - 3
config/config.go

@@ -65,7 +65,6 @@ var (
 	AutoRotate            bool
 	EnforceThumbnail      bool
 	ReturnAttachment      bool
-	SvgFixUnsupported     bool
 
 	AutoWebp          bool
 	EnforceWebp       bool
@@ -276,7 +275,6 @@ func Reset() {
 	AutoRotate = true
 	EnforceThumbnail = false
 	ReturnAttachment = false
-	SvgFixUnsupported = false
 
 	AutoWebp = false
 	EnforceWebp = false
@@ -508,7 +506,6 @@ func Configure() error {
 	configurators.Bool(&AutoRotate, "IMGPROXY_AUTO_ROTATE")
 	configurators.Bool(&EnforceThumbnail, "IMGPROXY_ENFORCE_THUMBNAIL")
 	configurators.Bool(&ReturnAttachment, "IMGPROXY_RETURN_ATTACHMENT")
-	configurators.Bool(&SvgFixUnsupported, "IMGPROXY_SVG_FIX_UNSUPPORTED")
 
 	if _, ok := os.LookupEnv("IMGPROXY_ENABLE_WEBP_DETECTION"); ok {
 		log.Warning("IMGPROXY_ENABLE_WEBP_DETECTION is deprecated, use IMGPROXY_AUTO_WEBP instead")

+ 0 - 15
processing_handler.go

@@ -446,21 +446,6 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
 		))
 	}
 
-	// We're going to rasterize SVG. Since librsvg lacks the support of some SVG
-	// features, we're going to replace them to minimize rendering error
-	if originData.Type == imagetype.SVG && config.SvgFixUnsupported {
-		fixed, changed, svgErr := svg.FixUnsupported(originData)
-		checkErr(ctx, "svg_processing", svgErr)
-
-		if changed {
-			// Since we'll replace origin data, it's better to close it to return
-			// it's buffer to the pool
-			originData.Close()
-
-			originData = fixed
-		}
-	}
-
 	resultData, err := func() (*imagedata.ImageData, error) {
 		defer metrics.StartProcessingSegment(ctx, metrics.Meta{
 			metrics.MetaProcessingOptions: metricsMeta[metrics.MetaProcessingOptions],

+ 0 - 133
svg/svg.go

@@ -2,31 +2,15 @@ package svg
 
 import (
 	"bytes"
-	"fmt"
 	"io"
 	"strings"
 
-	nanoid "github.com/matoous/go-nanoid/v2"
 	"github.com/tdewolff/parse/v2"
 	"github.com/tdewolff/parse/v2/xml"
 
 	"github.com/imgproxy/imgproxy/v3/imagedata"
 )
 
-var feDropShadowName = []byte("feDropShadow")
-
-var feDropShadowTemplate = strings.TrimSpace(`
-  <feMerge result="dsin-%[1]s"><feMergeNode %[3]s /></feMerge>
-  <feGaussianBlur %[4]s />
-  <feOffset %[5]s result="dsof-%[2]s" />
-  <feFlood %[6]s />
-  <feComposite in2="dsof-%[2]s" operator="in" />
-  <feMerge %[7]s>
-    <feMergeNode />
-    <feMergeNode in="dsin-%[1]s" />
-  </feMerge>
-`)
-
 func cloneHeaders(src map[string]string) map[string]string {
 	if src == nil {
 		return nil
@@ -111,120 +95,3 @@ func Sanitize(data *imagedata.ImageData) (*imagedata.ImageData, error) {
 		}
 	}
 }
-
-func replaceDropShadowNode(l *xml.Lexer, buf *bytes.Buffer) error {
-	var (
-		inAttrs     strings.Builder
-		blurAttrs   strings.Builder
-		offsetAttrs strings.Builder
-		floodAttrs  strings.Builder
-		finalAttrs  strings.Builder
-	)
-
-	inID, _ := nanoid.New(8)
-	offsetID, _ := nanoid.New(8)
-
-	hasStdDeviation := false
-	hasDx := false
-	hasDy := false
-
-TOKEN_LOOP:
-	for {
-		tt, tdata := l.Next()
-
-		switch tt {
-		case xml.ErrorToken:
-			if l.Err() != io.EOF {
-				return l.Err()
-			}
-			break TOKEN_LOOP
-		case xml.EndTagToken, xml.StartTagCloseVoidToken:
-			break TOKEN_LOOP
-		case xml.AttributeToken:
-			switch strings.ToLower(string(l.Text())) {
-			case "in":
-				inAttrs.Write(tdata)
-			case "stddeviation":
-				blurAttrs.Write(tdata)
-				hasStdDeviation = true
-			case "dx":
-				offsetAttrs.Write(tdata)
-				hasDx = true
-			case "dy":
-				offsetAttrs.Write(tdata)
-				hasDy = true
-			case "flood-color", "flood-opacity":
-				floodAttrs.Write(tdata)
-			default:
-				finalAttrs.Write(tdata)
-			}
-		}
-	}
-
-	if !hasStdDeviation {
-		blurAttrs.WriteString(` stdDeviation="2"`)
-	}
-
-	if !hasDx {
-		offsetAttrs.WriteString(` dx="2"`)
-	}
-
-	if !hasDy {
-		offsetAttrs.WriteString(` dy="2"`)
-	}
-
-	fmt.Fprintf(
-		buf, feDropShadowTemplate,
-		inID, offsetID,
-		inAttrs.String(),
-		blurAttrs.String(),
-		offsetAttrs.String(),
-		floodAttrs.String(),
-		finalAttrs.String(),
-	)
-
-	return nil
-}
-
-func FixUnsupported(data *imagedata.ImageData) (*imagedata.ImageData, bool, error) {
-	if !bytes.Contains(data.Data, feDropShadowName) {
-		return data, false, nil
-	}
-
-	r := bytes.NewReader(data.Data)
-	l := xml.NewLexer(parse.NewInput(r))
-
-	buf, cancel := imagedata.BorrowBuffer()
-
-	for {
-		tt, tdata := l.Next()
-
-		switch tt {
-		case xml.ErrorToken:
-			if l.Err() != io.EOF {
-				cancel()
-				return nil, false, l.Err()
-			}
-
-			newData := imagedata.ImageData{
-				Data:    buf.Bytes(),
-				Type:    data.Type,
-				Headers: cloneHeaders(data.Headers),
-			}
-			newData.SetCancel(cancel)
-
-			return &newData, true, nil
-		case xml.StartTagToken:
-			if bytes.Equal(l.Text(), feDropShadowName) {
-				if err := replaceDropShadowNode(l, buf); err != nil {
-					cancel()
-					return nil, false, err
-				}
-				continue
-			}
-			buf.Write(tdata)
-		default:
-			buf.Write(tdata)
-		}
-	}
-}

+ 0 - 27
svg/svg_test.go

@@ -3,7 +3,6 @@ package svg
 import (
 	"os"
 	"path/filepath"
-	"regexp"
 	"testing"
 
 	"github.com/stretchr/testify/suite"
@@ -52,32 +51,6 @@ func (s *SvgTestSuite) TestSanitize() {
 	s.Require().Equal(origin.Headers, actual.Headers)
 }
 
-func (s *SvgTestSuite) TestFixUnsupportedDropShadow() {
-	origin := s.readTestFile("test1.drop-shadow.svg")
-	expected := s.readTestFile("test1.drop-shadow.fixed.svg")
-
-	actual, changed, err := FixUnsupported(origin)
-
-	// `FixUnsupported` generates random IDs, we need to replace them for the test
-	re := regexp.MustCompile(`"ds(in|of)-.+?"`)
-	actualData := re.ReplaceAllString(string(actual.Data), `"ds$1-test"`)
-
-	s.Require().NoError(err)
-	s.Require().True(changed)
-	s.Require().Equal(string(expected.Data), actualData)
-	s.Require().Equal(origin.Headers, actual.Headers)
-}
-
-func (s *SvgTestSuite) TestFixUnsupportedNothingChanged() {
-	origin := s.readTestFile("test1.svg")
-
-	actual, changed, err := FixUnsupported(origin)
-
-	s.Require().NoError(err)
-	s.Require().False(changed)
-	s.Require().Equal(origin, actual)
-}
-
 func TestSvg(t *testing.T) {
 	suite.Run(t, new(SvgTestSuite))
 }