tiff.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. type TiffFormatError string
  31. func (e TiffFormatError) Error() string { return "invalid TIFF format: " + string(e) }
  32. func DecodeTiffMeta(rr io.Reader) (Meta, error) {
  33. var (
  34. tmp [12]byte
  35. byteOrder binary.ByteOrder
  36. )
  37. r := asTiffReader(rr)
  38. if _, err := io.ReadFull(r, tmp[:8]); err != nil {
  39. return nil, err
  40. }
  41. switch {
  42. case bytes.Equal(tiffLeHeader, tmp[0:4]):
  43. byteOrder = binary.LittleEndian
  44. case bytes.Equal(tiffBeHeader, tmp[0:4]):
  45. byteOrder = binary.BigEndian
  46. default:
  47. return nil, TiffFormatError("malformed header")
  48. }
  49. ifdOffset := int(byteOrder.Uint32(tmp[4:8]))
  50. if _, err := r.Discard(ifdOffset - 8); err != nil {
  51. return nil, err
  52. }
  53. if _, err := io.ReadFull(r, tmp[0:2]); err != nil {
  54. return nil, err
  55. }
  56. numItems := int(byteOrder.Uint16(tmp[0:2]))
  57. var width, height int
  58. for i := 0; i < numItems; i++ {
  59. if _, err := io.ReadFull(r, tmp[:]); err != nil {
  60. return nil, err
  61. }
  62. tag := byteOrder.Uint16(tmp[0:2])
  63. if tag != tiffImageWidth && tag != tiffImageLength {
  64. continue
  65. }
  66. datatype := byteOrder.Uint16(tmp[2:4])
  67. var value int
  68. switch datatype {
  69. case tiffDtByte:
  70. value = int(tmp[9])
  71. case tiffDtShort:
  72. value = int(byteOrder.Uint16(tmp[8:10]))
  73. case tiffDtLong:
  74. value = int(byteOrder.Uint32(tmp[8:12]))
  75. default:
  76. return nil, TiffFormatError("unsupported IFD entry datatype")
  77. }
  78. if tag == tiffImageWidth {
  79. width = value
  80. } else {
  81. height = value
  82. }
  83. if width > 0 && height > 0 {
  84. return &meta{
  85. format: imagetype.TIFF,
  86. width: width,
  87. height: height,
  88. }, nil
  89. }
  90. }
  91. return nil, TiffFormatError("image dimensions are not specified")
  92. }
  93. func init() {
  94. RegisterFormat(string(tiffLeHeader), DecodeTiffMeta)
  95. RegisterFormat(string(tiffBeHeader), DecodeTiffMeta)
  96. }