@@ -2,96 +2,119 @@ package imagemeta
22
33import (
44 "encoding/binary"
5+ "io"
56)
67
78type imageDecoderJPEG struct {
89 * baseStreamingDecoder
910}
1011
11- func (e * imageDecoderJPEG ) decode () ( err error ) {
12+ func (e * imageDecoderJPEG ) decode () error {
1213 // JPEG SOI marker.
13- var soi uint16
14- if soi , err = e . read2E (); err != nil {
14+ soi , err := e . read2E ()
15+ if err != nil {
1516 return nil
1617 }
18+
1719 if soi != markerSOI {
18- return
20+ return nil
1921 }
2022
21- findMarker := func (markerToFind uint16 ) int {
22- for {
23- var marker , length uint16
24- if marker , err = e .read2E (); err != nil {
25- return - 1
26- }
27- if length , err = e .read2E (); err != nil {
28- return - 1
29- }
23+ // These are the sources we support.
24+ sourceSet := TagSourceEXIF | TagSourceIPTC | TagSourceXMP
25+ // Remove sources that are not requested.
26+ sourceSet = sourceSet & e .opts .Sources
3027
31- // All JPEG markers begin with 0xff.
32- if marker >> 8 != 0xff {
33- return - 1
34- }
28+ for {
29+ if sourceSet .IsZero () {
30+ // Done.
31+ return nil
32+ }
33+ marker := e .read2 ()
34+ if e .isEOF {
35+ return nil
36+ }
3537
36- if marker == markerToFind {
37- return int ( length )
38- }
38+ if marker == 0 {
39+ continue
40+ }
3941
40- if length < 2 {
41- return - 1
42- }
42+ if marker == markerSOS {
43+ // Start of scan. We're done.
44+ return nil
45+ }
4346
44- e .skip (int64 (length - 2 ))
47+ // Read the 16-bit length of the segment. The value includes the 2 bytes for the
48+ // length itself, so we subtract 2 to get the number of remaining bytes.
49+ length := e .read2 ()
50+ if length < 2 {
51+ return ErrInvalidFormat
4552 }
46- }
53+ length -= 2
4754
48- if e .opts .Sources .Has (TagSourceEXIF ) {
49- pos := e .pos ()
50- if length := findMarker (markerAPP1 ); length > 0 {
51- err := func () error {
52- r , err := e .bufferedReader (length )
53- if err != nil {
54- return err
55- }
56- defer r .Close ()
57- exifr := newMetaDecoderEXIF (r , e .opts .HandleTag )
58-
59- header := exifr .read4 ()
60- if header != exifHeader {
61- return err
62- }
63- exifr .skip (2 )
64- if err := exifr .decode (); err != nil {
65- return err
66- }
67- return nil
68-
69- }()
70-
71- if err != nil {
55+ if marker == markerApp1EXIF && sourceSet .Has (TagSourceEXIF ) {
56+ sourceSet = sourceSet .Remove (TagSourceEXIF )
57+ if err := e .handleEXIF (int (length )); err != nil {
7258 return err
7359 }
60+ continue
61+ }
7462
63+ if marker == markerApp13 && sourceSet .Has (TagSourceIPTC ) {
64+ sourceSet = sourceSet .Remove (TagSourceIPTC )
65+ if err := e .handleIPTC (int (length )); err != nil {
66+ return err
67+ }
68+ continue
7569 }
76- e .seek (pos )
77- }
7870
79- if e .opts .Sources .Has (TagSourceIPTC ) {
80- // EXIF may be stored in a different order, but IPTC is always big-endian.
81- e .byteOrder = binary .BigEndian
82- if length := findMarker (markerApp13 ); length > 0 {
83- if err := func () error {
84- r , err := e .bufferedReader (length )
85- if err != nil {
86- return err
87- }
88- defer r .Close ()
89- dec := newMetaDecoderIPTC (r , e .opts .HandleTag )
90- return dec .decode ()
91- }(); err != nil {
71+ if marker == markerrApp1XMP && sourceSet .Has (TagSourceXMP ) {
72+ sourceSet = sourceSet .Remove (TagSourceXMP )
73+ const xmpIDLen = 29
74+ if length < xmpIDLen {
75+ return ErrInvalidFormat
76+ }
77+ e .skip (int64 (xmpIDLen ))
78+ length -= xmpIDLen
79+ r := io .LimitReader (e .r , int64 (length ))
80+ if err := decodeXMP (r , e .opts .HandleTag ); err != nil {
9281 return err
9382 }
83+ continue
9484 }
85+
86+ e .skip (int64 (length ))
87+ }
88+ }
89+
90+ func (e * imageDecoderJPEG ) handleIPTC (length int ) error {
91+ // EXIF may be stored in a different order, but IPTC is always big-endian.
92+ e .byteOrder = binary .BigEndian
93+ r , err := e .bufferedReader (length )
94+ if err != nil {
95+ return err
96+ }
97+ defer r .Close ()
98+ dec := newMetaDecoderIPTC (r , e .opts .HandleTag )
99+ return dec .decode ()
100+ }
101+
102+ func (e * imageDecoderJPEG ) handleEXIF (length int ) error {
103+ r , err := e .bufferedReader (length )
104+ if err != nil {
105+ return err
106+ }
107+ defer r .Close ()
108+ exifr := newMetaDecoderEXIF (r , e .opts .HandleTag )
109+
110+ header := exifr .read4 ()
111+ if header != exifHeader {
112+ return err
113+ }
114+ exifr .skip (2 )
115+ if err := exifr .decode (); err != nil {
116+ return err
95117 }
96118 return nil
119+
97120}
0 commit comments