1 | /*
|
---|
2 | * Copyright 2002-2016 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 | */
|
---|
21 | package com.drew.metadata.exif.makernotes;
|
---|
22 |
|
---|
23 | import com.drew.lang.Rational;
|
---|
24 | import com.drew.lang.annotations.NotNull;
|
---|
25 | import com.drew.lang.annotations.Nullable;
|
---|
26 | import com.drew.metadata.TagDescriptor;
|
---|
27 |
|
---|
28 | import static com.drew.metadata.exif.makernotes.FujifilmMakernoteDirectory.*;
|
---|
29 |
|
---|
30 | /**
|
---|
31 | * Provides human-readable string representations of tag values stored in a {@link FujifilmMakernoteDirectory}.
|
---|
32 | * <p>
|
---|
33 | * Fujifilm added their Makernote tag from the Year 2000's models (e.g.Finepix1400,
|
---|
34 | * Finepix4700). It uses IFD format and start from ASCII character 'FUJIFILM', and next 4
|
---|
35 | * bytes (value 0x000c) points the offset to first IFD entry.
|
---|
36 | * <pre><code>
|
---|
37 | * :0000: 46 55 4A 49 46 49 4C 4D-0C 00 00 00 0F 00 00 00 :0000: FUJIFILM........
|
---|
38 | * :0010: 07 00 04 00 00 00 30 31-33 30 00 10 02 00 08 00 :0010: ......0130......
|
---|
39 | * </code></pre>
|
---|
40 | * There are two big differences to the other manufacturers.
|
---|
41 | * <ul>
|
---|
42 | * <li>Fujifilm's Exif data uses Motorola align, but Makernote ignores it and uses Intel align.</li>
|
---|
43 | * <li>
|
---|
44 | * The other manufacturer's Makernote counts the "offset to data" from the first byte of TIFF header
|
---|
45 | * (same as the other IFD), but Fujifilm counts it from the first byte of Makernote itself.
|
---|
46 | * </li>
|
---|
47 | * </ul>
|
---|
48 | *
|
---|
49 | * @author Drew Noakes https://drewnoakes.com
|
---|
50 | */
|
---|
51 | public class FujifilmMakernoteDescriptor extends TagDescriptor<FujifilmMakernoteDirectory>
|
---|
52 | {
|
---|
53 | public FujifilmMakernoteDescriptor(@NotNull FujifilmMakernoteDirectory directory)
|
---|
54 | {
|
---|
55 | super(directory);
|
---|
56 | }
|
---|
57 |
|
---|
58 | @Override
|
---|
59 | @Nullable
|
---|
60 | public String getDescription(int tagType)
|
---|
61 | {
|
---|
62 | switch (tagType) {
|
---|
63 | case TAG_MAKERNOTE_VERSION:
|
---|
64 | return getMakernoteVersionDescription();
|
---|
65 | case TAG_SHARPNESS:
|
---|
66 | return getSharpnessDescription();
|
---|
67 | case TAG_WHITE_BALANCE:
|
---|
68 | return getWhiteBalanceDescription();
|
---|
69 | case TAG_COLOR_SATURATION:
|
---|
70 | return getColorSaturationDescription();
|
---|
71 | case TAG_TONE:
|
---|
72 | return getToneDescription();
|
---|
73 | case TAG_CONTRAST:
|
---|
74 | return getContrastDescription();
|
---|
75 | case TAG_NOISE_REDUCTION:
|
---|
76 | return getNoiseReductionDescription();
|
---|
77 | case TAG_HIGH_ISO_NOISE_REDUCTION:
|
---|
78 | return getHighIsoNoiseReductionDescription();
|
---|
79 | case TAG_FLASH_MODE:
|
---|
80 | return getFlashModeDescription();
|
---|
81 | case TAG_FLASH_EV:
|
---|
82 | return getFlashExposureValueDescription();
|
---|
83 | case TAG_MACRO:
|
---|
84 | return getMacroDescription();
|
---|
85 | case TAG_FOCUS_MODE:
|
---|
86 | return getFocusModeDescription();
|
---|
87 | case TAG_SLOW_SYNC:
|
---|
88 | return getSlowSyncDescription();
|
---|
89 | case TAG_PICTURE_MODE:
|
---|
90 | return getPictureModeDescription();
|
---|
91 | case TAG_EXR_AUTO:
|
---|
92 | return getExrAutoDescription();
|
---|
93 | case TAG_EXR_MODE:
|
---|
94 | return getExrModeDescription();
|
---|
95 | case TAG_AUTO_BRACKETING:
|
---|
96 | return getAutoBracketingDescription();
|
---|
97 | case TAG_FINE_PIX_COLOR:
|
---|
98 | return getFinePixColorDescription();
|
---|
99 | case TAG_BLUR_WARNING:
|
---|
100 | return getBlurWarningDescription();
|
---|
101 | case TAG_FOCUS_WARNING:
|
---|
102 | return getFocusWarningDescription();
|
---|
103 | case TAG_AUTO_EXPOSURE_WARNING:
|
---|
104 | return getAutoExposureWarningDescription();
|
---|
105 | case TAG_DYNAMIC_RANGE:
|
---|
106 | return getDynamicRangeDescription();
|
---|
107 | case TAG_FILM_MODE:
|
---|
108 | return getFilmModeDescription();
|
---|
109 | case TAG_DYNAMIC_RANGE_SETTING:
|
---|
110 | return getDynamicRangeSettingDescription();
|
---|
111 | default:
|
---|
112 | return super.getDescription(tagType);
|
---|
113 | }
|
---|
114 | }
|
---|
115 |
|
---|
116 | @Nullable
|
---|
117 | private String getMakernoteVersionDescription()
|
---|
118 | {
|
---|
119 | return getVersionBytesDescription(TAG_MAKERNOTE_VERSION, 2);
|
---|
120 | }
|
---|
121 |
|
---|
122 | @Nullable
|
---|
123 | public String getSharpnessDescription()
|
---|
124 | {
|
---|
125 | final Integer value = _directory.getInteger(TAG_SHARPNESS);
|
---|
126 | if (value == null)
|
---|
127 | return null;
|
---|
128 | switch (value) {
|
---|
129 | case 1: return "Softest";
|
---|
130 | case 2: return "Soft";
|
---|
131 | case 3: return "Normal";
|
---|
132 | case 4: return "Hard";
|
---|
133 | case 5: return "Hardest";
|
---|
134 | case 0x82: return "Medium Soft";
|
---|
135 | case 0x84: return "Medium Hard";
|
---|
136 | case 0x8000: return "Film Simulation";
|
---|
137 | case 0xFFFF: return "N/A";
|
---|
138 | default:
|
---|
139 | return "Unknown (" + value + ")";
|
---|
140 | }
|
---|
141 | }
|
---|
142 |
|
---|
143 | @Nullable
|
---|
144 | public String getWhiteBalanceDescription()
|
---|
145 | {
|
---|
146 | final Integer value = _directory.getInteger(TAG_WHITE_BALANCE);
|
---|
147 | if (value == null)
|
---|
148 | return null;
|
---|
149 | switch (value) {
|
---|
150 | case 0x000: return "Auto";
|
---|
151 | case 0x100: return "Daylight";
|
---|
152 | case 0x200: return "Cloudy";
|
---|
153 | case 0x300: return "Daylight Fluorescent";
|
---|
154 | case 0x301: return "Day White Fluorescent";
|
---|
155 | case 0x302: return "White Fluorescent";
|
---|
156 | case 0x303: return "Warm White Fluorescent";
|
---|
157 | case 0x304: return "Living Room Warm White Fluorescent";
|
---|
158 | case 0x400: return "Incandescence";
|
---|
159 | case 0x500: return "Flash";
|
---|
160 | case 0xf00: return "Custom White Balance";
|
---|
161 | case 0xf01: return "Custom White Balance 2";
|
---|
162 | case 0xf02: return "Custom White Balance 3";
|
---|
163 | case 0xf03: return "Custom White Balance 4";
|
---|
164 | case 0xf04: return "Custom White Balance 5";
|
---|
165 | case 0xff0: return "Kelvin";
|
---|
166 | default:
|
---|
167 | return "Unknown (" + value + ")";
|
---|
168 | }
|
---|
169 | }
|
---|
170 |
|
---|
171 | @Nullable
|
---|
172 | public String getColorSaturationDescription()
|
---|
173 | {
|
---|
174 | final Integer value = _directory.getInteger(TAG_COLOR_SATURATION);
|
---|
175 | if (value == null)
|
---|
176 | return null;
|
---|
177 | switch (value) {
|
---|
178 | case 0x000: return "Normal";
|
---|
179 | case 0x080: return "Medium High";
|
---|
180 | case 0x100: return "High";
|
---|
181 | case 0x180: return "Medium Low";
|
---|
182 | case 0x200: return "Low";
|
---|
183 | case 0x300: return "None (B&W)";
|
---|
184 | case 0x301: return "B&W Green Filter";
|
---|
185 | case 0x302: return "B&W Yellow Filter";
|
---|
186 | case 0x303: return "B&W Blue Filter";
|
---|
187 | case 0x304: return "B&W Sepia";
|
---|
188 | case 0x8000: return "Film Simulation";
|
---|
189 | default:
|
---|
190 | return "Unknown (" + value + ")";
|
---|
191 | }
|
---|
192 | }
|
---|
193 |
|
---|
194 | @Nullable
|
---|
195 | public String getToneDescription()
|
---|
196 | {
|
---|
197 | final Integer value = _directory.getInteger(TAG_TONE);
|
---|
198 | if (value == null)
|
---|
199 | return null;
|
---|
200 | switch (value) {
|
---|
201 | case 0x000: return "Normal";
|
---|
202 | case 0x080: return "Medium High";
|
---|
203 | case 0x100: return "High";
|
---|
204 | case 0x180: return "Medium Low";
|
---|
205 | case 0x200: return "Low";
|
---|
206 | case 0x300: return "None (B&W)";
|
---|
207 | case 0x8000: return "Film Simulation";
|
---|
208 | default:
|
---|
209 | return "Unknown (" + value + ")";
|
---|
210 | }
|
---|
211 | }
|
---|
212 |
|
---|
213 | @Nullable
|
---|
214 | public String getContrastDescription()
|
---|
215 | {
|
---|
216 | final Integer value = _directory.getInteger(TAG_CONTRAST);
|
---|
217 | if (value == null)
|
---|
218 | return null;
|
---|
219 | switch (value) {
|
---|
220 | case 0x000: return "Normal";
|
---|
221 | case 0x100: return "High";
|
---|
222 | case 0x300: return "Low";
|
---|
223 | default:
|
---|
224 | return "Unknown (" + value + ")";
|
---|
225 | }
|
---|
226 | }
|
---|
227 |
|
---|
228 | @Nullable
|
---|
229 | public String getNoiseReductionDescription()
|
---|
230 | {
|
---|
231 | final Integer value = _directory.getInteger(TAG_NOISE_REDUCTION);
|
---|
232 | if (value == null)
|
---|
233 | return null;
|
---|
234 | switch (value) {
|
---|
235 | case 0x040: return "Low";
|
---|
236 | case 0x080: return "Normal";
|
---|
237 | case 0x100: return "N/A";
|
---|
238 | default:
|
---|
239 | return "Unknown (" + value + ")";
|
---|
240 | }
|
---|
241 | }
|
---|
242 |
|
---|
243 | @Nullable
|
---|
244 | public String getHighIsoNoiseReductionDescription()
|
---|
245 | {
|
---|
246 | final Integer value = _directory.getInteger(TAG_HIGH_ISO_NOISE_REDUCTION);
|
---|
247 | if (value == null)
|
---|
248 | return null;
|
---|
249 | switch (value) {
|
---|
250 | case 0x000: return "Normal";
|
---|
251 | case 0x100: return "Strong";
|
---|
252 | case 0x200: return "Weak";
|
---|
253 | default:
|
---|
254 | return "Unknown (" + value + ")";
|
---|
255 | }
|
---|
256 | }
|
---|
257 |
|
---|
258 | @Nullable
|
---|
259 | public String getFlashModeDescription()
|
---|
260 | {
|
---|
261 | return getIndexedDescription(
|
---|
262 | TAG_FLASH_MODE,
|
---|
263 | "Auto",
|
---|
264 | "On",
|
---|
265 | "Off",
|
---|
266 | "Red-eye Reduction",
|
---|
267 | "External"
|
---|
268 | );
|
---|
269 | }
|
---|
270 |
|
---|
271 | @Nullable
|
---|
272 | public String getFlashExposureValueDescription()
|
---|
273 | {
|
---|
274 | Rational value = _directory.getRational(TAG_FLASH_EV);
|
---|
275 | return value == null ? null : value.toSimpleString(false) + " EV (Apex)";
|
---|
276 | }
|
---|
277 |
|
---|
278 | @Nullable
|
---|
279 | public String getMacroDescription()
|
---|
280 | {
|
---|
281 | return getIndexedDescription(TAG_MACRO, "Off", "On");
|
---|
282 | }
|
---|
283 |
|
---|
284 | @Nullable
|
---|
285 | public String getFocusModeDescription()
|
---|
286 | {
|
---|
287 | return getIndexedDescription(TAG_FOCUS_MODE, "Auto Focus", "Manual Focus");
|
---|
288 | }
|
---|
289 |
|
---|
290 | @Nullable
|
---|
291 | public String getSlowSyncDescription()
|
---|
292 | {
|
---|
293 | return getIndexedDescription(TAG_SLOW_SYNC, "Off", "On");
|
---|
294 | }
|
---|
295 |
|
---|
296 | @Nullable
|
---|
297 | public String getPictureModeDescription()
|
---|
298 | {
|
---|
299 | final Integer value = _directory.getInteger(TAG_PICTURE_MODE);
|
---|
300 | if (value == null)
|
---|
301 | return null;
|
---|
302 | switch (value) {
|
---|
303 | case 0x000: return "Auto";
|
---|
304 | case 0x001: return "Portrait scene";
|
---|
305 | case 0x002: return "Landscape scene";
|
---|
306 | case 0x003: return "Macro";
|
---|
307 | case 0x004: return "Sports scene";
|
---|
308 | case 0x005: return "Night scene";
|
---|
309 | case 0x006: return "Program AE";
|
---|
310 | case 0x007: return "Natural Light";
|
---|
311 | case 0x008: return "Anti-blur";
|
---|
312 | case 0x009: return "Beach & Snow";
|
---|
313 | case 0x00a: return "Sunset";
|
---|
314 | case 0x00b: return "Museum";
|
---|
315 | case 0x00c: return "Party";
|
---|
316 | case 0x00d: return "Flower";
|
---|
317 | case 0x00e: return "Text";
|
---|
318 | case 0x00f: return "Natural Light & Flash";
|
---|
319 | case 0x010: return "Beach";
|
---|
320 | case 0x011: return "Snow";
|
---|
321 | case 0x012: return "Fireworks";
|
---|
322 | case 0x013: return "Underwater";
|
---|
323 | case 0x014: return "Portrait with Skin Correction";
|
---|
324 | // skip 0x015
|
---|
325 | case 0x016: return "Panorama";
|
---|
326 | case 0x017: return "Night (Tripod)";
|
---|
327 | case 0x018: return "Pro Low-light";
|
---|
328 | case 0x019: return "Pro Focus";
|
---|
329 | // skip 0x01a
|
---|
330 | case 0x01b: return "Dog Face Detection";
|
---|
331 | case 0x01c: return "Cat Face Detection";
|
---|
332 | case 0x100: return "Aperture priority AE";
|
---|
333 | case 0x200: return "Shutter priority AE";
|
---|
334 | case 0x300: return "Manual exposure";
|
---|
335 | default:
|
---|
336 | return "Unknown (" + value + ")";
|
---|
337 | }
|
---|
338 | }
|
---|
339 |
|
---|
340 | @Nullable
|
---|
341 | public String getExrAutoDescription()
|
---|
342 | {
|
---|
343 | return getIndexedDescription(TAG_EXR_AUTO, "Auto", "Manual");
|
---|
344 | }
|
---|
345 |
|
---|
346 | @Nullable
|
---|
347 | public String getExrModeDescription()
|
---|
348 | {
|
---|
349 | final Integer value = _directory.getInteger(TAG_EXR_MODE);
|
---|
350 | if (value == null)
|
---|
351 | return null;
|
---|
352 | switch (value) {
|
---|
353 | case 0x100: return "HR (High Resolution)";
|
---|
354 | case 0x200: return "SN (Signal to Noise Priority)";
|
---|
355 | case 0x300: return "DR (Dynamic Range Priority)";
|
---|
356 | default:
|
---|
357 | return "Unknown (" + value + ")";
|
---|
358 | }
|
---|
359 | }
|
---|
360 |
|
---|
361 | @Nullable
|
---|
362 | public String getAutoBracketingDescription()
|
---|
363 | {
|
---|
364 | return getIndexedDescription(
|
---|
365 | TAG_AUTO_BRACKETING,
|
---|
366 | "Off",
|
---|
367 | "On",
|
---|
368 | "No Flash & Flash"
|
---|
369 | );
|
---|
370 | }
|
---|
371 |
|
---|
372 | @Nullable
|
---|
373 | public String getFinePixColorDescription()
|
---|
374 | {
|
---|
375 | final Integer value = _directory.getInteger(TAG_FINE_PIX_COLOR);
|
---|
376 | if (value == null)
|
---|
377 | return null;
|
---|
378 | switch (value) {
|
---|
379 | case 0x00: return "Standard";
|
---|
380 | case 0x10: return "Chrome";
|
---|
381 | case 0x30: return "B&W";
|
---|
382 | default:
|
---|
383 | return "Unknown (" + value + ")";
|
---|
384 | }
|
---|
385 | }
|
---|
386 |
|
---|
387 | @Nullable
|
---|
388 | public String getBlurWarningDescription()
|
---|
389 | {
|
---|
390 | return getIndexedDescription(
|
---|
391 | TAG_BLUR_WARNING,
|
---|
392 | "No Blur Warning",
|
---|
393 | "Blur warning"
|
---|
394 | );
|
---|
395 | }
|
---|
396 |
|
---|
397 | @Nullable
|
---|
398 | public String getFocusWarningDescription()
|
---|
399 | {
|
---|
400 | return getIndexedDescription(
|
---|
401 | TAG_FOCUS_WARNING,
|
---|
402 | "Good Focus",
|
---|
403 | "Out Of Focus"
|
---|
404 | );
|
---|
405 | }
|
---|
406 |
|
---|
407 | @Nullable
|
---|
408 | public String getAutoExposureWarningDescription()
|
---|
409 | {
|
---|
410 | return getIndexedDescription(
|
---|
411 | TAG_AUTO_EXPOSURE_WARNING,
|
---|
412 | "AE Good",
|
---|
413 | "Over Exposed"
|
---|
414 | );
|
---|
415 | }
|
---|
416 |
|
---|
417 | @Nullable
|
---|
418 | public String getDynamicRangeDescription()
|
---|
419 | {
|
---|
420 | return getIndexedDescription(
|
---|
421 | TAG_DYNAMIC_RANGE,
|
---|
422 | 1,
|
---|
423 | "Standard",
|
---|
424 | null,
|
---|
425 | "Wide"
|
---|
426 | );
|
---|
427 | }
|
---|
428 |
|
---|
429 | @Nullable
|
---|
430 | public String getFilmModeDescription()
|
---|
431 | {
|
---|
432 | final Integer value = _directory.getInteger(TAG_FILM_MODE);
|
---|
433 | if (value == null)
|
---|
434 | return null;
|
---|
435 | switch (value) {
|
---|
436 | case 0x000: return "F0/Standard (Provia) ";
|
---|
437 | case 0x100: return "F1/Studio Portrait";
|
---|
438 | case 0x110: return "F1a/Studio Portrait Enhanced Saturation";
|
---|
439 | case 0x120: return "F1b/Studio Portrait Smooth Skin Tone (Astia)";
|
---|
440 | case 0x130: return "F1c/Studio Portrait Increased Sharpness";
|
---|
441 | case 0x200: return "F2/Fujichrome (Velvia)";
|
---|
442 | case 0x300: return "F3/Studio Portrait Ex";
|
---|
443 | case 0x400: return "F4/Velvia";
|
---|
444 | case 0x500: return "Pro Neg. Std";
|
---|
445 | case 0x501: return "Pro Neg. Hi";
|
---|
446 | default:
|
---|
447 | return "Unknown (" + value + ")";
|
---|
448 | }
|
---|
449 | }
|
---|
450 |
|
---|
451 | @Nullable
|
---|
452 | public String getDynamicRangeSettingDescription()
|
---|
453 | {
|
---|
454 | final Integer value = _directory.getInteger(TAG_DYNAMIC_RANGE_SETTING);
|
---|
455 | if (value == null)
|
---|
456 | return null;
|
---|
457 | switch (value) {
|
---|
458 | case 0x000: return "Auto (100-400%)";
|
---|
459 | case 0x001: return "Manual";
|
---|
460 | case 0x100: return "Standard (100%)";
|
---|
461 | case 0x200: return "Wide 1 (230%)";
|
---|
462 | case 0x201: return "Wide 2 (400%)";
|
---|
463 | case 0x8000: return "Film Simulation";
|
---|
464 | default:
|
---|
465 | return "Unknown (" + value + ")";
|
---|
466 | }
|
---|
467 | }
|
---|
468 | }
|
---|