source: josm/trunk/src/com/drew/metadata/TagDescriptor.java@ 8855

Last change on this file since 8855 was 8132, checked in by Don-vip, 9 years ago

fix #11162 - update to metadata-extractor 2.7.2

File size: 8.7 KB
Line 
1/*
2 * Copyright 2002-2015 Drew Noakes
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * More information about this project is available at:
17 *
18 * https://drewnoakes.com/code/exif/
19 * https://github.com/drewnoakes/metadata-extractor
20 */
21package com.drew.metadata;
22
23import com.drew.lang.Rational;
24import com.drew.lang.StringUtil;
25import com.drew.lang.annotations.NotNull;
26import com.drew.lang.annotations.Nullable;
27
28import java.io.UnsupportedEncodingException;
29import java.lang.reflect.Array;
30import java.util.ArrayList;
31import java.util.Date;
32import java.util.List;
33
34/**
35 * Base class for all tag descriptor classes. Implementations are responsible for
36 * providing the human-readable string representation of tag values stored in a directory.
37 * The directory is provided to the tag descriptor via its constructor.
38 *
39 * @author Drew Noakes https://drewnoakes.com
40 */
41public class TagDescriptor<T extends Directory>
42{
43 @NotNull
44 protected final T _directory;
45
46 public TagDescriptor(@NotNull T directory)
47 {
48 _directory = directory;
49 }
50
51 /**
52 * Returns a descriptive value of the specified tag for this image.
53 * Where possible, known values will be substituted here in place of the raw
54 * tokens actually kept in the metadata segment. If no substitution is
55 * available, the value provided by <code>getString(tagType)</code> will be returned.
56 *
57 * @param tagType the tag to find a description for
58 * @return a description of the image's value for the specified tag, or
59 * <code>null</code> if the tag hasn't been defined.
60 */
61 @Nullable
62 public String getDescription(int tagType)
63 {
64 Object object = _directory.getObject(tagType);
65
66 if (object == null)
67 return null;
68
69 // special presentation for long arrays
70 if (object.getClass().isArray()) {
71 final int length = Array.getLength(object);
72 if (length > 16) {
73 final String componentTypeName = object.getClass().getComponentType().getName();
74 return String.format("[%d %s%s]", length, componentTypeName, length == 1 ? "" : "s");
75 }
76 }
77
78 // no special handling required, so use default conversion to a string
79 return _directory.getString(tagType);
80 }
81
82 /**
83 * Takes a series of 4 bytes from the specified offset, and converts these to a
84 * well-known version number, where possible.
85 * <p>
86 * Two different formats are processed:
87 * <ul>
88 * <li>[30 32 31 30] -&gt; 2.10</li>
89 * <li>[0 1 0 0] -&gt; 1.00</li>
90 * </ul>
91 *
92 * @param components the four version values
93 * @param majorDigits the number of components to be
94 * @return the version as a string of form "2.10" or null if the argument cannot be converted
95 */
96 @Nullable
97 public static String convertBytesToVersionString(@Nullable int[] components, final int majorDigits)
98 {
99 if (components == null)
100 return null;
101 StringBuilder version = new StringBuilder();
102 for (int i = 0; i < 4 && i < components.length; i++) {
103 if (i == majorDigits)
104 version.append('.');
105 char c = (char)components[i];
106 if (c < '0')
107 c += '0';
108 if (i == 0 && c == '0')
109 continue;
110 version.append(c);
111 }
112 return version.toString();
113 }
114
115 @Nullable
116 protected String getVersionBytesDescription(final int tagType, int majorDigits)
117 {
118 int[] values = _directory.getIntArray(tagType);
119 return values == null ? null : convertBytesToVersionString(values, majorDigits);
120 }
121
122 @Nullable
123 protected String getIndexedDescription(final int tagType, @NotNull String... descriptions)
124 {
125 return getIndexedDescription(tagType, 0, descriptions);
126 }
127
128 @Nullable
129 protected String getIndexedDescription(final int tagType, final int baseIndex, @NotNull String... descriptions)
130 {
131 final Integer index = _directory.getInteger(tagType);
132 if (index == null)
133 return null;
134 final int arrayIndex = index - baseIndex;
135 if (arrayIndex >= 0 && arrayIndex < descriptions.length) {
136 String description = descriptions[arrayIndex];
137 if (description != null)
138 return description;
139 }
140 return "Unknown (" + index + ")";
141 }
142
143 @Nullable
144 protected String getByteLengthDescription(final int tagType)
145 {
146 byte[] bytes = _directory.getByteArray(tagType);
147 if (bytes == null)
148 return null;
149 return String.format("(%d byte%s)", bytes.length, bytes.length == 1 ? "" : "s");
150 }
151
152 @Nullable
153 protected String getSimpleRational(final int tagType)
154 {
155 Rational value = _directory.getRational(tagType);
156 if (value == null)
157 return null;
158 return value.toSimpleString(true);
159 }
160
161 @Nullable
162 protected String getDecimalRational(final int tagType, final int decimalPlaces)
163 {
164 Rational value = _directory.getRational(tagType);
165 if (value == null)
166 return null;
167 return String.format("%." + decimalPlaces + "f", value.doubleValue());
168 }
169
170 @Nullable
171 protected String getFormattedInt(final int tagType, @NotNull final String format)
172 {
173 Integer value = _directory.getInteger(tagType);
174 if (value == null)
175 return null;
176 return String.format(format, value);
177 }
178
179 @Nullable
180 protected String getFormattedFloat(final int tagType, @NotNull final String format)
181 {
182 Float value = _directory.getFloatObject(tagType);
183 if (value == null)
184 return null;
185 return String.format(format, value);
186 }
187
188 @Nullable
189 protected String getFormattedString(final int tagType, @NotNull final String format)
190 {
191 String value = _directory.getString(tagType);
192 if (value == null)
193 return null;
194 return String.format(format, value);
195 }
196
197 @Nullable
198 protected String getEpochTimeDescription(final int tagType)
199 {
200 // TODO have observed a byte[8] here which is likely some kind of date (ticks as long?)
201 Long value = _directory.getLongObject(tagType);
202 if (value==null)
203 return null;
204 return new Date(value).toString();
205 }
206
207 /**
208 * LSB first. Labels may be null, a String, or a String[2] with (low label,high label) values.
209 */
210 @Nullable
211 protected String getBitFlagDescription(final int tagType, @NotNull final Object... labels)
212 {
213 Integer value = _directory.getInteger(tagType);
214
215 if (value == null)
216 return null;
217
218 List<String> parts = new ArrayList<String>();
219
220 int bitIndex = 0;
221 while (labels.length > bitIndex) {
222 Object labelObj = labels[bitIndex];
223 if (labelObj != null) {
224 boolean isBitSet = (value & 1) == 1;
225 if (labelObj instanceof String[]) {
226 String[] labelPair = (String[])labelObj;
227 assert(labelPair.length == 2);
228 parts.add(labelPair[isBitSet ? 1 : 0]);
229 } else if (isBitSet && labelObj instanceof String) {
230 parts.add((String)labelObj);
231 }
232 }
233 value >>= 1;
234 bitIndex++;
235 }
236
237 return StringUtil.join(parts, ", ");
238 }
239
240 @Nullable
241 protected String get7BitStringFromBytes(final int tagType)
242 {
243 final byte[] bytes = _directory.getByteArray(tagType);
244
245 if (bytes == null)
246 return null;
247
248 int length = bytes.length;
249 for (int index = 0; index < bytes.length; index++) {
250 int i = bytes[index] & 0xFF;
251 if (i == 0 || i > 0x7F) {
252 length = index;
253 break;
254 }
255 }
256
257 return new String(bytes, 0, length);
258 }
259
260 @Nullable
261 protected String getAsciiStringFromBytes(int tag)
262 {
263 byte[] values = _directory.getByteArray(tag);
264
265 if (values == null)
266 return null;
267
268 try {
269 return new String(values, "ASCII").trim();
270 } catch (UnsupportedEncodingException e) {
271 return null;
272 }
273 }
274}
Note: See TracBrowser for help on using the repository browser.