registry.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. package imagetype_new
  2. import (
  3. "io"
  4. "github.com/imgproxy/imgproxy/v3/bufreader"
  5. )
  6. const (
  7. // maxDetectionLimit is maximum bytes detectors allowed to read from the source
  8. maxDetectionLimit = 32 * 1024
  9. )
  10. // TypeDesc is used to store metadata about an image type.
  11. // It represents the minimal information needed to make imgproxy to
  12. // work with the type.
  13. type TypeDesc struct {
  14. String string
  15. Ext string
  16. Mime string
  17. IsVector bool
  18. SupportsAlpha bool
  19. SupportsColourProfile bool
  20. SupportsQuality bool
  21. SupportsAnimationLoad bool
  22. SupportsAnimationSave bool
  23. SupportsThumbnail bool
  24. }
  25. // DetectFunc is a function that detects the image type from byte data
  26. type DetectFunc func(r bufreader.ReadPeeker) (Type, error)
  27. // Registry holds the type registry
  28. type Registry struct {
  29. detectors []DetectFunc
  30. types []*TypeDesc
  31. }
  32. // globalRegistry is the default registry instance
  33. var globalRegistry = &Registry{}
  34. // RegisterType registers a new image type in the global registry.
  35. // It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
  36. func RegisterType(desc *TypeDesc) Type {
  37. return globalRegistry.RegisterType(desc)
  38. }
  39. // GetTypeDesc returns the TypeDesc for the given Type.
  40. // Returns nil if the type is not registered.
  41. func GetTypeDesc(t Type) *TypeDesc {
  42. return globalRegistry.GetTypeDesc(t)
  43. }
  44. // RegisterType registers a new image type in this registry.
  45. // It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
  46. func (r *Registry) RegisterType(desc *TypeDesc) Type {
  47. r.types = append(r.types, desc)
  48. return Type(len(r.types)) // 0 is unknown
  49. }
  50. // GetTypeDesc returns the TypeDesc for the given Type.
  51. // Returns nil if the type is not registered.
  52. func (r *Registry) GetTypeDesc(t Type) *TypeDesc {
  53. if t <= 0 { // This would be "default" type
  54. return nil
  55. }
  56. if int(t-1) >= len(r.types) {
  57. return nil
  58. }
  59. return r.types[t-1]
  60. }
  61. // RegisterDetector registers a custom detector function
  62. // Detectors are tried in the order they were registered
  63. func RegisterDetector(detector DetectFunc) {
  64. globalRegistry.RegisterDetector(detector)
  65. }
  66. // RegisterMagicBytes registers magic bytes for a specific image type
  67. // Magic byte detectors are always tried before custom detectors
  68. func RegisterMagicBytes(typ Type, signature ...[]byte) {
  69. globalRegistry.RegisterMagicBytes(typ, signature...)
  70. }
  71. // Detect attempts to detect the image type from a reader.
  72. // It first tries magic byte detection, then custom detectors in registration order
  73. func Detect(r io.Reader) (Type, error) {
  74. return globalRegistry.Detect(r)
  75. }
  76. // RegisterDetector registers a custom detector function on this registry instance
  77. func (r *Registry) RegisterDetector(detector DetectFunc) {
  78. r.detectors = append(r.detectors, detector)
  79. }
  80. // RegisterMagicBytes registers magic bytes for a specific image type on this registry instance
  81. func (r *Registry) RegisterMagicBytes(typ Type, signature ...[]byte) {
  82. r.detectors = append(r.detectors, func(r bufreader.ReadPeeker) (Type, error) {
  83. for _, sig := range signature {
  84. b, err := r.Peek(len(sig))
  85. if err != nil {
  86. return Unknown, err
  87. }
  88. if hasMagicBytes(b, sig) {
  89. return typ, nil
  90. }
  91. }
  92. return Unknown, nil
  93. })
  94. }
  95. // Detect runs image format detection
  96. func (r *Registry) Detect(re io.Reader) (Type, error) {
  97. br := bufreader.New(io.LimitReader(re, maxDetectionLimit))
  98. for _, fn := range globalRegistry.detectors {
  99. br.Rewind()
  100. if typ, err := fn(br); err == nil && typ != Unknown {
  101. return typ, nil
  102. }
  103. }
  104. return Unknown, newUnknownFormatError()
  105. }
  106. // hasMagicBytes checks if the data matches a magic byte signature
  107. // Supports '?' characters in signature which match any byte
  108. func hasMagicBytes(data []byte, magic []byte) bool {
  109. if len(data) < len(magic) {
  110. return false
  111. }
  112. for i, c := range magic {
  113. if c != data[i] && c != '?' {
  114. return false
  115. }
  116. }
  117. return true
  118. }