1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.tiff;
18
19 import java.io.IOException;
20 import java.io.PrintWriter;
21 import java.io.StringWriter;
22 import java.nio.ByteOrder;
23 import java.text.DateFormat;
24 import java.text.SimpleDateFormat;
25 import java.util.Arrays;
26 import java.util.Date;
27 import java.util.Locale;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30
31 import org.apache.commons.imaging.ImagingException;
32 import org.apache.commons.imaging.common.Allocator;
33 import org.apache.commons.imaging.common.BinaryFunctions;
34 import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
35 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
36 import org.apache.commons.imaging.formats.tiff.fieldtypes.AbstractFieldType;
37 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
38
39
40
41
42 public class TiffField {
43
44 public final class OversizeValueElement extends AbstractTiffElement {
45 public OversizeValueElement(final int offset, final int length) {
46 super(offset, length);
47 }
48
49 @Override
50 public String getElementDescription() {
51 return "OversizeValueElement, tag: " + getTagInfo().name + ", fieldType: " + getFieldType().getName();
52 }
53 }
54
55 private static final Logger LOGGER = Logger.getLogger(TiffField.class.getName());
56 private final TagInfo tagInfo;
57 private final int tag;
58 private final int directoryType;
59 private final AbstractFieldType abstractFieldType;
60 private final long count;
61 private final long offset;
62 private final byte[] value;
63 private final ByteOrder byteOrder;
64
65 private final int sortHint;
66
67 public TiffField(final int tag, final int directoryType, final AbstractFieldType abstractFieldType, final long count, final long offset, final byte[] value,
68 final ByteOrder byteOrder, final int sortHint) {
69
70 this.tag = tag;
71 this.directoryType = directoryType;
72 this.abstractFieldType = abstractFieldType;
73 this.count = count;
74 this.offset = offset;
75 this.value = value;
76 this.byteOrder = byteOrder;
77 this.sortHint = sortHint;
78
79 tagInfo = TiffTags.getTag(directoryType, tag);
80 }
81
82 public void dump() {
83 try (StringWriter sw = new StringWriter();
84 PrintWriter pw = new PrintWriter(sw)) {
85 dump(pw);
86 pw.flush();
87 sw.flush();
88 LOGGER.fine(sw.toString());
89 } catch (final IOException e) {
90 LOGGER.log(Level.SEVERE, e.getMessage(), e);
91 }
92 }
93
94 public void dump(final PrintWriter pw) {
95 dump(pw, null);
96 }
97
98 public void dump(final PrintWriter pw, final String prefix) {
99 if (prefix != null) {
100 pw.print(prefix + ": ");
101 }
102
103 pw.println(toString());
104 pw.flush();
105 }
106
107
108
109
110
111
112 public byte[] getByteArrayValue() {
113 return BinaryFunctions.head(value, getBytesLength());
114 }
115
116
117
118
119
120
121 public ByteOrder getByteOrder() {
122 return byteOrder;
123 }
124
125
126
127
128
129
130 public int getBytesLength() {
131 return (int) count * abstractFieldType.getSize();
132 }
133
134
135
136
137
138
139 public long getCount() {
140 return count;
141 }
142
143 public String getDescriptionWithoutValue() {
144 return getTag() + " (0x" + Integer.toHexString(getTag()) + ": " + getTagInfo().name + "): ";
145 }
146
147 public int getDirectoryType() {
148 return directoryType;
149 }
150
151 public double[] getDoubleArrayValue() throws ImagingException {
152 final Object o = getValue();
153
154
155
156 if (o instanceof Number) {
157 return new double[] { ((Number) o).doubleValue() };
158 }
159 if (o instanceof Number[]) {
160 final Number[] numbers = (Number[]) o;
161 final double[] result = Allocator.doubleArray(numbers.length);
162 Arrays.setAll(result, i -> numbers[i].doubleValue());
163 return result;
164 }
165 if (o instanceof short[]) {
166 final short[] numbers = (short[]) o;
167 final double[] result = Allocator.doubleArray(numbers.length);
168 Arrays.setAll(result, i -> numbers[i]);
169 return result;
170 }
171 if (o instanceof int[]) {
172 final int[] numbers = (int[]) o;
173 final double[] result = Allocator.doubleArray(numbers.length);
174 Arrays.setAll(result, i -> numbers[i]);
175 return result;
176 }
177 if (o instanceof float[]) {
178 final float[] numbers = (float[]) o;
179 final double[] result = Allocator.doubleArray(numbers.length);
180 Arrays.setAll(result, i -> numbers[i]);
181 return result;
182 }
183 if (o instanceof double[]) {
184 final double[] numbers = (double[]) o;
185 return Arrays.copyOf(numbers, numbers.length);
186 }
187
188 throw new ImagingException("Unknown value: " + o + " for: " + getTagInfo().getDescription());
189
190 }
191
192 public double getDoubleValue() throws ImagingException {
193 final Object o = getValue();
194 if (o == null) {
195 throw new ImagingException("Missing value: " + getTagInfo().getDescription());
196 }
197
198 return ((Number) o).doubleValue();
199 }
200
201
202
203
204
205
206 public AbstractFieldType getFieldType() {
207 return abstractFieldType;
208 }
209
210 public String getFieldTypeName() {
211 return getFieldType().getName();
212 }
213
214 public int[] getIntArrayValue() throws ImagingException {
215 final Object o = getValue();
216
217
218
219 if (o instanceof Number) {
220 return new int[] { ((Number) o).intValue() };
221 }
222 if (o instanceof Number[]) {
223 final Number[] numbers = (Number[]) o;
224 final int[] result = Allocator.intArray(numbers.length);
225 Arrays.setAll(result, i -> numbers[i].intValue());
226 return result;
227 }
228 if (o instanceof short[]) {
229 final short[] numbers = (short[]) o;
230 final int[] result = Allocator.intArray(numbers.length);
231 Arrays.setAll(result, i -> 0xffff & numbers[i]);
232 return result;
233 }
234 if (o instanceof int[]) {
235 final int[] numbers = (int[]) o;
236 return Arrays.copyOf(numbers, numbers.length);
237 }
238 if (o instanceof long[]) {
239 final long[] numbers = (long[]) o;
240 final int[] iNumbers = new int[numbers.length];
241 for (int i = 0; i < iNumbers.length; i++) {
242 iNumbers[i] = (int) numbers[i];
243 }
244 return iNumbers;
245 }
246
247 throw new ImagingException("Unknown value: " + o + " for: " + getTagInfo().getDescription());
248
249 }
250
251 public int getIntValue() throws ImagingException {
252 final Object o = getValue();
253 if (o == null) {
254 throw new ImagingException("Missing value: " + getTagInfo().getDescription());
255 }
256
257 return ((Number) o).intValue();
258 }
259
260 public int getIntValueOrArraySum() throws ImagingException {
261 final Object o = getValue();
262
263
264
265 if (o instanceof Number) {
266 return ((Number) o).intValue();
267 }
268 if (o instanceof Number[]) {
269 final Number[] numbers = (Number[]) o;
270 int sum = 0;
271 for (final Number number : numbers) {
272 sum += number.intValue();
273 }
274 return sum;
275 }
276 if (o instanceof short[]) {
277 final short[] numbers = (short[]) o;
278 int sum = 0;
279 for (final short number : numbers) {
280 sum += number;
281 }
282 return sum;
283 }
284 if (o instanceof int[]) {
285 final int[] numbers = (int[]) o;
286 int sum = 0;
287 for (final int number : numbers) {
288 sum += number;
289 }
290 return sum;
291 }
292
293 throw new ImagingException("Unknown value: " + o + " for: " + getTagInfo().getDescription());
294
295 }
296
297
298
299
300
301
302
303 public long[] getLongArrayValue() throws ImagingException {
304 final Object o = getValue();
305 if (o instanceof Number) {
306 return new long[] { ((Number) o).longValue() };
307 }
308 if (o instanceof Number[]) {
309 final Number[] numbers = (Number[]) o;
310 final long[] result = Allocator.longArray(numbers.length);
311 Arrays.setAll(result, i -> numbers[i].longValue());
312 return result;
313 }
314 if (o instanceof short[]) {
315 final short[] numbers = (short[]) o;
316 final long[] result = Allocator.longArray(numbers.length);
317 Arrays.setAll(result, i -> 0xffff & numbers[i]);
318 return result;
319 }
320 if (o instanceof int[]) {
321 final int[] numbers = (int[]) o;
322 final long[] result = Allocator.longArray(numbers.length);
323 Arrays.setAll(result, i -> 0xFFFFffffL & numbers[i]);
324 return result;
325 }
326 if (o instanceof long[]) {
327 final long[] numbers = (long[]) o;
328 return Arrays.copyOf(numbers, numbers.length);
329 }
330
331 throw new ImagingException("Unknown value: " + o + " for: " + getTagInfo().getDescription());
332 }
333
334
335
336
337
338
339
340 public long getLongValue() throws ImagingException {
341 final Object o = getValue();
342 if (o == null) {
343 throw new ImagingException("Missing value: " + getTagInfo().getDescription());
344 }
345 return ((Number) o).longValue();
346 }
347
348
349
350
351
352
353 public int getOffset() {
354 return (int) offset;
355 }
356
357 public AbstractTiffElement getOversizeValueElement() {
358 if (isLocalValue()) {
359 return null;
360 }
361
362 return new OversizeValueElement(getOffset(), value.length);
363 }
364
365 public int getSortHint() {
366 return sortHint;
367 }
368
369 public String getStringValue() throws ImagingException {
370 final Object o = getValue();
371 if (o == null) {
372 return null;
373 }
374 if (!(o instanceof String)) {
375 throw new ImagingException("Expected String value(" + getTagInfo().getDescription() + "): " + o);
376 }
377 return (String) o;
378 }
379
380
381
382
383
384
385 public int getTag() {
386 return tag;
387 }
388
389 public TagInfo getTagInfo() {
390 return tagInfo;
391 }
392
393 public String getTagName() {
394 if (getTagInfo() == TiffTagConstants.TIFF_TAG_UNKNOWN) {
395 return getTagInfo().name + " (0x" + Integer.toHexString(getTag()) + ")";
396 }
397 return getTagInfo().name;
398 }
399
400 public Object getValue() throws ImagingException {
401
402 return getTagInfo().getValue(this);
403 }
404
405 public String getValueDescription() {
406 try {
407 return getValueDescription(getValue());
408 } catch (final ImagingException e) {
409 return "Invalid value: " + e.getMessage();
410 }
411 }
412
413 private String getValueDescription(final Object o) {
414 if (o == null) {
415 return null;
416 }
417
418 if (o instanceof Number) {
419 return o.toString();
420 }
421 if (o instanceof String) {
422 return "'" + o.toString().trim() + "'";
423 }
424 if (o instanceof Date) {
425 final DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.ROOT);
426 return df.format((Date) o);
427 }
428 if (o instanceof Object[]) {
429 final Object[] objects = (Object[]) o;
430 final StringBuilder result = new StringBuilder();
431
432 for (int i = 0; i < objects.length; i++) {
433 final Object object = objects[i];
434
435 if (i > 50) {
436 result.append("... (").append(objects.length).append(")");
437 break;
438 }
439 if (i > 0) {
440 result.append(", ");
441 }
442 result.append(object.toString());
443 }
444 return result.toString();
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460 }
461 if (o instanceof short[]) {
462 final short[] values = (short[]) o;
463 final StringBuilder result = new StringBuilder();
464
465 for (int i = 0; i < values.length; i++) {
466 final short sVal = values[i];
467
468 if (i > 50) {
469 result.append("... (").append(values.length).append(")");
470 break;
471 }
472 if (i > 0) {
473 result.append(", ");
474 }
475 result.append(sVal);
476 }
477 return result.toString();
478 }
479 if (o instanceof int[]) {
480 final int[] values = (int[]) o;
481 final StringBuilder result = new StringBuilder();
482
483 for (int i = 0; i < values.length; i++) {
484 final int iVal = values[i];
485
486 if (i > 50) {
487 result.append("... (").append(values.length).append(")");
488 break;
489 }
490 if (i > 0) {
491 result.append(", ");
492 }
493 result.append(iVal);
494 }
495 return result.toString();
496 }
497 if (o instanceof long[]) {
498 final long[] values = (long[]) o;
499 final StringBuilder result = new StringBuilder();
500
501 for (int i = 0; i < values.length; i++) {
502 final long lVal = values[i];
503
504 if (i > 50) {
505 result.append("... (").append(values.length).append(")");
506 break;
507 }
508 if (i > 0) {
509 result.append(", ");
510 }
511 result.append(lVal);
512 }
513 return result.toString();
514 }
515 if (o instanceof double[]) {
516 final double[] values = (double[]) o;
517 final StringBuilder result = new StringBuilder();
518
519 for (int i = 0; i < values.length; i++) {
520 final double dVal = values[i];
521
522 if (i > 50) {
523 result.append("... (").append(values.length).append(")");
524 break;
525 }
526 if (i > 0) {
527 result.append(", ");
528 }
529 result.append(dVal);
530 }
531 return result.toString();
532 }
533 if (o instanceof byte[]) {
534 final byte[] values = (byte[]) o;
535 final StringBuilder result = new StringBuilder();
536
537 for (int i = 0; i < values.length; i++) {
538 final byte bVal = values[i];
539
540 if (i > 50) {
541 result.append("... (").append(values.length).append(")");
542 break;
543 }
544 if (i > 0) {
545 result.append(", ");
546 }
547 result.append(bVal);
548 }
549 return result.toString();
550 }
551 if (o instanceof char[]) {
552 final char[] values = (char[]) o;
553 final StringBuilder result = new StringBuilder();
554
555 for (int i = 0; i < values.length; i++) {
556 final char cVal = values[i];
557
558 if (i > 50) {
559 result.append("... (").append(values.length).append(")");
560 break;
561 }
562 if (i > 0) {
563 result.append(", ");
564 }
565 result.append(cVal);
566 }
567 return result.toString();
568 }
569 if (o instanceof float[]) {
570 final float[] values = (float[]) o;
571 final StringBuilder result = new StringBuilder();
572
573 for (int i = 0; i < values.length; i++) {
574 final float fVal = values[i];
575
576 if (i > 50) {
577 result.append("... (").append(values.length).append(")");
578 break;
579 }
580 if (i > 0) {
581 result.append(", ");
582 }
583 result.append(fVal);
584 }
585 return result.toString();
586 }
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 return "Unknown: " + o.getClass().getName();
604 }
605
606
607
608
609
610
611 public boolean isLocalValue() {
612 return count * abstractFieldType.getSize() <= TiffConstants.TIFF_ENTRY_MAX_VALUE_LENGTH;
613 }
614
615 @Override
616 public String toString() {
617 return getTag() + " (0x" + Integer.toHexString(getTag()) + ": " + getTagInfo().name + "): " + getValueDescription() + " (" + getCount() + " "
618 + getFieldType().getName() + ")";
619 }
620 }