imagetype.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. package imagetype
  2. import (
  3. "fmt"
  4. "net/url"
  5. "path/filepath"
  6. "strings"
  7. )
  8. type Type int
  9. const (
  10. Unknown Type = iota
  11. JPEG
  12. PNG
  13. WEBP
  14. GIF
  15. ICO
  16. SVG
  17. HEIC
  18. AVIF
  19. BMP
  20. TIFF
  21. )
  22. const contentDispositionFilenameFallback = "image"
  23. var (
  24. Types = map[string]Type{
  25. "jpeg": JPEG,
  26. "jpg": JPEG,
  27. "png": PNG,
  28. "webp": WEBP,
  29. "gif": GIF,
  30. "ico": ICO,
  31. "svg": SVG,
  32. "heic": HEIC,
  33. "avif": AVIF,
  34. "bmp": BMP,
  35. "tiff": TIFF,
  36. }
  37. mimes = map[Type]string{
  38. JPEG: "image/jpeg",
  39. PNG: "image/png",
  40. WEBP: "image/webp",
  41. GIF: "image/gif",
  42. ICO: "image/x-icon",
  43. SVG: "image/svg+xml",
  44. HEIC: "image/heif",
  45. AVIF: "image/avif",
  46. BMP: "image/bmp",
  47. TIFF: "image/tiff",
  48. }
  49. contentDispositionsFmt = map[Type]string{
  50. JPEG: "%s; filename=\"%s.jpg\"",
  51. PNG: "%s; filename=\"%s.png\"",
  52. WEBP: "%s; filename=\"%s.webp\"",
  53. GIF: "%s; filename=\"%s.gif\"",
  54. ICO: "%s; filename=\"%s.ico\"",
  55. SVG: "%s; filename=\"%s.svg\"",
  56. HEIC: "%s; filename=\"%s.heic\"",
  57. AVIF: "%s; filename=\"%s.avif\"",
  58. BMP: "%s; filename=\"%s.bmp\"",
  59. TIFF: "%s; filename=\"%s.tiff\"",
  60. }
  61. )
  62. func (it Type) String() string {
  63. for k, v := range Types {
  64. if v == it {
  65. return k
  66. }
  67. }
  68. return ""
  69. }
  70. func (it Type) MarshalJSON() ([]byte, error) {
  71. for k, v := range Types {
  72. if v == it {
  73. return []byte(fmt.Sprintf("%q", k)), nil
  74. }
  75. }
  76. return []byte("null"), nil
  77. }
  78. func (it Type) Mime() string {
  79. if mime, ok := mimes[it]; ok {
  80. return mime
  81. }
  82. return "application/octet-stream"
  83. }
  84. func (it Type) ContentDisposition(filename string, returnAttachment bool) string {
  85. disposition := "inline"
  86. if returnAttachment {
  87. disposition = "attachment"
  88. }
  89. format, ok := contentDispositionsFmt[it]
  90. if !ok {
  91. return disposition
  92. }
  93. return fmt.Sprintf(format, disposition, strings.ReplaceAll(filename, `"`, "%22"))
  94. }
  95. func (it Type) ContentDispositionFromURL(imageURL string, returnAttachment bool) string {
  96. url, err := url.Parse(imageURL)
  97. if err != nil {
  98. return it.ContentDisposition(contentDispositionFilenameFallback, returnAttachment)
  99. }
  100. _, filename := filepath.Split(url.Path)
  101. if len(filename) == 0 {
  102. return it.ContentDisposition(contentDispositionFilenameFallback, returnAttachment)
  103. }
  104. return it.ContentDisposition(strings.TrimSuffix(filename, filepath.Ext(filename)), returnAttachment)
  105. }
  106. func (it Type) SupportsAlpha() bool {
  107. return it != JPEG && it != BMP
  108. }
  109. func (it Type) SupportsAnimation() bool {
  110. return it == GIF || it == WEBP
  111. }
  112. func (it Type) SupportsColourProfile() bool {
  113. return it == JPEG ||
  114. it == PNG ||
  115. it == WEBP ||
  116. it == AVIF
  117. }
  118. func (it Type) SupportsThumbnail() bool {
  119. return it == HEIC || it == AVIF
  120. }