mirror of
https://github.com/dsoprea/go-exif.git
synced 2025-05-31 11:41:57 +00:00
This allows us to pass around individual tokens that we can use to generate IDs, names, and qualified and non-qualified IFD paths, rather than [necessarily] having to pass or store them individually. The previous global variables were strings. Now they are IfdIdentity structs and have been renamed to be more accurate (in general, as well as for this). The previous variables have been kept but are now just assigned to the newer variables. This is backwards-compatibility that will be removed in the future.
161 lines
3.4 KiB
Go
161 lines
3.4 KiB
Go
package exifundefined
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"encoding/binary"
|
|
|
|
"github.com/dsoprea/go-logging"
|
|
|
|
"github.com/dsoprea/go-exif/v2/common"
|
|
)
|
|
|
|
type TagA20CSpatialFrequencyResponse struct {
|
|
Columns uint16
|
|
Rows uint16
|
|
ColumnNames []string
|
|
Values []exifcommon.Rational
|
|
}
|
|
|
|
func (TagA20CSpatialFrequencyResponse) EncoderName() string {
|
|
return "CodecA20CSpatialFrequencyResponse"
|
|
}
|
|
|
|
func (sfr TagA20CSpatialFrequencyResponse) String() string {
|
|
return fmt.Sprintf("CodecA20CSpatialFrequencyResponse<COLUMNS=(%d) ROWS=(%d)>", sfr.Columns, sfr.Rows)
|
|
}
|
|
|
|
type CodecA20CSpatialFrequencyResponse struct {
|
|
}
|
|
|
|
func (CodecA20CSpatialFrequencyResponse) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
|
|
defer func() {
|
|
if state := recover(); state != nil {
|
|
err = log.Wrap(state.(error))
|
|
}
|
|
}()
|
|
|
|
// TODO(dustin): Add test.
|
|
|
|
sfr, ok := value.(TagA20CSpatialFrequencyResponse)
|
|
if ok == false {
|
|
log.Panicf("can only encode a TagA20CSpatialFrequencyResponse")
|
|
}
|
|
|
|
b := new(bytes.Buffer)
|
|
|
|
err = binary.Write(b, byteOrder, sfr.Columns)
|
|
log.PanicIf(err)
|
|
|
|
err = binary.Write(b, byteOrder, sfr.Rows)
|
|
log.PanicIf(err)
|
|
|
|
// Write columns.
|
|
|
|
for _, name := range sfr.ColumnNames {
|
|
_, err := b.WriteString(name)
|
|
log.PanicIf(err)
|
|
|
|
err = b.WriteByte(0)
|
|
log.PanicIf(err)
|
|
}
|
|
|
|
// Write values.
|
|
|
|
ve := exifcommon.NewValueEncoder(byteOrder)
|
|
|
|
ed, err := ve.Encode(sfr.Values)
|
|
log.PanicIf(err)
|
|
|
|
_, err = b.Write(ed.Encoded)
|
|
log.PanicIf(err)
|
|
|
|
encoded = b.Bytes()
|
|
|
|
// TODO(dustin): Confirm this size against the specification.
|
|
|
|
return encoded, uint32(len(encoded)), nil
|
|
}
|
|
|
|
func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
|
|
defer func() {
|
|
if state := recover(); state != nil {
|
|
err = log.Wrap(state.(error))
|
|
}
|
|
}()
|
|
|
|
// TODO(dustin): Add test using known good data.
|
|
|
|
byteOrder := valueContext.ByteOrder()
|
|
|
|
valueContext.SetUndefinedValueType(exifcommon.TypeByte)
|
|
|
|
valueBytes, err := valueContext.ReadBytes()
|
|
log.PanicIf(err)
|
|
|
|
sfr := TagA20CSpatialFrequencyResponse{}
|
|
|
|
sfr.Columns = byteOrder.Uint16(valueBytes[0:2])
|
|
sfr.Rows = byteOrder.Uint16(valueBytes[2:4])
|
|
|
|
columnNames := make([]string, sfr.Columns)
|
|
|
|
// startAt is where the current column name starts.
|
|
startAt := 4
|
|
|
|
// offset is our current position.
|
|
offset := 4
|
|
|
|
currentColumnNumber := uint16(0)
|
|
|
|
for currentColumnNumber < sfr.Columns {
|
|
if valueBytes[offset] == 0 {
|
|
columnName := string(valueBytes[startAt:offset])
|
|
if len(columnName) == 0 {
|
|
log.Panicf("SFR column (%d) has zero length", currentColumnNumber)
|
|
}
|
|
|
|
columnNames[currentColumnNumber] = columnName
|
|
currentColumnNumber++
|
|
|
|
offset++
|
|
startAt = offset
|
|
continue
|
|
}
|
|
|
|
offset++
|
|
}
|
|
|
|
sfr.ColumnNames = columnNames
|
|
|
|
rawRationalBytes := valueBytes[offset:]
|
|
|
|
rationalSize := exifcommon.TypeRational.Size()
|
|
if len(rawRationalBytes)%rationalSize > 0 {
|
|
log.Panicf("SFR rationals not aligned: (%d) %% (%d) > 0", len(rawRationalBytes), rationalSize)
|
|
}
|
|
|
|
rationalCount := len(rawRationalBytes) / rationalSize
|
|
|
|
parser := new(exifcommon.Parser)
|
|
|
|
items, err := parser.ParseRationals(rawRationalBytes, uint32(rationalCount), byteOrder)
|
|
log.PanicIf(err)
|
|
|
|
sfr.Values = items
|
|
|
|
return sfr, nil
|
|
}
|
|
|
|
func init() {
|
|
registerEncoder(
|
|
TagA20CSpatialFrequencyResponse{},
|
|
CodecA20CSpatialFrequencyResponse{})
|
|
|
|
registerDecoder(
|
|
exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
|
|
0xa20c,
|
|
CodecA20CSpatialFrequencyResponse{})
|
|
}
|