001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.imaging.formats.tiff;
018
019import java.awt.image.BufferedImage;
020import java.io.IOException;
021import java.nio.ByteOrder;
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025import java.util.Map;
026
027import org.apache.commons.imaging.ImageReadException;
028import org.apache.commons.imaging.common.ByteConversions;
029import org.apache.commons.imaging.common.RationalNumber;
030import org.apache.commons.imaging.formats.tiff.constants.TiffConstants;
031import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryConstants;
032import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
033import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType;
034import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
035import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAscii;
036import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoByte;
037import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoBytes;
038import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDouble;
039import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDoubles;
040import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloat;
041import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloats;
042import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoGpsText;
043import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLong;
044import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLongs;
045import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRational;
046import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRationals;
047import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSByte;
048import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSBytes;
049import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLong;
050import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLongs;
051import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRational;
052import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRationals;
053import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShort;
054import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShorts;
055import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShort;
056import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrLong;
057import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShorts;
058import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoXpString;
059
060public class TiffDirectory extends TiffElement {
061    public final int type;
062    public final List<TiffField> entries;
063    public final long nextDirectoryOffset;
064    private TiffImageData tiffImageData;
065    private JpegImageData jpegImageData;
066
067    public TiffDirectory(final int type, final List<TiffField> entries, final long offset, final long nextDirectoryOffset) {
068        super(offset, TiffConstants.TIFF_DIRECTORY_HEADER_LENGTH
069                + entries.size() * TiffConstants.TIFF_ENTRY_LENGTH
070                + TiffConstants.TIFF_DIRECTORY_FOOTER_LENGTH);
071
072        this.type = type;
073        this.entries = Collections.unmodifiableList(entries);
074        this.nextDirectoryOffset = nextDirectoryOffset;
075    }
076
077    public String description() {
078        return TiffDirectory.description(type);
079    }
080
081    @Override
082    public String getElementDescription() {
083        long entryOffset = offset + TiffConstants.TIFF_DIRECTORY_HEADER_LENGTH;
084
085        final StringBuilder result = new StringBuilder();
086        for (final TiffField entry : entries) {
087            result.append(String.format("\t[%d]: %s (%d, 0x%x), %s, %d: %s%n",
088                    entryOffset, entry.getTagInfo().name,
089                    entry.getTag(), entry.getTag(),
090                    entry.getFieldType().getName(), entry.getBytesLength(),
091                    entry.getValueDescription()));
092
093            entryOffset += TiffConstants.TIFF_ENTRY_LENGTH;
094        }
095        return result.toString();
096    }
097
098    public static String description(final int type) {
099        switch (type) {
100        case TiffDirectoryConstants.DIRECTORY_TYPE_UNKNOWN:
101            return "Unknown";
102        case TiffDirectoryConstants.DIRECTORY_TYPE_ROOT:
103            return "Root";
104        case TiffDirectoryConstants.DIRECTORY_TYPE_SUB:
105            return "Sub";
106        case TiffDirectoryConstants.DIRECTORY_TYPE_THUMBNAIL:
107            return "Thumbnail";
108        case TiffDirectoryConstants.DIRECTORY_TYPE_EXIF:
109            return "Exif";
110        case TiffDirectoryConstants.DIRECTORY_TYPE_GPS:
111            return "Gps";
112        case TiffDirectoryConstants.DIRECTORY_TYPE_INTEROPERABILITY:
113            return "Interoperability";
114        default:
115            return "Bad Type";
116        }
117    }
118
119
120    public List<TiffField> getDirectoryEntries() {
121        return new ArrayList<>(entries);
122    }
123
124    public void dump() {
125        for (final TiffField entry : entries) {
126            entry.dump();
127        }
128
129    }
130
131    public boolean hasJpegImageData() throws ImageReadException {
132        if (null != findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT)) {
133            return true;
134        }
135
136        return false;
137    }
138
139    public boolean hasTiffImageData() throws ImageReadException {
140        if (null != findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS)) {
141            return true;
142        }
143
144        if (null != findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS)) {
145            return true;
146        }
147
148        return false;
149    }
150
151    public BufferedImage getTiffImage(final ByteOrder byteOrder) throws ImageReadException,
152            IOException {
153        final Map<String, Object> params = null;
154        return getTiffImage(byteOrder, params);
155    }
156
157    public BufferedImage getTiffImage(final ByteOrder byteOrder, final Map<String, Object> params)
158            throws ImageReadException, IOException {
159        if (null == tiffImageData) {
160            return null;
161        }
162
163        return new TiffImageParser().getBufferedImage(this, byteOrder, params);
164    }
165
166    public TiffField findField(final TagInfo tag) throws ImageReadException {
167        final boolean failIfMissing = false;
168        return findField(tag, failIfMissing);
169    }
170
171    public TiffField findField(final TagInfo tag, final boolean failIfMissing)
172            throws ImageReadException {
173        if (entries == null) {
174            return null;
175        }
176
177        for (final TiffField field : entries) {
178            if (field.getTag() == tag.tag) {
179                return field;
180            }
181        }
182
183        if (failIfMissing) {
184            throw new ImageReadException("Missing expected field: "
185                    + tag.getDescription());
186        }
187
188        return null;
189    }
190
191    public Object getFieldValue(final TagInfo tag) throws ImageReadException {
192        final TiffField field = findField(tag);
193        if (field == null) {
194            return null;
195        }
196        return field.getValue();
197    }
198
199    public String getSingleFieldValue(final TagInfoAscii tag)
200            throws ImageReadException {
201        final String[] result = getFieldValue(tag, true);
202        if (result.length != 1) {
203            throw new ImageReadException("Field \"" + tag.name
204                    + "\" has incorrect length " + result.length);
205        }
206        return result[0];
207    }
208
209    public int getSingleFieldValue(final TagInfoShortOrLong tag) throws ImageReadException {
210        final int[] result = getFieldValue(tag, true);
211        if (result.length != 1) {
212            throw new ImageReadException("Field \"" + tag.name
213                    + "\" has incorrect length " + result.length);
214        }
215        return result[0];
216    }
217
218    public byte getFieldValue(final TagInfoByte tag)
219            throws ImageReadException {
220        final TiffField field = findField(tag);
221        if (field == null) {
222            throw new ImageReadException("Required field \"" + tag.name
223                    + "\" is missing");
224        }
225        if (!tag.dataTypes.contains(field.getFieldType())) {
226            throw new ImageReadException("Required field \"" + tag.name
227                    + "\" has incorrect type " + field.getFieldType().getName());
228        }
229        if (field.getCount() != 1) {
230            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
231        }
232        return field.getByteArrayValue()[0];
233    }
234
235    public byte[] getFieldValue(final TagInfoBytes tag, final boolean mustExist)
236            throws ImageReadException {
237        final TiffField field = findField(tag);
238        if (field == null) {
239            if (mustExist) {
240                throw new ImageReadException("Required field \"" + tag.name
241                        + "\" is missing");
242            } else {
243                return null;
244            }
245        }
246        if (!tag.dataTypes.contains(field.getFieldType())) {
247            if (mustExist) {
248                throw new ImageReadException("Required field \"" + tag.name
249                        + "\" has incorrect type " + field.getFieldType().getName());
250            } else {
251                return null;
252            }
253        }
254        return field.getByteArrayValue();
255    }
256
257    public String[] getFieldValue(final TagInfoAscii tag, final boolean mustExist)
258            throws ImageReadException {
259        final TiffField field = findField(tag);
260        if (field == null) {
261            if (mustExist) {
262                throw new ImageReadException("Required field \"" + tag.name
263                        + "\" is missing");
264            } else {
265                return null;
266            }
267        }
268        if (!tag.dataTypes.contains(field.getFieldType())) {
269            if (mustExist) {
270                throw new ImageReadException("Required field \"" + tag.name
271                        + "\" has incorrect type " + field.getFieldType().getName());
272            } else {
273                return null;
274            }
275        }
276        final byte[] bytes = field.getByteArrayValue();
277        return tag.getValue(field.getByteOrder(), bytes);
278    }
279
280    public short getFieldValue(final TagInfoShort tag)
281            throws ImageReadException {
282        final TiffField field = findField(tag);
283        if (field == null) {
284            throw new ImageReadException("Required field \"" + tag.name
285                    + "\" is missing");
286        }
287        if (!tag.dataTypes.contains(field.getFieldType())) {
288            throw new ImageReadException("Required field \"" + tag.name
289                    + "\" has incorrect type " + field.getFieldType().getName());
290        }
291        if (field.getCount() != 1) {
292            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
293        }
294        final byte[] bytes = field.getByteArrayValue();
295        return tag.getValue(field.getByteOrder(), bytes);
296    }
297
298    public short[] getFieldValue(final TagInfoShorts tag, final boolean mustExist)
299            throws ImageReadException {
300        final TiffField field = findField(tag);
301        if (field == null) {
302            if (mustExist) {
303                throw new ImageReadException("Required field \"" + tag.name
304                        + "\" is missing");
305            } else {
306                return null;
307            }
308        }
309        if (!tag.dataTypes.contains(field.getFieldType())) {
310            if (mustExist) {
311                throw new ImageReadException("Required field \"" + tag.name
312                        + "\" has incorrect type " + field.getFieldType().getName());
313            } else {
314                return null;
315            }
316        }
317        final byte[] bytes = field.getByteArrayValue();
318        return tag.getValue(field.getByteOrder(), bytes);
319    }
320
321    public int getFieldValue(final TagInfoLong tag)
322            throws ImageReadException {
323        final TiffField field = findField(tag);
324        if (field == null) {
325            throw new ImageReadException("Required field \"" + tag.name
326                    + "\" is missing");
327        }
328        if (!tag.dataTypes.contains(field.getFieldType())) {
329            throw new ImageReadException("Required field \"" + tag.name
330                    + "\" has incorrect type " + field.getFieldType().getName());
331        }
332        if (field.getCount() != 1) {
333            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
334        }
335        final byte[] bytes = field.getByteArrayValue();
336        return tag.getValue(field.getByteOrder(), bytes);
337    }
338
339    public int[] getFieldValue(final TagInfoLongs tag, final boolean mustExist)
340            throws ImageReadException {
341        final TiffField field = findField(tag);
342        if (field == null) {
343            if (mustExist) {
344                throw new ImageReadException("Required field \"" + tag.name
345                        + "\" is missing");
346            } else {
347                return null;
348            }
349        }
350        if (!tag.dataTypes.contains(field.getFieldType())) {
351            if (mustExist) {
352                throw new ImageReadException("Required field \"" + tag.name
353                        + "\" has incorrect type " + field.getFieldType().getName());
354            } else {
355                return null;
356            }
357        }
358        final byte[] bytes = field.getByteArrayValue();
359        return tag.getValue(field.getByteOrder(), bytes);
360    }
361
362    public int[] getFieldValue(final TagInfoShortOrLong tag, final boolean mustExist)
363            throws ImageReadException {
364        final TiffField field = findField(tag);
365        if (field == null) {
366            if (mustExist) {
367                throw new ImageReadException("Required field \"" + tag.name
368                        + "\" is missing");
369            } else {
370                return null;
371            }
372        }
373        if (!tag.dataTypes.contains(field.getFieldType())) {
374            if (mustExist) {
375                throw new ImageReadException("Required field \"" + tag.name
376                        + "\" has incorrect type " + field.getFieldType().getName());
377            } else {
378                return null;
379            }
380        }
381        final byte[] bytes = field.getByteArrayValue();
382        if (field.getFieldType() == FieldType.SHORT) {
383            return ByteConversions.toUInt16s(bytes, field.getByteOrder());
384        } else {
385            return ByteConversions.toInts(bytes, field.getByteOrder());
386        }
387    }
388
389    public RationalNumber getFieldValue(final TagInfoRational tag)
390            throws ImageReadException {
391        final TiffField field = findField(tag);
392        if (field == null) {
393            throw new ImageReadException("Required field \"" + tag.name
394                    + "\" is missing");
395        }
396        if (!tag.dataTypes.contains(field.getFieldType())) {
397            throw new ImageReadException("Required field \"" + tag.name
398                    + "\" has incorrect type " + field.getFieldType().getName());
399        }
400        if (field.getCount() != 1) {
401            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
402        }
403        final byte[] bytes = field.getByteArrayValue();
404        return tag.getValue(field.getByteOrder(), bytes);
405    }
406
407    public RationalNumber[] getFieldValue(final TagInfoRationals tag, final boolean mustExist)
408            throws ImageReadException {
409        final TiffField field = findField(tag);
410        if (field == null) {
411            if (mustExist) {
412                throw new ImageReadException("Required field \"" + tag.name
413                        + "\" is missing");
414            } else {
415                return null;
416            }
417        }
418        if (!tag.dataTypes.contains(field.getFieldType())) {
419            if (mustExist) {
420                throw new ImageReadException("Required field \"" + tag.name
421                        + "\" has incorrect type " + field.getFieldType().getName());
422            } else {
423                return null;
424            }
425        }
426        final byte[] bytes = field.getByteArrayValue();
427        return tag.getValue(field.getByteOrder(), bytes);
428    }
429
430    public byte getFieldValue(final TagInfoSByte tag)
431            throws ImageReadException {
432        final TiffField field = findField(tag);
433        if (field == null) {
434            throw new ImageReadException("Required field \"" + tag.name
435                    + "\" is missing");
436        }
437        if (!tag.dataTypes.contains(field.getFieldType())) {
438            throw new ImageReadException("Required field \"" + tag.name
439                    + "\" has incorrect type " + field.getFieldType().getName());
440        }
441        if (field.getCount() != 1) {
442            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
443        }
444        return field.getByteArrayValue()[0];
445    }
446
447    public byte[] getFieldValue(final TagInfoSBytes tag, final boolean mustExist)
448            throws ImageReadException {
449        final TiffField field = findField(tag);
450        if (field == null) {
451            if (mustExist) {
452                throw new ImageReadException("Required field \"" + tag.name
453                        + "\" is missing");
454            } else {
455                return null;
456            }
457        }
458        if (!tag.dataTypes.contains(field.getFieldType())) {
459            if (mustExist) {
460                throw new ImageReadException("Required field \"" + tag.name
461                        + "\" has incorrect type " + field.getFieldType().getName());
462            } else {
463                return null;
464            }
465        }
466        return field.getByteArrayValue();
467    }
468
469    public short getFieldValue(final TagInfoSShort tag)
470            throws ImageReadException {
471        final TiffField field = findField(tag);
472        if (field == null) {
473            throw new ImageReadException("Required field \"" + tag.name
474                    + "\" is missing");
475        }
476        if (!tag.dataTypes.contains(field.getFieldType())) {
477            throw new ImageReadException("Required field \"" + tag.name
478                    + "\" has incorrect type " + field.getFieldType().getName());
479        }
480        if (field.getCount() != 1) {
481            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
482        }
483        final byte[] bytes = field.getByteArrayValue();
484        return tag.getValue(field.getByteOrder(), bytes);
485    }
486
487    public short[] getFieldValue(final TagInfoSShorts tag, final boolean mustExist)
488            throws ImageReadException {
489        final TiffField field = findField(tag);
490        if (field == null) {
491            if (mustExist) {
492                throw new ImageReadException("Required field \"" + tag.name
493                        + "\" is missing");
494            } else {
495                return null;
496            }
497        }
498        if (!tag.dataTypes.contains(field.getFieldType())) {
499            if (mustExist) {
500                throw new ImageReadException("Required field \"" + tag.name
501                        + "\" has incorrect type " + field.getFieldType().getName());
502            } else {
503                return null;
504            }
505        }
506        final byte[] bytes = field.getByteArrayValue();
507        return tag.getValue(field.getByteOrder(), bytes);
508    }
509
510    public int getFieldValue(final TagInfoSLong tag)
511            throws ImageReadException {
512        final TiffField field = findField(tag);
513        if (field == null) {
514            throw new ImageReadException("Required field \"" + tag.name
515                    + "\" is missing");
516        }
517        if (!tag.dataTypes.contains(field.getFieldType())) {
518            throw new ImageReadException("Required field \"" + tag.name
519                    + "\" has incorrect type " + field.getFieldType().getName());
520        }
521        if (field.getCount() != 1) {
522            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
523        }
524        final byte[] bytes = field.getByteArrayValue();
525        return tag.getValue(field.getByteOrder(), bytes);
526    }
527
528    public int[] getFieldValue(final TagInfoSLongs tag, final boolean mustExist)
529            throws ImageReadException {
530        final TiffField field = findField(tag);
531        if (field == null) {
532            if (mustExist) {
533                throw new ImageReadException("Required field \"" + tag.name
534                        + "\" is missing");
535            } else {
536                return null;
537            }
538        }
539        if (!tag.dataTypes.contains(field.getFieldType())) {
540            if (mustExist) {
541                throw new ImageReadException("Required field \"" + tag.name
542                        + "\" has incorrect type " + field.getFieldType().getName());
543            } else {
544                return null;
545            }
546        }
547        final byte[] bytes = field.getByteArrayValue();
548        return tag.getValue(field.getByteOrder(), bytes);
549    }
550
551    public RationalNumber getFieldValue(final TagInfoSRational tag) throws ImageReadException {
552        final TiffField field = findField(tag);
553        if (field == null) {
554            throw new ImageReadException("Required field \"" + tag.name
555                    + "\" is missing");
556        }
557        if (!tag.dataTypes.contains(field.getFieldType())) {
558            throw new ImageReadException("Required field \"" + tag.name
559                    + "\" has incorrect type " + field.getFieldType().getName());
560        }
561        if (field.getCount() != 1) {
562            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
563        }
564        final byte[] bytes = field.getByteArrayValue();
565        return tag.getValue(field.getByteOrder(), bytes);
566    }
567
568    public RationalNumber[] getFieldValue(final TagInfoSRationals tag,
569            final boolean mustExist) throws ImageReadException {
570        final TiffField field = findField(tag);
571        if (field == null) {
572            if (mustExist) {
573                throw new ImageReadException("Required field \"" + tag.name
574                        + "\" is missing");
575            } else {
576                return null;
577            }
578        }
579        if (!tag.dataTypes.contains(field.getFieldType())) {
580            if (mustExist) {
581                throw new ImageReadException("Required field \"" + tag.name
582                        + "\" has incorrect type " + field.getFieldType().getName());
583            } else {
584                return null;
585            }
586        }
587        final byte[] bytes = field.getByteArrayValue();
588        return tag.getValue(field.getByteOrder(), bytes);
589    }
590
591    public float getFieldValue(final TagInfoFloat tag)
592            throws ImageReadException {
593        final TiffField field = findField(tag);
594        if (field == null) {
595            throw new ImageReadException("Required field \"" + tag.name
596                    + "\" is missing");
597        }
598        if (!tag.dataTypes.contains(field.getFieldType())) {
599            throw new ImageReadException("Required field \"" + tag.name
600                    + "\" has incorrect type " + field.getFieldType().getName());
601        }
602        if (field.getCount() != 1) {
603            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
604        }
605        final byte[] bytes = field.getByteArrayValue();
606        return tag.getValue(field.getByteOrder(), bytes);
607    }
608
609    public float[] getFieldValue(final TagInfoFloats tag, final boolean mustExist)
610            throws ImageReadException {
611        final TiffField field = findField(tag);
612        if (field == null) {
613            if (mustExist) {
614                throw new ImageReadException("Required field \"" + tag.name
615                        + "\" is missing");
616            } else {
617                return null;
618            }
619        }
620        if (!tag.dataTypes.contains(field.getFieldType())) {
621            if (mustExist) {
622                throw new ImageReadException("Required field \"" + tag.name
623                        + "\" has incorrect type " + field.getFieldType().getName());
624            } else {
625                return null;
626            }
627        }
628        final byte[] bytes = field.getByteArrayValue();
629        return tag.getValue(field.getByteOrder(), bytes);
630    }
631
632    public double getFieldValue(final TagInfoDouble tag)
633            throws ImageReadException {
634        final TiffField field = findField(tag);
635        if (field == null) {
636            throw new ImageReadException("Required field \"" + tag.name
637                    + "\" is missing");
638        }
639        if (!tag.dataTypes.contains(field.getFieldType())) {
640            throw new ImageReadException("Required field \"" + tag.name
641                    + "\" has incorrect type " + field.getFieldType().getName());
642        }
643        if (field.getCount() != 1) {
644            throw new ImageReadException("Field \"" + tag.name + "\" has wrong count " + field.getCount());
645        }
646        final byte[] bytes = field.getByteArrayValue();
647        return tag.getValue(field.getByteOrder(), bytes);
648    }
649
650    public double[] getFieldValue(final TagInfoDoubles tag, final boolean mustExist)
651            throws ImageReadException {
652        final TiffField field = findField(tag);
653        if (field == null) {
654            if (mustExist) {
655                throw new ImageReadException("Required field \"" + tag.name
656                        + "\" is missing");
657            } else {
658                return null;
659            }
660        }
661        if (!tag.dataTypes.contains(field.getFieldType())) {
662            if (mustExist) {
663                throw new ImageReadException("Required field \"" + tag.name
664                        + "\" has incorrect type " + field.getFieldType().getName());
665            } else {
666                return null;
667            }
668        }
669        final byte[] bytes = field.getByteArrayValue();
670        return tag.getValue(field.getByteOrder(), bytes);
671    }
672
673    public String getFieldValue(final TagInfoGpsText tag, final boolean mustExist)
674            throws ImageReadException {
675        final TiffField field = findField(tag);
676        if (field == null) {
677            if (mustExist) {
678                throw new ImageReadException("Required field \"" + tag.name
679                        + "\" is missing");
680            } else {
681                return null;
682            }
683        }
684        return tag.getValue(field);
685    }
686
687    public String getFieldValue(final TagInfoXpString tag, final boolean mustExist)
688            throws ImageReadException {
689        final TiffField field = findField(tag);
690        if (field == null) {
691            if (mustExist) {
692                throw new ImageReadException("Required field \"" + tag.name
693                        + "\" is missing");
694            } else {
695                return null;
696            }
697        }
698        return tag.getValue(field);
699    }
700
701    public static final class ImageDataElement extends TiffElement {
702        public ImageDataElement(final long offset, final int length) {
703            super(offset, length);
704        }
705
706        @Override
707        public String getElementDescription() {
708            return "ImageDataElement";
709        }
710    }
711
712    private List<ImageDataElement> getRawImageDataElements(
713            final TiffField offsetsField, final TiffField byteCountsField)
714            throws ImageReadException {
715        final int[] offsets = offsetsField.getIntArrayValue();
716        final int[] byteCounts = byteCountsField.getIntArrayValue();
717
718        if (offsets.length != byteCounts.length) {
719            throw new ImageReadException("offsets.length(" + offsets.length
720                    + ") != byteCounts.length(" + byteCounts.length + ")");
721        }
722
723        final List<ImageDataElement> result = new ArrayList<>(offsets.length);
724        for (int i = 0; i < offsets.length; i++) {
725            result.add(new ImageDataElement(offsets[i], byteCounts[i]));
726        }
727        return result;
728    }
729
730    public List<ImageDataElement> getTiffRawImageDataElements()
731            throws ImageReadException {
732        final TiffField tileOffsets = findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
733        final TiffField tileByteCounts = findField(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
734        final TiffField stripOffsets = findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
735        final TiffField stripByteCounts = findField(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
736
737        if ((tileOffsets != null) && (tileByteCounts != null)) {
738            return getRawImageDataElements(tileOffsets, tileByteCounts);
739        } else if ((stripOffsets != null) && (stripByteCounts != null)) {
740            return getRawImageDataElements(stripOffsets, stripByteCounts);
741        } else {
742            throw new ImageReadException("Couldn't find image data.");
743        }
744    }
745
746    public boolean imageDataInStrips() throws ImageReadException {
747        final TiffField tileOffsets = findField(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
748        final TiffField tileByteCounts = findField(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
749        final TiffField stripOffsets = findField(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
750        final TiffField stripByteCounts = findField(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
751
752        if ((tileOffsets != null) && (tileByteCounts != null)) {
753            return false;
754        } else if ((stripOffsets != null) && (stripByteCounts != null)) {
755            return true;
756        } else {
757            throw new ImageReadException("Couldn't find image data.");
758        }
759    }
760
761    public ImageDataElement getJpegRawImageDataElement() throws ImageReadException {
762        final TiffField jpegInterchangeFormat = findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT);
763        final TiffField jpegInterchangeFormatLength = findField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
764
765        if (jpegInterchangeFormat != null && jpegInterchangeFormatLength != null) {
766            final int offSet = jpegInterchangeFormat.getIntArrayValue()[0];
767            final int byteCount = jpegInterchangeFormatLength.getIntArrayValue()[0];
768
769            return new ImageDataElement(offSet, byteCount);
770        } else {
771            throw new ImageReadException("Couldn't find image data.");
772        }
773    }
774
775    public void setTiffImageData(final TiffImageData rawImageData) {
776        this.tiffImageData = rawImageData;
777    }
778
779    public TiffImageData getTiffImageData() {
780        return tiffImageData;
781    }
782
783    public void setJpegImageData(final JpegImageData value) {
784        this.jpegImageData = value;
785    }
786
787    public JpegImageData getJpegImageData() {
788        return jpegImageData;
789    }
790
791}