فهرست منبع

Joined imagedetect and imagetype

Viktor Sokolov 1 ماه پیش
والد
کامیت
4a47b6f5ef
6فایلهای تغییر یافته به همراه0 افزوده شده و 285 حذف شده
  1. 0 89
      imagedetect/detect.go
  2. 0 41
      imagedetect/detect_test.go
  3. 0 23
      imagedetect/errors.go
  4. 0 50
      imagedetect/registry.go
  5. 0 47
      imagedetect/registry_test.go
  6. 0 35
      imagedetect/svg.go

+ 0 - 89
imagedetect/detect.go

@@ -1,89 +0,0 @@
-package imagedetect
-
-import (
-	"io"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-	"github.com/imgproxy/imgproxy/v3/imagetype_new"
-)
-
-const (
-	// maxDetectionLimit is maximum bytes detectors allowed to read from the source
-	maxDetectionLimit = 32768
-)
-
-// Detect attempts to detect the image type from a reader.
-// It first tries magic byte detection, then custom detectors in registration order
-func Detect(r io.Reader) (imagetype_new.Type, error) {
-	br := bufreader.New(io.LimitReader(r, maxDetectionLimit))
-
-	for _, fn := range registry.detectors {
-		br.Rewind()
-		if typ, err := fn(br); err == nil && typ != imagetype_new.Unknown {
-			return typ, nil
-		}
-	}
-
-	return imagetype_new.Unknown, newUnknownFormatError()
-}
-
-// hasMagicBytes checks if the data matches a magic byte signature
-// Supports '?' characters in signature which match any byte
-func hasMagicBytes(data []byte, magic []byte) bool {
-	if len(data) < len(magic) {
-		return false
-	}
-
-	for i, c := range magic {
-		if c != data[i] && c != '?' {
-			return false
-		}
-	}
-	return true
-}
-
-// init registers default magic bytes for common image formats
-func init() {
-	// JPEG magic bytes
-	RegisterMagicBytes([]byte("\xff\xd8"), imagetype_new.JPEG)
-
-	// JXL magic bytes
-	//
-	// NOTE: for "naked" jxl (0xff 0x0a) there is no way to ensure this is a JXL file, except to fully
-	// decode it. The data starts right after it, no additional marker bytes are provided.
-	// We stuck with the potential false positives here.
-	RegisterMagicBytes([]byte{0xff, 0x0a}, imagetype_new.JXL)                                                             // JXL codestream (can't use string due to 0x0a)
-	RegisterMagicBytes([]byte{0x00, 0x00, 0x00, 0x0C, 0x4A, 0x58, 0x4C, 0x20, 0x0D, 0x0A, 0x87, 0x0A}, imagetype_new.JXL) // JXL container (has null bytes)
-
-	// PNG magic bytes
-	RegisterMagicBytes([]byte("\x89PNG\r\n\x1a\n"), imagetype_new.PNG)
-
-	// WEBP magic bytes (RIFF container with WEBP fourcc) - using wildcard for size
-	RegisterMagicBytes([]byte("RIFF????WEBP"), imagetype_new.WEBP)
-
-	// GIF magic bytes
-	RegisterMagicBytes([]byte("GIF8?a"), imagetype_new.GIF)
-
-	// ICO magic bytes
-	RegisterMagicBytes([]byte{0, 0, 1, 0}, imagetype_new.ICO) // ICO (has null bytes)
-
-	// HEIC/HEIF magic bytes with wildcards for size
-	RegisterMagicBytes([]byte("????ftypheic"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftypheix"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftyphevc"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftypheim"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftypheis"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftyphevm"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftyphevs"), imagetype_new.HEIC)
-	RegisterMagicBytes([]byte("????ftypmif1"), imagetype_new.HEIC)
-
-	// AVIF magic bytes
-	RegisterMagicBytes([]byte("????ftypavif"), imagetype_new.AVIF)
-
-	// BMP magic bytes
-	RegisterMagicBytes([]byte("BM"), imagetype_new.BMP)
-
-	// TIFF magic bytes (little-endian and big-endian)
-	RegisterMagicBytes([]byte("II*\x00"), imagetype_new.TIFF) // Little-endian
-	RegisterMagicBytes([]byte("MM\x00*"), imagetype_new.TIFF) // Big-endian
-}

+ 0 - 41
imagedetect/detect_test.go

@@ -1,41 +0,0 @@
-package imagedetect
-
-import (
-	"os"
-	"testing"
-
-	"github.com/imgproxy/imgproxy/v3/imagetype_new"
-	"github.com/stretchr/testify/require"
-)
-
-func TestDetect(t *testing.T) {
-	tests := []struct {
-		name string
-		file string
-		want imagetype_new.Type
-	}{
-		{"JPEG", "../testdata/test-images/jpg/jpg.jpg", imagetype_new.JPEG},
-		{"JXL", "../testdata/test-images/jxl/jxl.jxl", imagetype_new.JXL},
-		{"PNG", "../testdata/test-images/png/png.png", imagetype_new.PNG},
-		{"WEBP", "../testdata/test-images/webp/webp.webp", imagetype_new.WEBP},
-		{"GIF", "../testdata/test-images/gif/gif.gif", imagetype_new.GIF},
-		{"ICO", "../testdata/test-images/ico/png-256x256.ico", imagetype_new.ICO},
-		{"SVG", "../testdata/test-images/svg/svg.svg", imagetype_new.SVG},
-		{"HEIC", "../testdata/test-images/heif/heif.heif", imagetype_new.HEIC},
-		{"BMP", "../testdata/test-images/bmp/24-bpp.bmp", imagetype_new.BMP},
-		{"TIFF", "../testdata/test-images/tiff/tiff.tiff", imagetype_new.TIFF},
-		{"SVG", "../testdata/test-images/svg/svg.svg", imagetype_new.SVG},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			f, err := os.Open(tt.file)
-			require.NoError(t, err)
-			defer f.Close()
-
-			got, err := Detect(f)
-			require.NoError(t, err)
-			require.Equal(t, tt.want, got)
-		})
-	}
-}

