image_meta.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. package imagesize
  2. import (
  3. "bufio"
  4. "errors"
  5. "io"
  6. "sync"
  7. "sync/atomic"
  8. )
  9. type Meta struct {
  10. Format string
  11. Width, Height int
  12. }
  13. type format struct {
  14. magic string
  15. decodeMeta func(io.Reader) (*Meta, error)
  16. }
  17. type reader interface {
  18. io.Reader
  19. Peek(int) ([]byte, error)
  20. }
  21. var (
  22. formatsMu sync.Mutex
  23. atomicFormats atomic.Value
  24. ErrFormat = errors.New("unknown image format")
  25. )
  26. func asReader(r io.Reader) reader {
  27. if rr, ok := r.(reader); ok {
  28. return rr
  29. }
  30. return bufio.NewReader(r)
  31. }
  32. func matchMagic(magic string, b []byte) bool {
  33. if len(magic) != len(b) {
  34. return false
  35. }
  36. for i, c := range b {
  37. if magic[i] != c && magic[i] != '?' {
  38. return false
  39. }
  40. }
  41. return true
  42. }
  43. func RegisterFormat(magic string, decodeMeta func(io.Reader) (*Meta, error)) {
  44. formatsMu.Lock()
  45. defer formatsMu.Unlock()
  46. formats, _ := atomicFormats.Load().([]format)
  47. atomicFormats.Store(append(formats, format{magic, decodeMeta}))
  48. }
  49. func DecodeMeta(r io.Reader) (*Meta, error) {
  50. rr := asReader(r)
  51. formats, _ := atomicFormats.Load().([]format)
  52. for _, f := range formats {
  53. b, err := rr.Peek(len(f.magic))
  54. if err == nil && matchMagic(f.magic, b) {
  55. return f.decodeMeta(rr)
  56. }
  57. }
  58. return nil, ErrFormat
  59. }