image_data.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package imagedata
  2. import (
  3. "bytes"
  4. "context"
  5. "io"
  6. "sync"
  7. "github.com/imgproxy/imgproxy/v3/asyncbuffer"
  8. "github.com/imgproxy/imgproxy/v3/imagetype"
  9. )
  10. var (
  11. Watermark ImageData
  12. )
  13. // ImageData represents the data of an image that can be read from a source.
  14. // Please note that this interface can be backed by any reader, including lazy AsyncBuffer.
  15. // There is no other way to guarantee that the data is read without errors except reading it till EOF.
  16. type ImageData interface {
  17. io.Closer // Close closes the image data and releases any resources held by it
  18. Reader() io.ReadSeeker // Reader returns a new ReadSeeker for the image data
  19. Format() imagetype.Type // Format returns the image format from the metadata (shortcut)
  20. Size() (int, error) // Size returns the size of the image data in bytes
  21. Error() error // Error returns any error that occurred during reading data from source
  22. // AddCancel attaches a cancel function to the image data.
  23. // Please note that Cancel functions must be idempotent: for instance, an implementation
  24. // could wrap cancel into sync.Once.
  25. AddCancel(context.CancelFunc)
  26. }
  27. // imageDataBytes represents image data stored in a byte slice in memory
  28. type imageDataBytes struct {
  29. format imagetype.Type
  30. data []byte
  31. cancel []context.CancelFunc
  32. cancelOnce sync.Once
  33. }
  34. // imageDataAsyncBuffer is a struct that implements the ImageData interface backed by an AsyncBuffer
  35. type imageDataAsyncBuffer struct {
  36. b *asyncbuffer.AsyncBuffer
  37. format imagetype.Type
  38. desc string
  39. cancel []context.CancelFunc
  40. cancelOnce sync.Once
  41. }
  42. // Close closes the image data and releases any resources held by it
  43. func (d *imageDataBytes) Close() error {
  44. d.cancelOnce.Do(func() {
  45. for _, cancel := range d.cancel {
  46. cancel()
  47. }
  48. })
  49. return nil
  50. }
  51. // Format returns the image format based on the metadata
  52. func (d *imageDataBytes) Format() imagetype.Type {
  53. return d.format
  54. }
  55. // Reader returns an io.ReadSeeker for the image data
  56. func (d *imageDataBytes) Reader() io.ReadSeeker {
  57. return bytes.NewReader(d.data)
  58. }
  59. // Size returns the size of the image data in bytes.
  60. func (d *imageDataBytes) Size() (int, error) {
  61. return len(d.data), nil
  62. }
  63. // AddCancel attaches a cancel function to the image data
  64. func (d *imageDataBytes) AddCancel(cancel context.CancelFunc) {
  65. d.cancel = append(d.cancel, cancel)
  66. }
  67. func (d *imageDataBytes) Error() error {
  68. // No error handling for in-memory data, return nil
  69. return nil
  70. }
  71. // Reader returns a ReadSeeker for the image data
  72. func (d *imageDataAsyncBuffer) Reader() io.ReadSeeker {
  73. return d.b.Reader()
  74. }
  75. // Close closes the response body (hence, response) and the async buffer itself
  76. func (d *imageDataAsyncBuffer) Close() error {
  77. d.cancelOnce.Do(func() {
  78. d.b.Close()
  79. for _, cancel := range d.cancel {
  80. cancel()
  81. }
  82. })
  83. return nil
  84. }
  85. // Format returns the image format from the metadata
  86. func (d *imageDataAsyncBuffer) Format() imagetype.Type {
  87. return d.format
  88. }
  89. // Size returns the size of the image data in bytes.
  90. // It waits for the async buffer to finish reading.
  91. func (d *imageDataAsyncBuffer) Size() (int, error) {
  92. return d.b.Wait()
  93. }
  94. // AddCancel attaches a cancel function to the image data
  95. func (d *imageDataAsyncBuffer) AddCancel(cancel context.CancelFunc) {
  96. d.cancel = append(d.cancel, cancel)
  97. }
  98. // Error returns any error that occurred during reading data from
  99. // async buffer or the underlying source.
  100. func (d *imageDataAsyncBuffer) Error() error {
  101. if err := d.b.Error(); err != nil {
  102. return wrapDownloadError(err, d.desc)
  103. }
  104. return nil
  105. }