+ 0 - 23
imagedetect/errors.go

@@ -1,23 +0,0 @@
-package imagedetect
-
-import (
-	"net/http"
-
-	"github.com/imgproxy/imgproxy/v3/ierrors"
-)
-
-type (
-	UnknownFormatError struct{}
-)
-
-func newUnknownFormatError() error {
-	return ierrors.Wrap(
-		UnknownFormatError{},
-		1,
-		ierrors.WithStatusCode(http.StatusUnprocessableEntity),
-		ierrors.WithPublicMessage("Invalid source image"),
-		ierrors.WithShouldReport(false),
-	)
-}
-
-func (e UnknownFormatError) Error() string { return "Source image type not supported" }

+ 0 - 50
imagedetect/registry.go

@@ -1,50 +0,0 @@
-package imagedetect
-
-import (
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-	"github.com/imgproxy/imgproxy/v3/imagetype_new"
-)
-
-// DetectFunc is a function that detects the image type from byte data
-type DetectFunc func(r bufreader.ReadPeeker) (imagetype_new.Type, error)
-
-// Registry manages the registration and execution of image type detectors
-type Registry struct {
-	detectors []DetectFunc
-}
-
-// Global registry instance
-var registry = &Registry{}
-
-// RegisterDetector registers a custom detector function
-// Detectors are tried in the order they were registered
-func RegisterDetector(detector DetectFunc, bytesNeeded int) {
-	registry.RegisterDetector(detector, bytesNeeded)
-}
-
-// RegisterMagicBytes registers magic bytes for a specific image type
-// Magic byte detectors are always tried before custom detectors
-func RegisterMagicBytes(signature []byte, typ imagetype_new.Type) {
-	registry.RegisterMagicBytes(signature, typ)
-}
-
-// RegisterDetector registers a custom detector function on this registry instance
-func (r *Registry) RegisterDetector(detector DetectFunc, bytesNeeded int) {
-	r.detectors = append(r.detectors, detector)
-}
-
-// RegisterMagicBytes registers magic bytes for a specific image type on this registry instance
-func (r *Registry) RegisterMagicBytes(signature []byte, typ imagetype_new.Type) {
-	r.detectors = append(r.detectors, func(r bufreader.ReadPeeker) (imagetype_new.Type, error) {
-		b, err := r.Peek(len(signature))
-		if err != nil {
-			return imagetype_new.Unknown, err
-		}
-
-		if hasMagicBytes(b, signature) {
-			return typ, nil
-		}
-
-		return imagetype_new.Unknown, nil
-	})
-}

+ 0 - 47
imagedetect/registry_test.go

@@ -1,47 +0,0 @@
-package imagedetect
-
-import (
-	"testing"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-	"github.com/imgproxy/imgproxy/v3/imagetype_new"
-	"github.com/stretchr/testify/require"
-)
-
-func TestRegisterDetector(t *testing.T) {
-	// Create a test registry to avoid interfering with global state
-	testRegistry := &Registry{}
-
-	// Create a test detector function
-	testDetector := func(r bufreader.ReadPeeker) (imagetype_new.Type, error) {
-		b, err := r.Peek(2)
-		if err != nil {
-			return imagetype_new.Unknown, err
-		}
-		if len(b) >= 2 && b[0] == 0xFF && b[1] == 0xD8 {
-			return imagetype_new.JPEG, nil
-		}
-		return imagetype_new.Unknown, newUnknownFormatError()
-	}
-
-	// Register the detector using the method
-	testRegistry.RegisterDetector(testDetector, 64)
-
-	// Verify the detector is registered
-	require.Len(t, testRegistry.detectors, 1)
-	require.NotNil(t, testRegistry.detectors[0])
-}
-
-func TestRegisterMagicBytes(t *testing.T) {
-	// Create a test registry to avoid interfering with global state
-	testRegistry := &Registry{}
-
-	require.Empty(t, testRegistry.detectors)
-
-	// Register magic bytes for JPEG using the method
-	jpegMagic := []byte{0xFF, 0xD8}
-	testRegistry.RegisterMagicBytes(jpegMagic, imagetype_new.JPEG)
-
-	// Verify the magic bytes are registered
-	require.Len(t, testRegistry.detectors, 1)
-}

+ 0 - 35
imagedetect/svg.go

@@ -1,35 +0,0 @@
-package imagedetect
-
-import (
-	"strings"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-	"github.com/imgproxy/imgproxy/v3/imagetype_new"
-
-	"github.com/tdewolff/parse/v2"
-	"github.com/tdewolff/parse/v2/xml"
-)
-
-func init() {
-	// Register SVG detector (needs at least 1000 bytes to reliably detect SVG)
-	RegisterDetector(IsSVG, 1000)
-}
-
-func IsSVG(r bufreader.ReadPeeker) (imagetype_new.Type, error) {
-	l := xml.NewLexer(parse.NewInput(r))
-
-	for {
-		tt, _ := l.Next()
-
-		switch tt {
-		case xml.ErrorToken:
-			return imagetype_new.Unknown, nil
-
-		case xml.StartTagToken:
-			tag := strings.ToLower(string(l.Text()))
-			if tag == "svg" || tag == "svg:svg" {
-				return imagetype_new.SVG, nil
-			}
-		}
-	}
-}