mirror of https://github.com/dsoprea/go-exif.git
152 lines
3.1 KiB
Go
152 lines
3.1 KiB
Go
package exifundefined
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"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
|
|
}
|
|
|
|
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 interface{}, 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.SetUnknownValueType(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(
|
|
TagA302CfaPattern{},
|
|
CodecA302CfaPattern{})
|
|
|
|
registerDecoder(
|
|
exifcommon.IfdPathStandardExif,
|
|
0xa302,
|
|
CodecA302CfaPattern{})
|
|
}
|