jpeg.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. package imagemeta
  2. import (
  3. "bufio"
  4. "io"
  5. "github.com/imgproxy/imgproxy/v3/imagetype"
  6. )
  7. const (
  8. // https://www.disktuna.com/list-of-jpeg-markers/
  9. jpegSof0Marker = 0xc0 // Start Of Frame (Baseline Sequential).
  10. jpegSof1Marker = 0xc1 // Start Of Frame (Extended Sequential DCT)
  11. jpegSof2Marker = 0xc2 // Start Of Frame (Progressive DCT )
  12. jpegSof3Marker = 0xc3 // Start Of Frame (Lossless sequential)
  13. jpegSof5Marker = 0xc5 // Start Of Frame (Differential sequential DCT)
  14. jpegSof6Marker = 0xc6 // Start Of Frame (Differential progressive DCT)
  15. jpegSof7Marker = 0xc7 // Start Of Frame (Differential lossless sequential)
  16. jpegSof9Marker = 0xc9 // Start Of Frame (Extended sequential DCT, Arithmetic coding)
  17. jpegSof10Marker = 0xca // Start Of Frame (Progressive DCT, Arithmetic coding)
  18. jpegSof11Marker = 0xcb // Start Of Frame (Lossless sequential, Arithmetic coding)
  19. jpegSof13Marker = 0xcd // Start Of Frame (Differential sequential DCT, Arithmetic coding)
  20. jpegSof14Marker = 0xce // Start Of Frame (Differential progressive DCT, Arithmetic coding)
  21. jpegSof15Marker = 0xcf // Start Of Frame (Differential lossless sequential, Arithmetic coding).
  22. jpegRst0Marker = 0xd0 // ReSTart (0).
  23. jpegRst7Marker = 0xd7 // ReSTart (7).
  24. jpegSoiMarker = 0xd8 // Start Of Image.
  25. jpegEoiMarker = 0xd9 // End Of Image.
  26. jpegSosMarker = 0xda // Start Of Scan.
  27. )
  28. type jpegReader interface {
  29. io.Reader
  30. ReadByte() (byte, error)
  31. Discard(n int) (discarded int, err error)
  32. }
  33. func asJpegReader(r io.Reader) jpegReader {
  34. if rr, ok := r.(jpegReader); ok {
  35. return rr
  36. }
  37. return bufio.NewReader(r)
  38. }
  39. func DecodeJpegMeta(rr io.Reader) (Meta, error) {
  40. var tmp [512]byte
  41. r := asJpegReader(rr)
  42. if _, err := io.ReadFull(r, tmp[:2]); err != nil {
  43. return nil, err
  44. }
  45. if tmp[0] != 0xff || tmp[1] != jpegSoiMarker {
  46. return nil, newFormatError("JPEG", "missing SOI marker")
  47. }
  48. for {
  49. _, err := io.ReadFull(r, tmp[:2])
  50. if err != nil {
  51. return nil, err
  52. }
  53. // This is not a segment, continue searching
  54. for tmp[0] != 0xff {
  55. tmp[0] = tmp[1]
  56. tmp[1], err = r.ReadByte()
  57. if err != nil {
  58. return nil, err
  59. }
  60. }
  61. marker := tmp[1]
  62. if marker == 0 {
  63. // Treat "\xff\x00" as extraneous data.
  64. continue
  65. }
  66. // Marker can be preceded by fill bytes
  67. for marker == 0xff {
  68. marker, err = r.ReadByte()
  69. if err != nil {
  70. return nil, err
  71. }
  72. }
  73. if marker == jpegEoiMarker { // End Of Image.
  74. return nil, newFormatError("JPEG", "missing SOF marker")
  75. }
  76. if marker == jpegSoiMarker {
  77. return nil, newFormatError("JPEG", "two SOI markers")
  78. }
  79. if jpegRst0Marker <= marker && marker <= jpegRst7Marker {
  80. continue
  81. }
  82. if _, err = io.ReadFull(r, tmp[:2]); err != nil {
  83. return nil, err
  84. }
  85. n := int(tmp[0])<<8 + int(tmp[1]) - 2
  86. if n <= 0 {
  87. // We should fail here, but libvips is more tolerant to this, so, continue
  88. continue
  89. }
  90. switch marker {
  91. case jpegSof0Marker, jpegSof1Marker, jpegSof2Marker, jpegSof3Marker, jpegSof5Marker,
  92. jpegSof6Marker, jpegSof7Marker, jpegSof9Marker, jpegSof10Marker, jpegSof11Marker,
  93. jpegSof13Marker, jpegSof14Marker, jpegSof15Marker:
  94. if _, err := io.ReadFull(r, tmp[:5]); err != nil {
  95. return nil, err
  96. }
  97. // We only support 8-bit precision.
  98. if tmp[0] != 8 {
  99. return nil, newFormatError("JPEG", "unsupported precision")
  100. }
  101. return &meta{
  102. format: imagetype.JPEG,
  103. width: int(tmp[3])<<8 + int(tmp[4]),
  104. height: int(tmp[1])<<8 + int(tmp[2]),
  105. }, nil
  106. case jpegSosMarker:
  107. return nil, newFormatError("JPEG", "missing SOF marker")
  108. }
  109. // Skip any other uninteresting segments
  110. if _, err := r.Discard(n); err != nil {
  111. return nil, err
  112. }
  113. }
  114. }
  115. func init() {
  116. RegisterFormat("\xff\xd8", DecodeJpegMeta)
  117. }