...

Source file src/github.com/dsoprea/go-exif/v3/undefined/exif_A20C_spatial_frequency_response.go

Documentation: github.com/dsoprea/go-exif/v3/undefined

     1  package exifundefined
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"encoding/binary"
     8  
     9  	"github.com/dsoprea/go-logging"
    10  
    11  	"github.com/dsoprea/go-exif/v3/common"
    12  )
    13  
    14  type TagA20CSpatialFrequencyResponse struct {
    15  	Columns     uint16
    16  	Rows        uint16
    17  	ColumnNames []string
    18  	Values      []exifcommon.Rational
    19  }
    20  
    21  func (TagA20CSpatialFrequencyResponse) EncoderName() string {
    22  	return "CodecA20CSpatialFrequencyResponse"
    23  }
    24  
    25  func (sfr TagA20CSpatialFrequencyResponse) String() string {
    26  	return fmt.Sprintf("CodecA20CSpatialFrequencyResponse<COLUMNS=(%d) ROWS=(%d)>", sfr.Columns, sfr.Rows)
    27  }
    28  
    29  type CodecA20CSpatialFrequencyResponse struct {
    30  }
    31  
    32  func (CodecA20CSpatialFrequencyResponse) Encode(value interface{}, byteOrder binary.ByteOrder) (encoded []byte, unitCount uint32, err error) {
    33  	defer func() {
    34  		if state := recover(); state != nil {
    35  			err = log.Wrap(state.(error))
    36  		}
    37  	}()
    38  
    39  	// TODO(dustin): Add test.
    40  
    41  	sfr, ok := value.(TagA20CSpatialFrequencyResponse)
    42  	if ok == false {
    43  		log.Panicf("can only encode a TagA20CSpatialFrequencyResponse")
    44  	}
    45  
    46  	b := new(bytes.Buffer)
    47  
    48  	err = binary.Write(b, byteOrder, sfr.Columns)
    49  	log.PanicIf(err)
    50  
    51  	err = binary.Write(b, byteOrder, sfr.Rows)
    52  	log.PanicIf(err)
    53  
    54  	// Write columns.
    55  
    56  	for _, name := range sfr.ColumnNames {
    57  		_, err := b.WriteString(name)
    58  		log.PanicIf(err)
    59  
    60  		err = b.WriteByte(0)
    61  		log.PanicIf(err)
    62  	}
    63  
    64  	// Write values.
    65  
    66  	ve := exifcommon.NewValueEncoder(byteOrder)
    67  
    68  	ed, err := ve.Encode(sfr.Values)
    69  	log.PanicIf(err)
    70  
    71  	_, err = b.Write(ed.Encoded)
    72  	log.PanicIf(err)
    73  
    74  	encoded = b.Bytes()
    75  
    76  	// TODO(dustin): Confirm this size against the specification.
    77  
    78  	return encoded, uint32(len(encoded)), nil
    79  }
    80  
    81  func (CodecA20CSpatialFrequencyResponse) Decode(valueContext *exifcommon.ValueContext) (value EncodeableValue, err error) {
    82  	defer func() {
    83  		if state := recover(); state != nil {
    84  			err = log.Wrap(state.(error))
    85  		}
    86  	}()
    87  
    88  	// TODO(dustin): Add test using known good data.
    89  
    90  	byteOrder := valueContext.ByteOrder()
    91  
    92  	valueContext.SetUndefinedValueType(exifcommon.TypeByte)
    93  
    94  	valueBytes, err := valueContext.ReadBytes()
    95  	log.PanicIf(err)
    96  
    97  	sfr := TagA20CSpatialFrequencyResponse{}
    98  
    99  	sfr.Columns = byteOrder.Uint16(valueBytes[0:2])
   100  	sfr.Rows = byteOrder.Uint16(valueBytes[2:4])
   101  
   102  	columnNames := make([]string, sfr.Columns)
   103  
   104  	// startAt is where the current column name starts.
   105  	startAt := 4
   106  
   107  	// offset is our current position.
   108  	offset := 4
   109  
   110  	currentColumnNumber := uint16(0)
   111  
   112  	for currentColumnNumber < sfr.Columns {
   113  		if valueBytes[offset] == 0 {
   114  			columnName := string(valueBytes[startAt:offset])
   115  			if len(columnName) == 0 {
   116  				log.Panicf("SFR column (%d) has zero length", currentColumnNumber)
   117  			}
   118  
   119  			columnNames[currentColumnNumber] = columnName
   120  			currentColumnNumber++
   121  
   122  			offset++
   123  			startAt = offset
   124  			continue
   125  		}
   126  
   127  		offset++
   128  	}
   129  
   130  	sfr.ColumnNames = columnNames
   131  
   132  	rawRationalBytes := valueBytes[offset:]
   133  
   134  	rationalSize := exifcommon.TypeRational.Size()
   135  	if len(rawRationalBytes)%rationalSize > 0 {
   136  		log.Panicf("SFR rationals not aligned: (%d) %% (%d) > 0", len(rawRationalBytes), rationalSize)
   137  	}
   138  
   139  	rationalCount := len(rawRationalBytes) / rationalSize
   140  
   141  	parser := new(exifcommon.Parser)
   142  
   143  	items, err := parser.ParseRationals(rawRationalBytes, uint32(rationalCount), byteOrder)
   144  	log.PanicIf(err)
   145  
   146  	sfr.Values = items
   147  
   148  	return sfr, nil
   149  }
   150  
   151  func init() {
   152  	registerEncoder(
   153  		TagA20CSpatialFrequencyResponse{},
   154  		CodecA20CSpatialFrequencyResponse{})
   155  
   156  	registerDecoder(
   157  		exifcommon.IfdExifStandardIfdIdentity.UnindexedString(),
   158  		0xa20c,
   159  		CodecA20CSpatialFrequencyResponse{})
   160  }
   161  

View as plain text