Skip to content
Permalink
Browse files

Better SVG detection

  • Loading branch information
DarthSim committed Feb 11, 2020
1 parent fd2c020 commit af8366139f474fad08b56d6c7c1187f074dcefe2
Showing with 63 additions and 9 deletions.
  1. +4 −0 CHANGELOG.md
  2. +3 −0 config.go
  3. +4 −0 docs/configuration.md
  4. +4 −0 docs/image_formats_support.md
  5. +2 −0 download.go
  6. +6 −0 imagemeta/image_meta.go
  7. +40 −9 imagemeta/svg.go
@@ -7,6 +7,10 @@
- `imgproxy health` command.
- (pro) `IMGPROXY_GIF_OPTIMIZE_FRAMES` & `IMGPROXY_GIF_OPTIMIZE_TRANSPARENCY` configs and `gif_options` processing option.

### Changed

- Better SVG detection.

### Fixed
- Fix detection of SVG starting with a comment.

@@ -163,6 +163,7 @@ type config struct {
MaxSrcResolution int
MaxSrcFileSize int
MaxAnimationFrames int
MaxSvgCheckBytes int

JpegProgressive bool
PngInterlaced bool
@@ -245,6 +246,7 @@ var conf = config{
TTL: 3600,
MaxSrcResolution: 16800000,
MaxAnimationFrames: 1,
MaxSvgCheckBytes: 32 * 1024,
SignatureSize: 32,
PngQuantizationColors: 256,
Quality: 80,
@@ -294,6 +296,7 @@ func configure() {
intEnvConfig(&conf.MaxSrcDimension, "IMGPROXY_MAX_SRC_DIMENSION")
megaIntEnvConfig(&conf.MaxSrcResolution, "IMGPROXY_MAX_SRC_RESOLUTION")
intEnvConfig(&conf.MaxSrcFileSize, "IMGPROXY_MAX_SRC_FILE_SIZE")
intEnvConfig(&conf.MaxSvgCheckBytes, "IMGPROXY_MAX_SVG_CHECK_BYTES")

if _, ok := os.LookupEnv("IMGPROXY_MAX_GIF_FRAMES"); ok {
logWarning("`IMGPROXY_MAX_GIF_FRAMES` is deprecated and will be removed in future versions. Use `IMGPROXY_MAX_ANIMATION_FRAMES` instead")
@@ -53,6 +53,10 @@ imgproxy can process animated images (GIF, WebP), but since this operation is pr

**Note:** imgproxy summarizes all frames resolutions while checking source image resolution.

imgproxy reads some amount of bytes to check if the source image is SVG. By default it reads maximum of 32KB, but you can change this:

* `IMGPROXY_MAX_SVG_CHECK_BYTES`: the maximum number of bytes imgproxy will read to recognize SVG. If imgproxy can't recognize your SVG, try to increase this number. Default: `32768` (32KB)

You can also specify a secret to enable authorization with the HTTP `Authorization` header for use in production environments:

* `IMGPROXY_SECRET`: the authorization token. If specified, the HTTP request should contain the `Authorization: Bearer %secret%` header;
@@ -27,6 +27,10 @@ imgproxy supports SVG sources without limitations, but SVG results are not suppo

When the source image is SVG and the SVG result is requested, imgproxy returns source image without modifications.

imgproxy reads some amount of bytes to check if the source image is SVG. By default it reads maximum of 32KB, but you can change this:

* `IMGPROXY_MAX_SVG_CHECK_BYTES`: the maximum number of bytes imgproxy will read to recognize SVG. If imgproxy can't recognize your SVG, try to increase this number. Default: `32768` (32KB)

## HEIC support

imgproxy supports HEIC only when using libvips 8.8.0+. Official imgproxy Docker image supports HEIC out of the box.
@@ -90,6 +90,8 @@ func initDownloading() {
}

downloadBufPool = newBufPool("download", conf.Concurrency, conf.DownloadBufferSize)

imagemeta.SetMaxSvgCheckRead(conf.MaxSvgCheckBytes)
}

func checkDimensions(width, height int) error {
@@ -88,5 +88,11 @@ func DecodeMeta(r io.Reader) (Meta, error) {
}
}

if ok, err := IsSVG(rr); err != nil {
return nil, err
} else if ok {
return &meta{format: "svg", width: 1, height: 1}, nil
}

return nil, ErrFormat
}
@@ -1,17 +1,48 @@
package imagemeta

import (
"encoding/xml"
"io"
"sync/atomic"
)

func init() {
// Register fake svg decoder. Since we need this only for type detecting, we can
// return fake image sizes
decodeMeta := func(io.Reader) (Meta, error) {
return &meta{format: "svg", width: 1, height: 1}, nil
var maxSvgBytes int64 = 32 * 1024

type svgHeader struct {
XMLName xml.Name
}

func SetMaxSvgCheckRead(n int) {
atomic.StoreInt64(&maxSvgBytes, int64(n))
}

func IsSVG(r io.Reader) (bool, error) {
maxBytes := int(atomic.LoadInt64(&maxSvgBytes))

var h svgHeader

buf := make([]byte, 0, maxBytes)
b := make([]byte, 1024)

for {
n, err := r.Read(b)
if err != nil && err != io.EOF {
return false, err
}
if n <= 0 {
return false, nil
}

buf = append(buf, b[:n]...)

if xml.Unmarshal(buf, &h); h.XMLName.Local == "svg" {
return true, nil
}

if len(buf) >= maxBytes {
break
}
}
RegisterFormat("<?xml ", decodeMeta)
RegisterFormat("<svg", decodeMeta)
// We believe that file starting with HTML comment is SVG
RegisterFormat("<!--", decodeMeta)

return false, nil
}

0 comments on commit af83661

Please sign in to comment.
You can’t perform that action at this time.