image.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package image
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/base64"
  6. "errors"
  7. "fmt"
  8. "image"
  9. // import gif decoder
  10. _ "image/gif"
  11. // import jpeg decoder
  12. _ "image/jpeg"
  13. // import png decoder
  14. _ "image/png"
  15. "io"
  16. "net/http"
  17. "regexp"
  18. "strings"
  19. "github.com/labring/aiproxy/core/common"
  20. // import webp decoder
  21. _ "golang.org/x/image/webp"
  22. )
  23. // Regex to match data URL pattern
  24. var dataURLPattern = regexp.MustCompile(`^data:image/([^;]+);base64,(.*)`)
  25. func IsImageURL(contentType string) bool {
  26. return strings.HasPrefix(contentType, "image/")
  27. }
  28. // TrimImageContentType delete after `;`
  29. func TrimImageContentType(contentType string) string {
  30. before, _, _ := strings.Cut(contentType, ";")
  31. return before
  32. }
  33. func GetImageSizeFromURL(url string) (width, height int, err error) {
  34. req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, url, nil)
  35. if err != nil {
  36. return 0, 0, err
  37. }
  38. resp, err := http.DefaultClient.Do(req)
  39. if err != nil {
  40. return width, height, err
  41. }
  42. defer resp.Body.Close()
  43. if resp.StatusCode != http.StatusOK {
  44. return 0, 0, fmt.Errorf("download image error: status code: %d", resp.StatusCode)
  45. }
  46. if resp.ContentLength > MaxImageSize {
  47. return 0, 0, fmt.Errorf(
  48. "download image error: image too large: %d, max: %d",
  49. resp.ContentLength,
  50. MaxImageSize,
  51. )
  52. }
  53. var reader io.Reader
  54. if resp.ContentLength <= 0 {
  55. reader = common.LimitReader(resp.Body, MaxImageSize)
  56. } else {
  57. reader = resp.Body
  58. }
  59. img, _, err := image.DecodeConfig(reader)
  60. if err != nil {
  61. return width, height, err
  62. }
  63. return img.Width, img.Height, nil
  64. }
  65. const (
  66. MaxImageSize = 1024 * 1024 * 10 // 10MB
  67. )
  68. func GetImageFromURL(ctx context.Context, url string) (string, string, error) {
  69. // Check if the URL is a data URL
  70. if !strings.HasPrefix(url, "http://") &&
  71. !strings.HasPrefix(url, "https://") {
  72. matches := dataURLPattern.FindStringSubmatch(url)
  73. if len(matches) == 3 {
  74. return "image/" + matches[1], matches[2], nil
  75. }
  76. return "", "", errors.New("download image error: not an image url")
  77. }
  78. req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
  79. if err != nil {
  80. return "", "", err
  81. }
  82. resp, err := http.DefaultClient.Do(req)
  83. if err != nil {
  84. return "", "", err
  85. }
  86. defer resp.Body.Close()
  87. if resp.StatusCode != http.StatusOK {
  88. return "", "", fmt.Errorf("download image error: status code: %d", resp.StatusCode)
  89. }
  90. buf, err := common.GetResponseBodyLimit(resp, MaxImageSize)
  91. if err != nil {
  92. return "", "", err
  93. }
  94. contentType := resp.Header.Get("Content-Type")
  95. if !IsImageURL(contentType) {
  96. contentType = http.DetectContentType(buf)
  97. if !IsImageURL(contentType) {
  98. return "", "", errors.New("download iamge error: not an image")
  99. }
  100. }
  101. return TrimImageContentType(contentType), base64.StdEncoding.EncodeToString(buf), nil
  102. }
  103. var reg = regexp.MustCompile(`^data:image/([^;]+);base64,`)
  104. func GetImageSizeFromBase64(encoded string) (width, height int, err error) {
  105. decoded, err := base64.StdEncoding.DecodeString(reg.ReplaceAllString(encoded, ""))
  106. if err != nil {
  107. return 0, 0, err
  108. }
  109. img, _, err := image.DecodeConfig(bytes.NewReader(decoded))
  110. if err != nil {
  111. return 0, 0, err
  112. }
  113. return img.Width, img.Height, nil
  114. }
  115. func GetImageSize(image string) (width, height int, err error) {
  116. if strings.HasPrefix(image, "data:image/") {
  117. return GetImageSizeFromBase64(image)
  118. }
  119. return GetImageSizeFromURL(image)
  120. }