Browse Source

Revert "IMG-23: split image type detection from meta (#1481)"

This reverts commit e7bcb211a3a5c6a5e8f971419d980715d7acce1a.
Victor Sokolov 1 tháng trước cách đây
mục cha
commit
2e29898fc6

+ 63 - 38
bufreader/bufreader.go

@@ -1,79 +1,104 @@
-// bufreader provides a buffered reader that reads from io.Reader, but caches
-// the data in a bytes.Buffer to allow peeking and discarding without re-reading.
 package bufreader
 
 import (
+	"bufio"
+	"bytes"
 	"io"
-)
 
-// ReadPeeker is an interface that combines io.Reader and a method to peek at the next n bytes
-type ReadPeeker interface {
-	io.Reader
-	Peek(n int) ([]byte, error) // Peek returns the next n bytes without advancing
-}
+	"github.com/imgproxy/imgproxy/v3/imath"
+)
 
-// Reader is a buffered reader that reads from an io.Reader and caches the data.
 type Reader struct {
 	r   io.Reader
-	buf []byte
-	pos int
+	buf *bytes.Buffer
+	cur int
 }
 
-// New creates new buffered reader
-func New(r io.Reader) *Reader {
+func New(r io.Reader, buf *bytes.Buffer) *Reader {
 	br := Reader{
 		r:   r,
-		buf: nil,
+		buf: buf,
 	}
 	return &br
 }
 
-// Read reads data into p from the buffered reader.
 func (br *Reader) Read(p []byte) (int, error) {
-	if err := br.fetch(br.pos + len(p)); err != nil {
+	if err := br.fill(br.cur + len(p)); err != nil {
+		return 0, err
+	}
+
+	n := copy(p, br.buf.Bytes()[br.cur:])
+	br.cur += n
+	return n, nil
+}
+
+func (br *Reader) ReadByte() (byte, error) {
+	if err := br.fill(br.cur + 1); err != nil {
+		return 0, err
+	}
+
+	b := br.buf.Bytes()[br.cur]
+	br.cur++
+	return b, nil
+}
+
+func (br *Reader) Discard(n int) (int, error) {
+	if n < 0 {
+		return 0, bufio.ErrNegativeCount
+	}
+	if n == 0 {
+		return 0, nil
+	}
+
+	if err := br.fill(br.cur + n); err != nil {
 		return 0, err
 	}
 
-	n := copy(p, br.buf[br.pos:])
-	br.pos += n
+	n = imath.Min(n, br.buf.Len()-br.cur)
+	br.cur += n
 	return n, nil
 }
 
-// Peek returns the next n bytes from the buffered reader without advancing the position.
 func (br *Reader) Peek(n int) ([]byte, error) {
-	err := br.fetch(br.pos + n)
-	if err != nil && err != io.EOF {
-		return nil, err
+	if n < 0 {
+		return []byte{}, bufio.ErrNegativeCount
+	}
+	if n == 0 {
+		return []byte{}, nil
+	}
+
+	if err := br.fill(br.cur + n); err != nil {
+		return []byte{}, err
 	}
 
-	// Return slice of buffered data without advancing position
-	available := br.buf[br.pos:]
-	if len(available) == 0 && err == io.EOF {
-		return nil, io.EOF
+	if n > br.buf.Len()-br.cur {
+		return br.buf.Bytes()[br.cur:], io.EOF
 	}
 
-	return available[:min(len(available), n)], nil
+	return br.buf.Bytes()[br.cur : br.cur+n], nil
 }
 
-// Rewind seeks buffer to the beginning
-func (br *Reader) Rewind() {
-	br.pos = 0
+func (br *Reader) Flush() error {
+	_, err := br.buf.ReadFrom(br.r)
+	return err
 }
 
-// fetch ensures the buffer contains at least 'need' bytes
-func (br *Reader) fetch(need int) error {
-	if need-len(br.buf) <= 0 {
+func (br *Reader) fill(need int) error {
+	n := need - br.buf.Len()
+	if n <= 0 {
 		return nil
 	}
 
-	b := make([]byte, need)
-	n, err := io.ReadFull(br.r, b)
-	if err != nil && err != io.ErrUnexpectedEOF {
+	n = imath.Max(4096, n)
+
+	if _, err := br.buf.ReadFrom(io.LimitReader(br.r, int64(n))); err != nil {
 		return err
 	}
 
-	// append only those which we read in fact
-	br.buf = append(br.buf, b[:n]...)
+	// Nothing was read, it's EOF
+	if br.cur == br.buf.Len() {
+		return io.EOF
+	}
 
 	return nil
 }

+ 0 - 97
bufreader/bufreader_test.go

@@ -1,97 +0,0 @@
-package bufreader
-
-import (
-	"io"
-	"strings"
-	"testing"
-
-	"github.com/stretchr/testify/suite"
-)
-
-// BufferedReaderTestSuite defines the test suite for the buffered reader
-type BufferedReaderTestSuite struct {
-	suite.Suite
-}
-
-func (s *BufferedReaderTestSuite) TestRead() {
-	data := "hello world"
-	br := New(strings.NewReader(data))
-
-	// First read
-	p1 := make([]byte, 5)
-	n1, err1 := br.Read(p1)
-	s.Require().NoError(err1)
-	s.Equal(5, n1)
-	s.Equal("hello", string(p1))
-
-	// Second read
-	p2 := make([]byte, 6)
-	n2, err2 := br.Read(p2)
-	s.Require().NoError(err2)
-	s.Equal(6, n2)
-	s.Equal(" world", string(p2))
-
-	// Verify position
-	s.Equal(11, br.pos)
-}
-
-func (s *BufferedReaderTestSuite) TestEOF() {
-	data := "hello"
-	br := New(strings.NewReader(data))
-
-	// Read all data
-	p1 := make([]byte, 5)
-	n1, err1 := br.Read(p1)
-	s.Require().NoError(err1)
-	s.Equal(5, n1)
-	s.Equal("hello", string(p1))
-
-	// Try to read more - should get EOF
-	p2 := make([]byte, 5)
-	n2, err2 := br.Read(p2)
-	s.Equal(io.EOF, err2)
-	s.Equal(0, n2)
-}
-
-func (s *BufferedReaderTestSuite) TestEOF_WhenDataExhausted() {
-	data := "hello"
-	br := New(strings.NewReader(data))
-
-	// Try to read more than available
-	p := make([]byte, 10)
-	n, err := br.Read(p)
-
-	s.Require().NoError(err)
-	s.Equal(5, n)
-	s.Equal("hello", string(p[:n]))
-}
-
-func (s *BufferedReaderTestSuite) TestPeek() {
-	data := "hello world"
-	br := New(strings.NewReader(data))
-
-	// Peek at first 5 bytes
-	peeked, err := br.Peek(5)
-	s.Require().NoError(err)
-	s.Equal("hello", string(peeked))
-	s.Equal(0, br.pos) // Position should not change
-
-	// Read the same data to verify peek didn't consume it
-	p := make([]byte, 5)
-	n, err := br.Read(p)
-	s.Require().NoError(err)
-	s.Equal(5, n)
-	s.Equal("hello", string(p))
-	s.Equal(5, br.pos) // Position should now be updated
-
-	// Peek at the next 7 bytes (which are beyond the EOF)
-	peeked2, err := br.Peek(7)
-	s.Require().NoError(err)
-	s.Equal(" world", string(peeked2))
-	s.Equal(5, br.pos) // Position should still be 5
-}
-
-// TestBufferedReaderSuite runs the test suite
-func TestBufferedReader(t *testing.T) {
-	suite.Run(t, new(BufferedReaderTestSuite))
-}

+ 9 - 2
imagetype/imagetype.go

@@ -1,5 +1,3 @@
-// Code generated by gen_imagetype.go; DO NOT EDIT.
-
 package imagetype
 
 import (
@@ -76,6 +74,15 @@ var (
 	}
 )
 
+func ByMime(mime string) Type {
+	for k, v := range mimes {
+		if v == mime {
+			return k
+		}
+	}
+	return Unknown
+}
+
 func (it Type) String() string {
 	// JPEG has two names, we should use only the full one
 	if it == JPEG {

+ 0 - 191
imagetype_new/defs.go

@@ -1,191 +0,0 @@
-package imagetype_new
-
-var (
-	JPEG = RegisterType(&TypeDesc{
-		String:                "jpeg",
-		Ext:                   ".jpg",
-		Mime:                  "image/jpeg",
-		IsVector:              false,
-		SupportsAlpha:         false,
-		SupportsColourProfile: true,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	JXL = RegisterType(&TypeDesc{
-		String:                "jxl",
-		Ext:                   ".jxl",
-		Mime:                  "image/jxl",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: true,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	PNG = RegisterType(&TypeDesc{
-		String:                "png",
-		Ext:                   ".png",
-		Mime:                  "image/png",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-		SupportsQuality:       false,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	WEBP = RegisterType(&TypeDesc{
-		String:                "webp",
-		Ext:                   ".webp",
-		Mime:                  "image/webp",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: true,
-		SupportsAnimationSave: true,
-		SupportsThumbnail:     false,
-	})
-
-	GIF = RegisterType(&TypeDesc{
-		String:                "gif",
-		Ext:                   ".gif",
-		Mime:                  "image/gif",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: false,
-		SupportsQuality:       false,
-		SupportsAnimationLoad: true,
-		SupportsAnimationSave: true,
-		SupportsThumbnail:     false,
-	})
-
-	ICO = RegisterType(&TypeDesc{
-		String:                "ico",
-		Ext:                   ".ico",
-		Mime:                  "image/x-icon",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: false,
-		SupportsQuality:       false,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	SVG = RegisterType(&TypeDesc{
-		String:                "svg",
-		Ext:                   ".svg",
-		Mime:                  "image/svg+xml",
-		IsVector:              true,
-		SupportsAlpha:         true,
-		SupportsColourProfile: false,
-		SupportsQuality:       false,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	HEIC = RegisterType(&TypeDesc{
-		String:                "heic",
-		Ext:                   ".heic",
-		Mime:                  "image/heif",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     true,
-	})
-
-	AVIF = RegisterType(&TypeDesc{
-		String:                "avif",
-		Ext:                   ".avif",
-		Mime:                  "image/avif",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     true,
-	})
-
-	BMP = RegisterType(&TypeDesc{
-		String:                "bmp",
-		Ext:                   ".bmp",
-		Mime:                  "image/bmp",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: false,
-		SupportsQuality:       false,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-
-	TIFF = RegisterType(&TypeDesc{
-		String:                "tiff",
-		Ext:                   ".tiff",
-		Mime:                  "image/tiff",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: false,
-		SupportsQuality:       true,
-		SupportsAnimationLoad: false,
-		SupportsAnimationSave: false,
-		SupportsThumbnail:     false,
-	})
-)
-
-// init registers default magic bytes for common image formats
-func init() {
-	// NOTE: we cannot be 100% sure of image type until we fully decode it. This is especially true
-	// for "naked" jxl (0xff 0x0a). There is no other way to ensure this is a JXL file, except to fully
-	// decode it. Two bytes are too few to reliably identify the format. The same applies to ICO.
-
-	// JPEG magic bytes
-	RegisterMagicBytes(JPEG, []byte("\xff\xd8"))
-
-	// JXL magic bytes
-	RegisterMagicBytes(JXL, []byte{0xff, 0x0a})                                                             // JXL codestream (can't use string due to 0x0a)
-	RegisterMagicBytes(JXL, []byte{0x00, 0x00, 0x00, 0x0C, 0x4A, 0x58, 0x4C, 0x20, 0x0D, 0x0A, 0x87, 0x0A}) // JXL container (has null bytes)
-
-	// PNG magic bytes
-	RegisterMagicBytes(PNG, []byte("\x89PNG\r\n\x1a\n"))
-
-	// WEBP magic bytes (RIFF container with WEBP fourcc) - using wildcard for size
-	RegisterMagicBytes(WEBP, []byte("RIFF????WEBP"))
-
-	// GIF magic bytes
-	RegisterMagicBytes(GIF, []byte("GIF8?a"))
-
-	// ICO magic bytes
-	RegisterMagicBytes(ICO, []byte{0, 0, 1, 0}) // ICO (has null bytes)
-
-	// HEIC/HEIF magic bytes with wildcards for size
-	RegisterMagicBytes(HEIC, []byte("????ftypheic"),
-		[]byte("????ftypheix"),
-		[]byte("????ftyphevc"),
-		[]byte("????ftypheim"),
-		[]byte("????ftypheis"),
-		[]byte("????ftyphevm"),
-		[]byte("????ftyphevs"),
-		[]byte("????ftypmif1"))
-
-	// AVIF magic bytes
-	RegisterMagicBytes(AVIF, []byte("????ftypavif"))
-
-	// BMP magic bytes
-	RegisterMagicBytes(BMP, []byte("BM"))
-
-	// TIFF magic bytes (little-endian and big-endian)
-	RegisterMagicBytes(TIFF, []byte("II*\x00"), []byte("MM\x00*")) // Big-Endian, Little-endian
-}

+ 0 - 23
imagetype_new/errors.go

@@ -1,23 +0,0 @@
-package imagetype_new
-
-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 - 143
imagetype_new/registry.go

@@ -1,143 +0,0 @@
-package imagetype_new
-
-import (
-	"io"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-)
-
-const (
-	// maxDetectionLimit is maximum bytes detectors allowed to read from the source
-	maxDetectionLimit = 32 * 1024
-)
-
-// TypeDesc is used to store metadata about an image type.
-// It represents the minimal information needed to make imgproxy to
-// work with the type.
-type TypeDesc struct {
-	String                string
-	Ext                   string
-	Mime                  string
-	IsVector              bool
-	SupportsAlpha         bool
-	SupportsColourProfile bool
-	SupportsQuality       bool
-	SupportsAnimationLoad bool
-	SupportsAnimationSave bool
-	SupportsThumbnail     bool
-}
-
-// DetectFunc is a function that detects the image type from byte data
-type DetectFunc func(r bufreader.ReadPeeker) (Type, error)
-
-// Registry holds the type registry
-type Registry struct {
-	detectors []DetectFunc
-	types     []*TypeDesc
-}
-
-// globalRegistry is the default registry instance
-var globalRegistry = &Registry{}
-
-// RegisterType registers a new image type in the global registry.
-// It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
-func RegisterType(desc *TypeDesc) Type {
-	return globalRegistry.RegisterType(desc)
-}
-
-// GetTypeDesc returns the TypeDesc for the given Type.
-// Returns nil if the type is not registered.
-func GetTypeDesc(t Type) *TypeDesc {
-	return globalRegistry.GetTypeDesc(t)
-}
-
-// RegisterType registers a new image type in this registry.
-// It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
-func (r *Registry) RegisterType(desc *TypeDesc) Type {
-	r.types = append(r.types, desc)
-	return Type(len(r.types)) // 0 is unknown
-}
-
-// GetTypeDesc returns the TypeDesc for the given Type.
-// Returns nil if the type is not registered.
-func (r *Registry) GetTypeDesc(t Type) *TypeDesc {
-	if t <= 0 { // This would be "default" type
-		return nil
-	}
-
-	if int(t-1) >= len(r.types) {
-		return nil
-	}
-
-	return r.types[t-1]
-}
-
-// RegisterDetector registers a custom detector function
-// Detectors are tried in the order they were registered
-func RegisterDetector(detector DetectFunc) {
-	globalRegistry.RegisterDetector(detector)
-}
-
-// RegisterMagicBytes registers magic bytes for a specific image type
-// Magic byte detectors are always tried before custom detectors
-func RegisterMagicBytes(typ Type, signature ...[]byte) {
-	globalRegistry.RegisterMagicBytes(typ, signature...)
-}
-
-// 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) (Type, error) {
-	return globalRegistry.Detect(r)
-}
-
-// RegisterDetector registers a custom detector function on this registry instance
-func (r *Registry) RegisterDetector(detector DetectFunc) {
-	r.detectors = append(r.detectors, detector)
-}
-
-// RegisterMagicBytes registers magic bytes for a specific image type on this registry instance
-func (r *Registry) RegisterMagicBytes(typ Type, signature ...[]byte) {
-	r.detectors = append(r.detectors, func(r bufreader.ReadPeeker) (Type, error) {
-		for _, sig := range signature {
-			b, err := r.Peek(len(sig))
-			if err != nil {
-				return Unknown, err
-			}
-
-			if hasMagicBytes(b, sig) {
-				return typ, nil
-			}
-		}
-
-		return Unknown, nil
-	})
-}
-
-// Detect runs image format detection
-func (r *Registry) Detect(re io.Reader) (Type, error) {
-	br := bufreader.New(io.LimitReader(re, maxDetectionLimit))
-
-	for _, fn := range globalRegistry.detectors {
-		br.Rewind()
-		if typ, err := fn(br); err == nil && typ != Unknown {
-			return typ, nil
-		}
-	}
-
-	return 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
-}

+ 0 - 178
imagetype_new/registry_test.go

@@ -1,178 +0,0 @@
-package imagetype_new
-
-import (
-	"testing"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-	"github.com/stretchr/testify/require"
-)
-
-func TestRegisterType(t *testing.T) {
-	// Create a separate registry for testing to avoid conflicts with global registry
-	testRegistry := &Registry{}
-
-	// Register a custom type
-	customDesc := &TypeDesc{
-		String:                "custom",
-		Ext:                   ".custom",
-		Mime:                  "image/custom",
-		IsVector:              false,
-		SupportsAlpha:         true,
-		SupportsColourProfile: true,
-	}
-
-	customType := testRegistry.RegisterType(customDesc)
-
-	// Verify the type is now registered
-	result := testRegistry.GetTypeDesc(customType)
-	require.NotNil(t, result)
-	require.Equal(t, customDesc.String, result.String)
-	require.Equal(t, customDesc.Ext, result.Ext)
-	require.Equal(t, customDesc.Mime, result.Mime)
-	require.Equal(t, customDesc.IsVector, result.IsVector)
-	require.Equal(t, customDesc.SupportsAlpha, result.SupportsAlpha)
-	require.Equal(t, customDesc.SupportsColourProfile, result.SupportsColourProfile)
-}
-
-func TestTypeProperties(t *testing.T) {
-	// Test that Type methods use TypeDesc fields correctly
-	tests := []struct {
-		name                string
-		typ                 Type
-		expectVector        bool
-		expectAlpha         bool
-		expectColourProfile bool
-		expectQuality       bool
-		expectAnimationLoad bool
-		expectAnimationSave bool
-		expectThumbnail     bool
-	}{
-		{
-			name:                "JPEG",
-			typ:                 JPEG,
-			expectVector:        false,
-			expectAlpha:         false,
-			expectColourProfile: true,
-			expectQuality:       true,
-			expectAnimationLoad: false,
-			expectAnimationSave: false,
-			expectThumbnail:     false,
-		},
-		{
-			name:                "PNG",
-			typ:                 PNG,
-			expectVector:        false,
-			expectAlpha:         true,
-			expectColourProfile: true,
-			expectQuality:       false,
-			expectAnimationLoad: false,
-			expectAnimationSave: false,
-			expectThumbnail:     false,
-		},
-		{
-			name:                "WEBP",
-			typ:                 WEBP,
-			expectVector:        false,
-			expectAlpha:         true,
-			expectColourProfile: true,
-			expectQuality:       true,
-			expectAnimationLoad: true,
-			expectAnimationSave: true,
-			expectThumbnail:     false,
-		},
-		{
-			name:                "SVG",
-			typ:                 SVG,
-			expectVector:        true,
-			expectAlpha:         true,
-			expectColourProfile: false,
-			expectQuality:       false,
-			expectAnimationLoad: false,
-			expectAnimationSave: false,
-			expectThumbnail:     false,
-		},
-		{
-			name:                "GIF",
-			typ:                 GIF,
-			expectVector:        false,
-			expectAlpha:         true,
-			expectColourProfile: false,
-			expectQuality:       false,
-			expectAnimationLoad: true,
-			expectAnimationSave: true,
-			expectThumbnail:     false,
-		},
-		{
-			name:                "HEIC",
-			typ:                 HEIC,
-			expectVector:        false,
-			expectAlpha:         true,
-			expectColourProfile: true,
-			expectQuality:       true,
-			expectAnimationLoad: false,
-			expectAnimationSave: false,
-			expectThumbnail:     true,
-		},
-		{
-			name:                "AVIF",
-			typ:                 AVIF,
-			expectVector:        false,
-			expectAlpha:         true,
-			expectColourProfile: true,
-			expectQuality:       true,
-			expectAnimationLoad: false,
-			expectAnimationSave: false,
-			expectThumbnail:     true,
-		},
-	}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			require.Equal(t, tt.expectVector, tt.typ.IsVector())
-			require.Equal(t, tt.expectAlpha, tt.typ.SupportsAlpha())
-			require.Equal(t, tt.expectColourProfile, tt.typ.SupportsColourProfile())
-			require.Equal(t, tt.expectQuality, tt.typ.SupportsQuality())
-			require.Equal(t, tt.expectAnimationLoad, tt.typ.SupportsAnimationLoad())
-			require.Equal(t, tt.expectAnimationSave, tt.typ.SupportsAnimationSave())
-			require.Equal(t, tt.expectThumbnail, tt.typ.SupportsThumbnail())
-		})
-	}
-}
-
-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) (Type, error) {
-		b, err := r.Peek(2)
-		if err != nil {
-			return Unknown, err
-		}
-		if len(b) >= 2 && b[0] == 0xFF && b[1] == 0xD8 {
-			return JPEG, nil
-		}
-		return Unknown, newUnknownFormatError()
-	}
-
-	// Register the detector using the method
-	testRegistry.RegisterDetector(testDetector)
-
-	// 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(JPEG, jpegMagic)
-
-	// Verify the magic bytes are registered
-	require.Len(t, testRegistry.detectors, 1)
-}

+ 0 - 34
imagetype_new/svg.go

@@ -1,34 +0,0 @@
-package imagetype_new
-
-import (
-	"strings"
-
-	"github.com/imgproxy/imgproxy/v3/bufreader"
-
-	"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)
-}
-
-func IsSVG(r bufreader.ReadPeeker) (Type, error) {
-	l := xml.NewLexer(parse.NewInput(r))
-
-	for {
-		tt, _ := l.Next()
-
-		switch tt {
-		case xml.ErrorToken:
-			return Unknown, nil
-
-		case xml.StartTagToken:
-			tag := strings.ToLower(string(l.Text()))
-			if tag == "svg" || tag == "svg:svg" {
-				return SVG, nil
-			}
-		}
-	}
-}

+ 0 - 121
imagetype_new/type.go

@@ -1,121 +0,0 @@
-package imagetype_new
-
-import (
-	"fmt"
-)
-
-// Type represents an image type
-type (
-	// Type represents an image type.
-	Type int
-)
-
-// Supported image types
-var (
-	// Unknown is a reserved type, it has index 0. We guarantee that index 0 won't be used
-	// for any other type. This way, Unknown is a zero value for Type.
-	Unknown Type = 0
-)
-
-// Mime returns the MIME type for the image type.
-func (t Type) Mime() string {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.Mime
-	}
-
-	return "application/octet-stream"
-}
-
-// String returns the string representation of the image type.
-func (t Type) String() string {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.String
-	}
-
-	return ""
-}
-
-// Ext returns the file extension for the image type.
-func (t Type) Ext() string {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.Ext
-	}
-
-	return ""
-}
-
-// MarshalJSON implements the json.Marshaler interface for Type.
-func (t Type) MarshalJSON() ([]byte, error) {
-	s := t.String()
-	if s == "" {
-		return []byte("null"), nil
-	}
-
-	return fmt.Appendf(nil, "%q", s), nil
-}
-
-// IsVector checks if the image type is a vector format.
-func (t Type) IsVector() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.IsVector
-	}
-	return false
-}
-
-// SupportsAlpha checks if the image type supports alpha transparency.
-func (t Type) SupportsAlpha() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsAlpha
-	}
-	return true
-}
-
-// SupportsAnimationLoad checks if the image type supports animation.
-func (t Type) SupportsAnimationLoad() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsAnimationLoad
-	}
-	return false
-}
-
-// SupportsAnimationSave checks if the image type supports saving animations.
-func (t Type) SupportsAnimationSave() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsAnimationSave
-	}
-	return false
-}
-
-// SupportsColourProfile checks if the image type supports colour profiles.
-func (t Type) SupportsColourProfile() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsColourProfile
-	}
-	return false
-}
-
-// SupportsQuality checks if the image type supports quality adjustments.
-func (t Type) SupportsQuality() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsQuality
-	}
-	return false
-}
-
-// SupportsThumbnail checks if the image type supports thumbnails.
-func (t Type) SupportsThumbnail() bool {
-	desc := GetTypeDesc(t)
-	if desc != nil {
-		return desc.SupportsThumbnail
-	}
-	return false
-}

+ 0 - 59
imagetype_new/type_test.go

@@ -1,59 +0,0 @@
-package imagetype_new
-
-import (
-	"os"
-	"testing"
-
-	"github.com/stretchr/testify/require"
-)
-
-func TestDefaultTypesRegistered(t *testing.T) {
-	// Test that all default types are properly registered by init()
-	defaultTypes := []Type{
-		JPEG, JXL, PNG, WEBP, GIF, ICO, SVG, HEIC, AVIF, BMP, TIFF,
-	}
-
-	for _, typ := range defaultTypes {
-		t.Run(typ.String(), func(t *testing.T) {
-			desc := GetTypeDesc(typ)
-			require.NotNil(t, desc)
-
-			// Verify that the description has non-empty fields
-			require.NotEmpty(t, desc.String)
-			require.NotEmpty(t, desc.Ext)
-			require.NotEqual(t, "application/octet-stream", desc.Mime)
-		})
-	}
-}
-
-func TestDetect(t *testing.T) {
-	tests := []struct {
-		name string
-		file string
-		want Type
-	}{
-		{"JPEG", "../testdata/test-images/jpg/jpg.jpg", JPEG},
-		{"JXL", "../testdata/test-images/jxl/jxl.jxl", JXL},
-		{"PNG", "../testdata/test-images/png/png.png", PNG},
-		{"WEBP", "../testdata/test-images/webp/webp.webp", WEBP},
-		{"GIF", "../testdata/test-images/gif/gif.gif", GIF},
-		{"ICO", "../testdata/test-images/ico/png-256x256.ico", ICO},
-		{"SVG", "../testdata/test-images/svg/svg.svg", SVG},
-		{"HEIC", "../testdata/test-images/heif/heif.heif", HEIC},
-		{"BMP", "../testdata/test-images/bmp/24-bpp.bmp", BMP},
-		{"TIFF", "../testdata/test-images/tiff/tiff.tiff", TIFF},
-		{"SVG", "../testdata/test-images/svg/svg.svg", 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)
-		})
-	}
-}