Package: EXIF
EXIF
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
EXIF() |
|
|
|
|
|
||||||||||||||||||||
EXIF(Instant) |
|
|
|
|
|
||||||||||||||||||||
adjust(Instant, String) |
|
|
|
|
|
||||||||||||||||||||
getBitsPerSample() |
|
|
|
|
|
||||||||||||||||||||
getDateTimeAsDate() |
|
|
|
|
|
||||||||||||||||||||
getDateTimeDigitizedAsDate() |
|
|
|
|
|
||||||||||||||||||||
getDateTimeOriginalAsDate() |
|
|
|
|
|
||||||||||||||||||||
getFileSource() |
|
|
|
|
|
||||||||||||||||||||
getICCProfile() |
|
|
|
|
|
||||||||||||||||||||
getOriginalRawFileName() |
|
|
|
|
|
||||||||||||||||||||
getSceneType() |
|
|
|
|
|
||||||||||||||||||||
getUserComment() |
|
|
|
|
|
||||||||||||||||||||
getUserCommentAsString() |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeAsDate$0(Instant, String) |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeAsDate$1(Instant) |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeDigitizedAsDate$4(Instant, String) |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeDigitizedAsDate$5(Instant) |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeOriginalAsDate$2(Instant, String) |
|
|
|
|
|
||||||||||||||||||||
lambda$getDateTimeOriginalAsDate$3(Instant) |
|
|
|
|
|
||||||||||||||||||||
setDateTime(String) |
|
|
|
|
|
||||||||||||||||||||
setDateTimeAsDate(Instant) |
|
|
|
|
|
||||||||||||||||||||
setDateTimeDigitized(String) |
|
|
|
|
|
||||||||||||||||||||
setDateTimeDigitizedAsDate(Instant) |
|
|
|
|
|
||||||||||||||||||||
setDateTimeOriginal(String) |
|
|
|
|
|
||||||||||||||||||||
setDateTimeOriginalAsDate(Instant) |
|
|
|
|
|
||||||||||||||||||||
setUserCommentAsString(String) |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
Coverage
1: /*
2: * *********************************************************************************************************************
3: *
4: * Mistral: open source imaging engine
5: * http://tidalwave.it/projects/mistral
6: *
7: * Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *********************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
12: * the License. You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
17: * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
18: * specific language governing permissions and limitations under the License.
19: *
20: * *********************************************************************************************************************
21: *
22: * git clone https://bitbucket.org/tidalwave/mistral-src
23: * git clone https://github.com/tidalwave-it/mistral-src
24: *
25: * *********************************************************************************************************************
26: */
27: package it.tidalwave.image.metadata;
28:
29: import javax.annotation.CheckForNull;
30: import javax.annotation.Nonnull;
31: import java.time.Instant;
32: import java.time.temporal.ChronoUnit;
33: import java.util.Optional;
34: import java.awt.color.ICC_Profile;
35: import lombok.extern.slf4j.Slf4j;
36:
37: /***********************************************************************************************************************
38: *
39: * @author Fabrizio Giudici
40: *
41: **********************************************************************************************************************/
42: @Slf4j
43: public class EXIF extends EXIFDirectoryGenerated
44: {
45: private static final long serialVersionUID = 3088068666726854799L;
46:
47: private static final String ASCII_PREFIX = "ASCII\u0000\u0000\u0000";
48:
49: /*******************************************************************************************************************
50: *
51: *
52: ******************************************************************************************************************/
53: public EXIF()
54: {
55: }
56:
57: /*******************************************************************************************************************
58: *
59: *
60: ******************************************************************************************************************/
61: public EXIF (final Instant latestModificationTime)
62: {
63: super(latestModificationTime);
64: }
65:
66: /*******************************************************************************************************************
67: *
68: * FIXME: this conversion could be generically be implemented in getObject().
69: *
70: ******************************************************************************************************************/
71: @Override @Nonnull
72: public Optional<int[]> getBitsPerSample()
73: {
74: Object object = getRaw(C_BITS_PER_SAMPLE);
75:
76:• if (object instanceof short[])
77: {
78: final var shorts = (short[])object;
79: final var result = new int[shorts.length];
80:
81:• for (var i = 0; i < shorts.length; i++)
82: {
83: result[i] = shorts[i];
84: }
85:
86: object = result;
87: }
88:
89: return Optional.ofNullable((int[])object);
90: }
91:
92: /*******************************************************************************************************************
93: *
94: * The specification says it's an UNDEFINED[1], so some implementations
95: * return an array of one byte instead of a single byte. This would cause
96: * a ClassCastException in the generated code.
97: *
98: ******************************************************************************************************************/
99: @Override @Nonnull
100: public Optional<FileSource> getFileSource()
101: {
102: Object object = getRaw(C_FILE_SOURCE);
103:
104:• if (object instanceof byte[])
105: {
106: object = FileSource.fromInteger(((byte[])object)[0]);
107: }
108:
109:• else if (object instanceof Integer)
110: {
111: object = FileSource.fromInteger(((Integer)object));
112: }
113:
114: return Optional.ofNullable((FileSource)object);
115: }
116:
117: /*******************************************************************************************************************
118: *
119: * The specification says it's an UNDEFINED[1], so some implementations
120: * return an array of one byte instead of a single byte. This would cause
121: * a ClassCastException in the generated code.
122: *
123: ******************************************************************************************************************/
124: @Override @Nonnull
125: public Optional<SceneType> getSceneType()
126: {
127: Object object = getRaw(C_SCENE_TYPE);
128:
129:• if (object instanceof byte[])
130: {
131: object = SceneType.fromInteger(((byte[])object)[0]);
132: }
133:
134:• else if (object instanceof Integer)
135: {
136: object = SceneType.fromInteger(((Integer)object));
137: }
138:
139: return Optional.ofNullable((SceneType)object);
140: }
141:
142: /*******************************************************************************************************************
143: *
144: * {@inheritDoc}
145: *
146: ******************************************************************************************************************/
147: @Override @Nonnull
148: public Optional<byte[]> getUserComment()
149: {
150: try
151: {
152: return super.getUserComment();
153: }
154: catch (Exception e)
155: {
156: final int i = (Integer)getRaw(37510); // flowers.jpeg does this strange thing
157:
158: return Optional.ofNullable(("" + i).getBytes());
159: }
160: }
161:
162: /*******************************************************************************************************************
163: *
164: *
165: ******************************************************************************************************************/
166: @Nonnull
167: public Optional<String> getUserCommentAsString()
168: {
169: String string = null;
170: final var bytes = getUserComment().orElse(null);
171:
172:• if (bytes != null)
173: {
174: string = new String(bytes);
175:
176:• if (string.startsWith(ASCII_PREFIX))
177: {
178: return Optional.of(string.substring(ASCII_PREFIX.length()));
179: }
180: }
181:
182: return Optional.ofNullable(string);
183: }
184:
185: /*******************************************************************************************************************
186: *
187: *
188: ******************************************************************************************************************/
189: public void setUserCommentAsString (@Nonnull final String string)
190: {
191:• setUserComment((string == null) ? null : (ASCII_PREFIX + string).getBytes());
192: }
193:
194: /*******************************************************************************************************************
195: *
196: * {@inheritDoc}
197: *
198: ******************************************************************************************************************/
199: @Override @Nonnull
200: public Optional<String> getOriginalRawFileName()
201: {
202: var value = getRaw(C_ORIGINAL_RAW_FILE_NAME);
203:
204:• if (value instanceof byte[])
205: {
206: value = new String((byte[])value);
207: }
208:
209: return Optional.ofNullable((String)value);
210: }
211:
212: /*******************************************************************************************************************
213: *
214: * @return
215: *
216: ******************************************************************************************************************/
217: @Nonnull
218: public Optional<ICC_Profile> getICCProfile()
219: {
220: return getInterColourProfile().map(ICC_Profile::getInstance);
221: }
222:
223: /*******************************************************************************************************************
224: *
225: * @return
226: *
227: ******************************************************************************************************************/
228: @Nonnull
229: public Optional<Instant> getDateTimeAsDate()
230: {
231: return getDateTime().map(EXIF::parseDateTime).flatMap(d -> getSubsecTime().map(s -> adjust(d, s)));
232: }
233:
234: /*******************************************************************************************************************
235: *
236: ******************************************************************************************************************/
237: public void setDateTimeAsDate (@Nonnull final Instant date)
238: {
239:• setDateTime((date == null) ? null : formatDateTime(date));
240: }
241:
242: /*******************************************************************************************************************
243: *
244: * @return
245: *
246: ******************************************************************************************************************/
247: @Nonnull
248: public Optional<Instant> getDateTimeOriginalAsDate()
249: {
250: return getDateTimeOriginal().map(EXIF::parseDateTime)
251: .flatMap(d -> getSubsecTimeOriginal().map(s -> adjust(d, s)));
252: }
253:
254: /*******************************************************************************************************************
255: *
256: ******************************************************************************************************************/
257: public void setDateTimeOriginalAsDate (@Nonnull final Instant date)
258: {
259:• setDateTimeOriginal((date == null) ? null : formatDateTime(date));
260: }
261:
262: /*******************************************************************************************************************
263: *
264: * @return
265: *
266: ******************************************************************************************************************/
267: @Nonnull
268: public Optional<Instant> getDateTimeDigitizedAsDate()
269: {
270: return getDateTimeDigitized().map(EXIF::parseDateTime).flatMap(d -> getSubsecTimeDigitized().map(s -> adjust(d,
271: s)));
272: }
273:
274: /*******************************************************************************************************************
275: *
276: ******************************************************************************************************************/
277: public void setDateTimeDigitizedAsDate (@Nonnull final Instant date)
278: {
279:• setDateTimeDigitized((date == null) ? null : formatDateTime(date));
280: }
281:
282: /*******************************************************************************************************************
283: *
284: ******************************************************************************************************************/
285: @Override
286: public void setDateTime (@Nonnull final String dateTime)
287: {
288: super.setDateTime(dateTime);
289: }
290:
291: /*******************************************************************************************************************
292: *
293: ******************************************************************************************************************/
294: @Override
295: public void setDateTimeDigitized (@Nonnull final String dateTimeDigitized)
296: {
297: super.setDateTimeDigitized(dateTimeDigitized);
298: }
299:
300: /*******************************************************************************************************************
301: *
302: ******************************************************************************************************************/
303: @Override
304: public void setDateTimeOriginal (@Nonnull final String dateTimeOriginal)
305: {
306: super.setDateTimeOriginal(dateTimeOriginal);
307: }
308:
309: /*******************************************************************************************************************
310: *
311: * @param instant
312: * @param subsec
313: *
314: ******************************************************************************************************************/
315: @Nonnull
316: private Instant adjust (@CheckForNull final Instant instant, @Nonnull final String subsec)
317: {
318:• if (instant == null)
319: {
320: return null;
321: }
322:
323: return instant.plus(Integer.parseInt(subsec) * 10, ChronoUnit.MILLIS);
324: }
325: }