]> gitweb.fperrin.net Git - GpsPrune.git/blob - src/tim/prune/jpeg/drew/ExifTiffHandler.java
Version 20.4, May 2021
[GpsPrune.git] / src / tim / prune / jpeg / drew / ExifTiffHandler.java
1 /*
2  * Copyright 2002-2015 Drew Noakes
3  *
4  * More information about this project is available at:
5  *
6  *    https://drewnoakes.com/code/exif/
7  *    https://github.com/drewnoakes/metadata-extractor
8  */
9 package tim.prune.jpeg.drew;
10
11 import tim.prune.jpeg.JpegData;
12
13 /**
14  * Implementation of TiffHandler used for handling TIFF tags according to the Exif standard.
15  *
16  * @author Drew Noakes https://drewnoakes.com
17  */
18 public class ExifTiffHandler
19 {
20         private JpegData _jpegData = null;
21         private long _thumbnailOffset = -1L, _thumbnailLength = -1L;
22
23         /** This tag is a pointer to the Exif SubIFD. */
24         private static final int DIR_EXIF_SUB_IFD_OFFSET = 0x8769;
25         /** This tag is a pointer to the Exif GPS IFD. */
26         private static final int DIR_GPS_INFO_OFFSET = 0x8825;
27
28         private static final int TAG_GPS_LATITUDE_REF  = 0x0001;
29         private static final int TAG_GPS_LATITUDE      = 0x0002;
30         private static final int TAG_GPS_LONGITUDE_REF = 0x0003;
31         private static final int TAG_GPS_LONGITUDE     = 0x0004;
32         private static final int TAG_GPS_ALTITUDE      = 0x0006;
33         private static final int TAG_GPS_BEARING       = 0x0011;
34
35         private static final int TAG_ORIENTATION       = 0x0112;
36         private static final int TAG_THUMBNAIL_OFFSET  = 0x0201;
37         private static final int TAG_THUMBNAIL_LENGTH  = 0x0202;
38
39         private static final int TAG_SUB_ORITIME       = 0x9003;
40         private static final int TAG_SUB_DIGITIME      = 0x9004;
41
42
43         /**
44          * Constructor
45          * @param jpegData data object to populate with received results
46          */
47         public ExifTiffHandler(JpegData jpegData)
48         {
49                 _jpegData = jpegData;
50                 _thumbnailOffset = _thumbnailLength = -1L;
51         }
52
53         public boolean isTagIfdPointer(int tagType)
54         {
55                 if (tagType == DIR_EXIF_SUB_IFD_OFFSET) {
56                         return true;
57                 } else if (tagType == DIR_GPS_INFO_OFFSET) {
58                         return true;
59                 }
60
61                 return false;
62         }
63
64         public void completed(final ByteArrayReader reader, final int tiffHeaderOffset)
65         {
66                 // after the extraction process, if we have the correct tags, we may be able to store thumbnail information
67                 if (_thumbnailOffset >= 0L && _thumbnailLength > 0L)
68                 {
69                         try {
70                                 byte[] thumbData = reader.getBytes(tiffHeaderOffset + (int) _thumbnailOffset, (int) _thumbnailLength);
71                                 if (thumbData != null)
72                                 {
73                                         byte[] thumbCopy = new byte[thumbData.length];
74                                         System.arraycopy(thumbData, 0, thumbCopy, 0, thumbData.length);
75                                         _jpegData.setThumbnailImage(thumbCopy);
76                                 }
77                         } catch (ExifException ex) {}
78                 }
79         }
80
81         public void setRationalArray(int tagId, Rational[] array)
82         {
83                 switch (tagId)
84                 {
85                         case TAG_GPS_LATITUDE:
86                                 _jpegData.setLatitude(new double[] {array[0].doubleValue(), array[1].doubleValue(),
87                                         array[2].convertToPositiveValue()});
88                                 break;
89                         case TAG_GPS_LONGITUDE:
90                                 _jpegData.setLongitude(new double[] {array[0].doubleValue(), array[1].doubleValue(),
91                                         array[2].convertToPositiveValue()});
92                                 break;
93                 }
94         }
95
96         public void setRational(int tagId, Rational rational)
97         {
98                 switch (tagId)
99                 {
100                         case TAG_GPS_ALTITUDE:
101                                 _jpegData.setAltitude(rational.intValue());
102                                 return;
103                         case TAG_GPS_BEARING:
104                                 _jpegData.setBearing(rational.doubleValue());
105                                 return;
106                 }
107                 // maybe it was an integer passed as a rational?
108                 if (rational.getDenominator() == 1L) {
109                         setIntegerValue(tagId, rational.intValue());
110                 }
111         }
112
113         public void setString(int tagId, String string)
114         {
115                 switch (tagId)
116                 {
117                         case TAG_SUB_ORITIME:
118                                 _jpegData.setOriginalTimestamp(string);
119                                 break;
120                         case TAG_SUB_DIGITIME:
121                                 _jpegData.setDigitizedTimestamp(string);
122                                 break;
123                         case TAG_GPS_LATITUDE_REF:
124                                 _jpegData.setLatitudeRef(string);
125                                 break;
126                         case TAG_GPS_LONGITUDE_REF:
127                                 _jpegData.setLongitudeRef(string);
128                                 break;
129                 }
130         }
131
132         public void setIntegerValue(int tagId, int intVal)
133         {
134                 switch (tagId)
135                 {
136                         case TAG_ORIENTATION:
137                                 _jpegData.setOrientationCode(intVal);
138                                 break;
139                         case TAG_THUMBNAIL_OFFSET:
140                                 _thumbnailOffset = intVal;
141                                 break;
142                         case TAG_THUMBNAIL_LENGTH:
143                                 _thumbnailLength = intVal;
144                                 break;
145                         case TAG_GPS_BEARING:
146                                 _jpegData.setBearing(intVal);
147                                 break;
148                 }
149         }
150
151
152         /**
153          * Decide, based on the directory id and the tag id, if we want to parse and process it
154          * @param inDirectoryId
155          * @param childTagId
156          * @return true if the tag should be parsed
157          */
158         public boolean isInterestingTag(int inDirectoryId, int childTagId)
159         {
160                 switch (inDirectoryId)
161                 {
162                         case DIR_GPS_INFO_OFFSET:
163                                 return true;
164                         case DIR_EXIF_SUB_IFD_OFFSET:
165                                 return childTagId == TAG_SUB_ORITIME
166                                         || childTagId == TAG_SUB_DIGITIME;
167                         case 0:
168                                 return childTagId == TAG_THUMBNAIL_OFFSET
169                                         || childTagId == TAG_THUMBNAIL_LENGTH
170                                         || childTagId == TAG_ORIENTATION;
171                 }
172                 return false;
173         }
174 }