tiff.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. package imagemeta
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/binary"
  6. "io"
  7. "github.com/imgproxy/imgproxy/v3/imagetype"
  8. )
  9. var (
  10. tiffLeHeader = []byte("II\x2A\x00")
  11. tiffBeHeader = []byte("MM\x00\x2A")
  12. )
  13. const (
  14. tiffDtByte = 1
  15. tiffDtShort = 3
  16. tiffDtLong = 4
  17. tiffImageWidth = 256
  18. tiffImageLength = 257
  19. )
  20. type tiffReader interface {
  21. io.Reader
  22. Discard(n int) (discarded int, err error)
  23. }
  24. func asTiffReader(r io.Reader) tiffReader {
  25. if rr, ok := r.(tiffReader); ok {
  26. return rr
  27. }
  28. return bufio.NewReader(r)
  29. }
  30. func DecodeTiffMeta(rr io.Reader) (Meta, error) {
  31. var (
  32. tmp [12]byte
  33. byteOrder binary.ByteOrder
  34. )
  35. r := asTiffReader(rr)
  36. if _, err := io.ReadFull(r, tmp[:8]); err != nil {
  37. return nil, err
  38. }
  39. switch {
  40. case bytes.Equal(tiffLeHeader, tmp[0:4]):
  41. byteOrder = binary.LittleEndian
  42. case bytes.Equal(tiffBeHeader, tmp[0:4]):
  43. byteOrder = binary.BigEndian
  44. default:
  45. return nil, newFormatError("TIFF", "malformed header")
  46. }
  47. ifdOffset := int(byteOrder.Uint32(tmp[4:8]))
  48. if _, err := r.Discard(ifdOffset - 8); err != nil {
  49. return nil, err
  50. }
  51. if _, err := io.ReadFull(r, tmp[0:2]); err != nil {
  52. return nil, err
  53. }
  54. numItems := int(byteOrder.Uint16(tmp[0:2]))
  55. var width, height int
  56. for i := 0; i < numItems; i++ {
  57. if _, err := io.ReadFull(r, tmp[:]); err != nil {
  58. return nil, err
  59. }
  60. tag := byteOrder.Uint16(tmp[0:2])
  61. if tag != tiffImageWidth && tag != tiffImageLength {
  62. continue
  63. }
  64. datatype := byteOrder.Uint16(tmp[2:4])
  65. var value int
  66. switch datatype {
  67. case tiffDtByte:
  68. value = int(tmp[8])
  69. case tiffDtShort:
  70. value = int(byteOrder.Uint16(tmp[8:10]))
  71. case tiffDtLong:
  72. value = int(byteOrder.Uint32(tmp[8:12]))
  73. default:
  74. return nil, newFormatError("TIFF", "unsupported IFD entry datatype")
  75. }
  76. if tag == tiffImageWidth {
  77. width = value
  78. } else {
  79. height = value
  80. }
  81. if width > 0 && height > 0 {
  82. return &meta{
  83. format: imagetype.TIFF,
  84. width: width,
  85. height: height,
  86. }, nil
  87. }
  88. }
  89. return nil, newFormatError("TIFF", "image dimensions are not specified")
  90. }
  91. func init() {
  92. RegisterFormat(string(tiffLeHeader), DecodeTiffMeta)
  93. RegisterFormat(string(tiffBeHeader), DecodeTiffMeta)
  94. }