registry.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package imagetype
  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. typesByName map[string]Type // maps type string to Type
  32. }
  33. // globalRegistry is the default registry instance
  34. var globalRegistry = NewRegistry()
  35. // NewRegistry creates a new image type registry.
  36. func NewRegistry() *registry {
  37. return &registry{
  38. types: nil,
  39. typesByName: make(map[string]Type),
  40. }
  41. }
  42. // RegisterType registers a new image type in the global registry.
  43. // It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
  44. func RegisterType(desc *TypeDesc) Type {
  45. return globalRegistry.RegisterType(desc)
  46. }
  47. // GetTypeDesc returns the TypeDesc for the given Type.
  48. // Returns nil if the type is not registered.
  49. func GetTypeDesc(t Type) *TypeDesc {
  50. return globalRegistry.GetTypeDesc(t)
  51. }
  52. // GetTypes returns all registered image types.
  53. func GetTypeByName(name string) (Type, bool) {
  54. return globalRegistry.GetTypeByName(name)
  55. }
  56. // RegisterType registers a new image type in this registry.
  57. // It panics if the type already exists (i.e., if a TypeDesc is already registered for this Type).
  58. func (r *registry) RegisterType(desc *TypeDesc) Type {
  59. r.types = append(r.types, desc)
  60. typ := Type(len(r.types)) // 0 is unknown
  61. r.typesByName[desc.String] = typ
  62. // NOTE: this is a special case for JPEG. The problem is that JPEG is using
  63. // several alternative extensions and processing_options.go is using extension to
  64. // find a type by key. There might be not the only case (e.g. ".tif/.tiff").
  65. // We need to handle this case in a more generic way.
  66. if desc.String == "jpeg" {
  67. // JPEG is a special case, we need to alias it
  68. r.typesByName["jpg"] = typ
  69. }
  70. return typ
  71. }
  72. // GetTypeDesc returns the TypeDesc for the given Type.
  73. // Returns nil if the type is not registered.
  74. func (r *registry) GetTypeDesc(t Type) *TypeDesc {
  75. if t <= 0 { // This would be "default" type
  76. return nil
  77. }
  78. if int(t-1) >= len(r.types) {
  79. return nil
  80. }
  81. return r.types[t-1]
  82. }
  83. // GetTypeByName returns Type by it's name
  84. func (r *registry) GetTypeByName(name string) (Type, bool) {
  85. typ, ok := r.typesByName[name]
  86. return typ, ok
  87. }
  88. // RegisterDetector registers a custom detector function
  89. // Detectors are tried in the order they were registered
  90. func RegisterDetector(detector DetectFunc) {
  91. globalRegistry.RegisterDetector(detector)
  92. }
  93. // RegisterMagicBytes registers magic bytes for a specific image type
  94. // Magic byte detectors are always tried before custom detectors
  95. func RegisterMagicBytes(typ Type, signature ...[]byte) {
  96. globalRegistry.RegisterMagicBytes(typ, signature...)
  97. }
  98. // Detect attempts to detect the image type from a reader.
  99. // It first tries magic byte detection, then custom detectors in registration order
  100. func Detect(r io.Reader) (Type, error) {
  101. return globalRegistry.Detect(r)
  102. }
  103. // RegisterDetector registers a custom detector function on this registry instance
  104. func (r *registry) RegisterDetector(detector DetectFunc) {
  105. r.detectors = append(r.detectors, detector)
  106. }
  107. // RegisterMagicBytes registers magic bytes for a specific image type on this registry instance
  108. func (r *registry) RegisterMagicBytes(typ Type, signature ...[]byte) {
  109. r.detectors = append(r.detectors, func(r bufreader.ReadPeeker) (Type, error) {
  110. for _, sig := range signature {
  111. b, err := r.Peek(len(sig))
  112. if err != nil {
  113. return Unknown, err
  114. }
  115. if hasMagicBytes(b, sig) {
  116. return typ, nil
  117. }
  118. }
  119. return Unknown, nil
  120. })
  121. }
  122. // Detect runs image format detection
  123. func (r *registry) Detect(re io.Reader) (Type, error) {
  124. br := bufreader.New(io.LimitReader(re, maxDetectionLimit))
  125. for _, fn := range r.detectors {
  126. br.Rewind()
  127. typ, err := fn(br)
  128. if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
  129. return Unknown, newTypeDetectionError(err)
  130. }
  131. if err == nil && typ != Unknown {
  132. return typ, nil
  133. }
  134. }
  135. return Unknown, newUnknownFormatError()
  136. }
  137. // hasMagicBytes checks if the data matches a magic byte signature
  138. // Supports '?' characters in signature which match any byte
  139. func hasMagicBytes(data []byte, magic []byte) bool {
  140. if len(data) < len(magic) {
  141. return false
  142. }
  143. for i, c := range magic {
  144. if c != data[i] && c != '?' {
  145. return false
  146. }
  147. }
  148. return true
  149. }