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

This commit is contained in:
DarthSim
2025-06-11 16:45:25 +03:00
parent 95932b522c
commit 3c4a75a709
5 changed files with 3 additions and 178 deletions

View File

@@ -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.

View File

@@ -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")

View File

@@ -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],

View File

@@ -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)
}
}
}

View File

@@ -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))
}