image_data.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package imagedata
  2. import (
  3. "context"
  4. "encoding/base64"
  5. "fmt"
  6. "net/http"
  7. "net/http/cookiejar"
  8. "os"
  9. "strings"
  10. "sync"
  11. "github.com/imgproxy/imgproxy/v3/config"
  12. "github.com/imgproxy/imgproxy/v3/ierrors"
  13. "github.com/imgproxy/imgproxy/v3/imagetype"
  14. )
  15. var (
  16. Watermark *ImageData
  17. FallbackImage *ImageData
  18. )
  19. type ImageData struct {
  20. Type imagetype.Type
  21. Data []byte
  22. Headers map[string]string
  23. cancel context.CancelFunc
  24. cancelOnce sync.Once
  25. }
  26. func (d *ImageData) Close() {
  27. d.cancelOnce.Do(func() {
  28. if d.cancel != nil {
  29. d.cancel()
  30. }
  31. })
  32. }
  33. func (d *ImageData) SetCancel(cancel context.CancelFunc) {
  34. d.cancel = cancel
  35. }
  36. func Init() error {
  37. initRead()
  38. if err := initDownloading(); err != nil {
  39. return err
  40. }
  41. if err := loadWatermark(); err != nil {
  42. return err
  43. }
  44. if err := loadFallbackImage(); err != nil {
  45. return err
  46. }
  47. return nil
  48. }
  49. func loadWatermark() (err error) {
  50. if len(config.WatermarkData) > 0 {
  51. Watermark, err = FromBase64(config.WatermarkData, "watermark")
  52. return
  53. }
  54. if len(config.WatermarkPath) > 0 {
  55. Watermark, err = FromFile(config.WatermarkPath, "watermark")
  56. return
  57. }
  58. if len(config.WatermarkURL) > 0 {
  59. Watermark, err = Download(config.WatermarkURL, "watermark", nil, nil)
  60. return
  61. }
  62. return nil
  63. }
  64. func loadFallbackImage() (err error) {
  65. switch {
  66. case len(config.FallbackImageData) > 0:
  67. FallbackImage, err = FromBase64(config.FallbackImageData, "fallback image")
  68. case len(config.FallbackImagePath) > 0:
  69. FallbackImage, err = FromFile(config.FallbackImagePath, "fallback image")
  70. case len(config.FallbackImageURL) > 0:
  71. FallbackImage, err = Download(config.FallbackImageURL, "fallback image", nil, nil)
  72. default:
  73. FallbackImage, err = nil, nil
  74. }
  75. if FallbackImage != nil && err == nil && config.FallbackImageTTL > 0 {
  76. if FallbackImage.Headers == nil {
  77. FallbackImage.Headers = make(map[string]string)
  78. }
  79. FallbackImage.Headers["Fallback-Image"] = "1"
  80. }
  81. return err
  82. }
  83. func FromBase64(encoded, desc string) (*ImageData, error) {
  84. dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(encoded))
  85. size := 4 * (len(encoded)/3 + 1)
  86. imgdata, err := readAndCheckImage(dec, size)
  87. if err != nil {
  88. return nil, fmt.Errorf("Can't decode %s: %s", desc, err)
  89. }
  90. return imgdata, nil
  91. }
  92. func FromFile(path, desc string) (*ImageData, error) {
  93. f, err := os.Open(path)
  94. if err != nil {
  95. return nil, fmt.Errorf("Can't read %s: %s", desc, err)
  96. }
  97. fi, err := f.Stat()
  98. if err != nil {
  99. return nil, fmt.Errorf("Can't read %s: %s", desc, err)
  100. }
  101. imgdata, err := readAndCheckImage(f, int(fi.Size()))
  102. if err != nil {
  103. return nil, fmt.Errorf("Can't read %s: %s", desc, err)
  104. }
  105. return imgdata, nil
  106. }
  107. func Download(imageURL, desc string, header http.Header, jar *cookiejar.Jar) (*ImageData, error) {
  108. imgdata, err := download(imageURL, header, jar)
  109. if err != nil {
  110. if nmErr, ok := err.(*ErrorNotModified); ok {
  111. nmErr.Message = fmt.Sprintf("Can't download %s: %s", desc, nmErr.Message)
  112. return nil, nmErr
  113. }
  114. return nil, ierrors.WrapWithPrefix(err, 1, fmt.Sprintf("Can't download %s", desc))
  115. }
  116. return imgdata, nil
  117. }