From 3c4a75a70959296de8e609d8772c7b68c8c76972 Mon Sep 17 00:00:00 2001 From: DarthSim Date: Wed, 11 Jun 2025 16:45:25 +0300 Subject: [PATCH] Remove the `IMGPROXY_SVG_FIX_UNSUPPORTED` config. The problem it was solving is now fixed in librsvg --- CHANGELOG.md | 3 + config/config.go | 3 - processing_handler.go | 15 ----- svg/svg.go | 133 ------------------------------------------ svg/svg_test.go | 27 --------- 5 files changed, 3 insertions(+), 178 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54fd9e34..394cc067 100644 --- a/CHANGELOG.md +++ b/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. diff --git a/config/config.go b/config/config.go index d3fa55e1..e1528388 100644 --- a/config/config.go +++ b/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") diff --git a/processing_handler.go b/processing_handler.go index 0522951b..94fc805d 100644 --- a/processing_handler.go +++ b/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], diff --git a/svg/svg.go b/svg/svg.go index cfc70261..103c5089 100644 --- a/svg/svg.go +++ b/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(` - - - - - - - - - -`) - 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) - } - } -} diff --git a/svg/svg_test.go b/svg/svg_test.go index 432da392..c141ef3f 100644 --- a/svg/svg_test.go +++ b/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)) }