Files
query-orchestration/vendor/github.com/chai2010/tiff/tiff_ifd_entry.go
T
Jay Brown b71a28d3c0 Merged in feature/support-more-types (pull request #219)
support new types for import

* tests pass

* missing file

* bug fixes
2026-03-31 17:40:42 +00:00

552 lines
14 KiB
Go

// Copyright 2014 <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package tiff
import (
"bytes"
"encoding/binary"
"fmt"
"strings"
)
type IFDEntry struct {
Header *Header
Tag TagType
DataType DataType
Count int
Offset int64
Data []byte
}
type byIFDEntry []*IFDEntry
func (d byIFDEntry) Len() int { return len(d) }
func (d byIFDEntry) Less(i, j int) bool { return d[i].Tag < d[j].Tag }
func (d byIFDEntry) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
func NewIFDEntry(hdr *Header, tag TagType, dataType DataType, data interface{}) (p *IFDEntry) {
p = &IFDEntry{
Header: hdr,
Tag: tag,
DataType: dataType,
}
p.SetValue(data)
return p
}
func (p *IFDEntry) Valid() bool {
if p == nil {
return false
}
if !p.Header.Valid() || !p.Tag.Valid() || !p.DataType.Valid() {
return false
}
if p.Count <= 0 || len(p.Data) == 0 {
return false
}
return true
}
func (p *IFDEntry) Bytes() (entry, data []byte) {
if p.Header.TiffType == TiffType_ClassicTIFF {
var buf bytes.Buffer
binary.Write(&buf, p.Header.ByteOrder, uint16(p.Tag))
binary.Write(&buf, p.Header.ByteOrder, uint16(p.DataType))
binary.Write(&buf, p.Header.ByteOrder, uint32(p.Count))
offsetOrData := make([]byte, 4)
if len(p.Data) > 4 {
p.Header.ByteOrder.PutUint32(offsetOrData, uint32(p.Offset))
data = p.Data
} else {
copy(offsetOrData[:], p.Data)
}
buf.Write(offsetOrData)
entry = buf.Bytes()
return
} else {
var buf bytes.Buffer
binary.Write(&buf, p.Header.ByteOrder, uint16(p.Tag))
binary.Write(&buf, p.Header.ByteOrder, uint16(p.DataType))
binary.Write(&buf, p.Header.ByteOrder, uint64(p.Count))
offsetOrData := make([]byte, 8)
if len(p.Data) > 8 {
p.Header.ByteOrder.PutUint64(offsetOrData, uint64(p.Offset))
data = p.Data
} else {
copy(offsetOrData[:], p.Data)
}
buf.Write(offsetOrData)
entry = buf.Bytes()
return
}
}
func (p *IFDEntry) GetInts() []int64 {
switch p.DataType {
case DataType_Byte:
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
dst[i] = int64(int8(p.Data[i]))
}
return dst
case DataType_SByte:
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
dst[i] = int64(uint8(p.Data[i]))
}
return dst
case DataType_Short:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v uint16
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
case DataType_SShort:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v int16
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
case DataType_Long, DataType_IFD:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v uint32
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
case DataType_SLong:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v int32
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
case DataType_Long8, DataType_IFD8:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v uint64
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
case DataType_SLong8:
r := bytes.NewReader(p.Data)
dst := make([]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v int64
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = int64(v)
}
return dst
}
return nil
}
func (p *IFDEntry) GetFloats() []float64 {
switch p.DataType {
case DataType_Float:
r := bytes.NewReader(p.Data)
dst := make([]float64, p.Count)
for i := 0; i < p.Count; i++ {
var v float32
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = float64(v)
}
return dst
case DataType_Double:
r := bytes.NewReader(p.Data)
dst := make([]float64, p.Count)
for i := 0; i < p.Count; i++ {
var v float64
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i] = float64(v)
}
return dst
case DataType_Rational, DataType_SRational:
rats := p.GetRationals()
floats := make([]float64, len(rats))
for i := 0; i < len(rats); i++ {
floats[i] = float64(rats[i][0]) / float64(rats[i][1])
}
return floats
default:
ints := p.GetInts()
floats := make([]float64, len(ints))
for i := 0; i < len(ints); i++ {
floats[i] = float64(ints[i])
}
return floats
}
}
func (p *IFDEntry) GetRationals() [][2]int64 {
switch p.DataType {
case DataType_Rational:
r := bytes.NewReader(p.Data)
dst := make([][2]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v [2]uint32
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i][0] = int64(v[0])
dst[i][1] = int64(v[1])
}
return dst
case DataType_SRational:
r := bytes.NewReader(p.Data)
dst := make([][2]int64, p.Count)
for i := 0; i < p.Count; i++ {
var v [2]int32
if err := binary.Read(r, p.Header.ByteOrder, &v); err != nil {
return nil
}
dst[i][0] = int64(v[0])
dst[i][1] = int64(v[1])
}
return dst
}
return nil
}
func (p *IFDEntry) GetString() string {
switch p.DataType {
case DataType_ASCII:
if idx := bytes.Index(p.Data, []byte("\000")); idx >= 0 {
return string(p.Data[:idx])
}
return string(p.Data)
}
return ""
}
func (p *IFDEntry) GetValue() interface{} {
panic("TODO")
}
func (p *IFDEntry) GetUndefined(value interface{}) interface{} {
if p.DataType != DataType_Undefined {
return nil
}
if err := binary.Read(bytes.NewReader(p.Data), p.Header.ByteOrder, value); err != nil {
return nil
}
return value
}
func (p *IFDEntry) SetInts(value ...int64) (err error) {
if p.DataType == DataType_Nil {
if p.Header.IsBigTiff() {
p.DataType = DataType_Long8
} else {
p.DataType = DataType_Long
}
}
switch p.DataType {
case DataType_Byte:
tmp := make([]uint8, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = uint8(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_SByte:
tmp := make([]int8, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = int8(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_Short:
tmp := make([]uint16, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = uint16(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_SShort:
tmp := make([]int16, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = int16(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_Long, DataType_IFD:
tmp := make([]uint32, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = uint32(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_SLong:
tmp := make([]int32, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = int32(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_Long8, DataType_IFD8:
tmp := make([]uint64, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = uint64(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_SLong8:
tmp := make([]int64, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = int64(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
}
return
}
func (p *IFDEntry) SetFloats(value ...float64) (err error) {
if p.DataType == DataType_Nil {
p.DataType = DataType_Double
}
switch p.DataType {
case DataType_Float:
tmp := make([]float32, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i] = float32(value[i])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_Double:
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, value); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(value)
}
return
}
func (p *IFDEntry) SetRationals(value ...[2]int64) (err error) {
if p.DataType == DataType_Nil {
p.DataType = DataType_Rational
}
switch p.DataType {
case DataType_Rational:
tmp := make([][2]uint32, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i][0] = uint32(value[i][0])
tmp[i][1] = uint32(value[i][1])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
case DataType_SRational:
tmp := make([][2]int32, len(value))
for i := 0; i < len(tmp); i++ {
tmp[i][0] = int32(value[i][0])
tmp[i][1] = int32(value[i][1])
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, tmp); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(tmp)
}
return
}
func (p *IFDEntry) SetString(value string) (err error) {
if p.DataType == DataType_Nil {
p.DataType = DataType_ASCII
}
switch p.DataType {
case DataType_ASCII:
if idx := strings.Index(value, "\000"); idx >= 0 {
value = value[:idx]
}
p.Data = make([]byte, len(value)+1)
copy(p.Data, []byte(value))
p.Data[len(value)] = 0 // +NULL
p.Count = len(p.Data) + 1
}
return
}
func (p *IFDEntry) SetUndefined(value interface{}) (err error) {
if p.DataType == DataType_Nil {
p.DataType = DataType_Undefined
}
if p.DataType != DataType_Undefined {
return
}
var buf bytes.Buffer
if err = binary.Write(&buf, p.Header.ByteOrder, value); err != nil {
return
}
p.Data = buf.Bytes()
p.Count = len(p.Data)
return
}
func (p *IFDEntry) SetValue(value interface{}) (err error) {
panic("TODO")
}
func (p *IFDEntry) isOnlyOneValue() bool {
nums, _ := _TagType_NumsTable[p.Tag]
return len(nums) == 1 && nums[0] == 1
}
func (p *IFDEntry) String() string {
switch p.Tag {
case TagType_NewSubfileType:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_NewSubfileType(v[0]))
}
case TagType_SubfileType:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_SubfileType(v[0]))
}
case TagType_ImageWidth:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, int(v[0]))
}
case TagType_ImageLength:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, int(v[0]))
}
case TagType_Compression:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_CompressionType(v[0]))
}
case TagType_PhotometricInterpretation:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_PhotometricType(v[0]))
}
case TagType_RowsPerStrip:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, int(v[0]))
}
case TagType_SamplesPerPixel:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, int(v[0]))
}
case TagType_ResolutionUnit:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_ResolutionUnitType(v[0]))
}
case TagType_Predictor:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_PredictorType(v[0]))
}
case TagType_StripOffsets, TagType_TileOffsets, TagType_FreeOffsets:
return fmt.Sprintf("%v(%v): %#08x", p.Tag, p.DataType, p.GetInts())
case TagType_SampleFormat:
if v := p.GetInts(); len(v) == 1 {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, TagValue_SampleFormatType(v[0]))
}
}
switch {
case p.DataType.IsIntType():
switch p.DataType {
case DataType_IFD, DataType_IFD8:
return fmt.Sprintf("%v(%v): %#08x", p.Tag, p.DataType, p.GetInts())
}
if v := p.GetInts(); len(v) == 1 && p.isOnlyOneValue() {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v[0])
} else {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v)
}
case p.DataType.IsFloatType():
if v := p.GetFloats(); len(v) == 1 && p.isOnlyOneValue() {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v[0])
} else {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v)
}
case p.DataType.IsRationalType():
if v := p.GetRationals(); len(v) == 1 && p.isOnlyOneValue() {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v[0])
} else {
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, v)
}
case p.DataType.IsStringType():
return fmt.Sprintf("%v(%v): %q", p.Tag, p.DataType, p.GetString())
default:
return fmt.Sprintf("%v(%v): %v", p.Tag, p.DataType, p.Data)
}
}