tiff.go 2.2 KB

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