123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- package imagemeta
- import (
- "bufio"
- "bytes"
- "encoding/binary"
- "io"
- "github.com/imgproxy/imgproxy/v3/imagetype"
- )
- var (
- tiffLeHeader = []byte("II\x2A\x00")
- tiffBeHeader = []byte("MM\x00\x2A")
- )
- const (
- tiffDtByte = 1
- tiffDtShort = 3
- tiffDtLong = 4
- tiffImageWidth = 256
- tiffImageLength = 257
- )
- type tiffReader interface {
- io.Reader
- Discard(n int) (discarded int, err error)
- }
- func asTiffReader(r io.Reader) tiffReader {
- if rr, ok := r.(tiffReader); ok {
- return rr
- }
- return bufio.NewReader(r)
- }
- func DecodeTiffMeta(rr io.Reader) (Meta, error) {
- var (
- tmp [12]byte
- byteOrder binary.ByteOrder
- )
- r := asTiffReader(rr)
- if _, err := io.ReadFull(r, tmp[:8]); err != nil {
- return nil, err
- }
- switch {
- case bytes.Equal(tiffLeHeader, tmp[0:4]):
- byteOrder = binary.LittleEndian
- case bytes.Equal(tiffBeHeader, tmp[0:4]):
- byteOrder = binary.BigEndian
- default:
- return nil, newFormatError("TIFF", "malformed header")
- }
- ifdOffset := int(byteOrder.Uint32(tmp[4:8]))
- if _, err := r.Discard(ifdOffset - 8); err != nil {
- return nil, err
- }
- if _, err := io.ReadFull(r, tmp[0:2]); err != nil {
- return nil, err
- }
- numItems := int(byteOrder.Uint16(tmp[0:2]))
- var width, height int
- for i := 0; i < numItems; i++ {
- if _, err := io.ReadFull(r, tmp[:]); err != nil {
- return nil, err
- }
- tag := byteOrder.Uint16(tmp[0:2])
- if tag != tiffImageWidth && tag != tiffImageLength {
- continue
- }
- datatype := byteOrder.Uint16(tmp[2:4])
- var value int
- switch datatype {
- case tiffDtByte:
- value = int(tmp[8])
- case tiffDtShort:
- value = int(byteOrder.Uint16(tmp[8:10]))
- case tiffDtLong:
- value = int(byteOrder.Uint32(tmp[8:12]))
- default:
- return nil, newFormatError("TIFF", "unsupported IFD entry datatype")
- }
- if tag == tiffImageWidth {
- width = value
- } else {
- height = value
- }
- if width > 0 && height > 0 {
- return &meta{
- format: imagetype.TIFF,
- width: width,
- height: height,
- }, nil
- }
- }
- return nil, newFormatError("TIFF", "image dimensions are not specified")
- }
- func init() {
- RegisterFormat(string(tiffLeHeader), DecodeTiffMeta)
- RegisterFormat(string(tiffBeHeader), DecodeTiffMeta)
- }
|