1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.imaging.formats.tiff.write;
18
19 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_DIRECTORY_FOOTER_LENGTH;
20 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_DIRECTORY_HEADER_LENGTH;
21 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_LENGTH;
22 import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_MAX_VALUE_LENGTH;
23
24 import java.io.IOException;
25 import java.nio.ByteOrder;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.Iterator;
31 import java.util.List;
32
33 import org.apache.commons.imaging.ImagingException;
34 import org.apache.commons.imaging.common.Allocator;
35 import org.apache.commons.imaging.common.BinaryOutputStream;
36 import org.apache.commons.imaging.common.RationalNumber;
37 import org.apache.commons.imaging.formats.tiff.AbstractTiffElement;
38 import org.apache.commons.imaging.formats.tiff.AbstractTiffImageData;
39 import org.apache.commons.imaging.formats.tiff.JpegImageData;
40 import org.apache.commons.imaging.formats.tiff.TiffDirectory;
41 import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryType;
42 import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants;
43 import org.apache.commons.imaging.formats.tiff.fieldtypes.AbstractFieldType;
44 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo;
45 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAscii;
46 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAsciiOrByte;
47 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAsciiOrRational;
48 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoByte;
49 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoByteOrShort;
50 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoBytes;
51 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDouble;
52 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDoubles;
53 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloat;
54 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloats;
55 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoGpsText;
56 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLong;
57 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLongs;
58 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRational;
59 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRationals;
60 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSByte;
61 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSBytes;
62 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLong;
63 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLongs;
64 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRational;
65 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRationals;
66 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShort;
67 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShorts;
68 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShort;
69 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrLong;
70 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrLongOrRational;
71 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrRational;
72 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShorts;
73 import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoXpString;
74
75 public final class TiffOutputDirectory extends AbstractTiffOutputItem implements Iterable<TiffOutputField> {
76 public static final Comparator<TiffOutputDirectory> COMPARATOR = Comparator.comparingInt(TiffOutputDirectory::getType);
77 private final int type;
78 private final List<TiffOutputField> fields = new ArrayList<>();
79 private final ByteOrder byteOrder;
80 private TiffOutputDirectory nextDirectory;
81 private JpegImageData jpegImageData;
82 private AbstractTiffImageData abstractTiffImageData;
83
84 public TiffOutputDirectory(final int type, final ByteOrder byteOrder) {
85 this.type = type;
86 this.byteOrder = byteOrder;
87 }
88
89 public void add(final TagInfoAscii tagInfo, final String... values) throws ImagingException {
90 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
91 if (tagInfo.length > 0 && tagInfo.length != bytes.length) {
92 throw new ImagingException("Tag expects " + tagInfo.length + " byte(s), not " + values.length);
93 }
94 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.ASCII, bytes.length, bytes);
95 add(tiffOutputField);
96 }
97
98 public void add(final TagInfoAsciiOrByte tagInfo, final String... values) throws ImagingException {
99 final byte[] bytes = tagInfo.encodeValue(AbstractFieldType.ASCII, values, byteOrder);
100 if (tagInfo.length > 0 && tagInfo.length != bytes.length) {
101 throw new ImagingException("Tag expects " + tagInfo.length + " byte(s), not " + values.length);
102 }
103 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.ASCII, bytes.length, bytes);
104 add(tiffOutputField);
105 }
106
107 public void add(final TagInfoAsciiOrRational tagInfo, final RationalNumber... values) throws ImagingException {
108 if (tagInfo.length > 0 && tagInfo.length != values.length) {
109 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
110 }
111 final byte[] bytes = tagInfo.encodeValue(AbstractFieldType.RATIONAL, values, byteOrder);
112 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.RATIONAL, bytes.length, bytes);
113 add(tiffOutputField);
114 }
115
116 public void add(final TagInfoAsciiOrRational tagInfo, final String... values) throws ImagingException {
117 final byte[] bytes = tagInfo.encodeValue(AbstractFieldType.ASCII, values, byteOrder);
118 if (tagInfo.length > 0 && tagInfo.length != bytes.length) {
119 throw new ImagingException("Tag expects " + tagInfo.length + " byte(s), not " + values.length);
120 }
121 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.ASCII, bytes.length, bytes);
122 add(tiffOutputField);
123 }
124
125 public void add(final TagInfoByte tagInfo, final byte value) throws ImagingException {
126 if (tagInfo.length != 1) {
127 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
128 }
129 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
130 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.BYTE, bytes.length, bytes);
131 add(tiffOutputField);
132 }
133
134 public void add(final TagInfoByteOrShort tagInfo, final byte... values) throws ImagingException {
135 if (tagInfo.length > 0 && tagInfo.length != values.length) {
136 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
137 }
138 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
139 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.BYTE, values.length, bytes);
140 add(tiffOutputField);
141 }
142
143 public void add(final TagInfoByteOrShort tagInfo, final short... values) throws ImagingException {
144 if (tagInfo.length > 0 && tagInfo.length != values.length) {
145 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
146 }
147 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
148 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, values.length, bytes);
149 add(tiffOutputField);
150 }
151
152 public void add(final TagInfoBytes tagInfo, final byte... values) throws ImagingException {
153 if (tagInfo.length > 0 && tagInfo.length != values.length) {
154 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
155 }
156 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
157 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.BYTE, values.length, bytes);
158 add(tiffOutputField);
159 }
160
161 public void add(final TagInfoDouble tagInfo, final double value) throws ImagingException {
162 if (tagInfo.length != 1) {
163 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
164 }
165 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
166 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.DOUBLE, 1, bytes);
167 add(tiffOutputField);
168 }
169
170 public void add(final TagInfoDoubles tagInfo, final double... values) throws ImagingException {
171 if (tagInfo.length > 0 && tagInfo.length != values.length) {
172 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
173 }
174 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
175 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.DOUBLE, values.length, bytes);
176 add(tiffOutputField);
177 }
178
179 public void add(final TagInfoFloat tagInfo, final float value) throws ImagingException {
180 if (tagInfo.length != 1) {
181 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
182 }
183 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
184 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.FLOAT, 1, bytes);
185 add(tiffOutputField);
186 }
187
188 public void add(final TagInfoFloats tagInfo, final float... values) throws ImagingException {
189 if (tagInfo.length > 0 && tagInfo.length != values.length) {
190 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
191 }
192 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
193 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.FLOAT, values.length, bytes);
194 add(tiffOutputField);
195 }
196
197 public void add(final TagInfoGpsText tagInfo, final String value) throws ImagingException {
198 final byte[] bytes = tagInfo.encodeValue(AbstractFieldType.UNDEFINED, value, byteOrder);
199 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, tagInfo.dataTypes.get(0), bytes.length, bytes);
200 add(tiffOutputField);
201 }
202
203 public void add(final TagInfoLong tagInfo, final int value) throws ImagingException {
204 if (tagInfo.length != 1) {
205 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
206 }
207 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
208 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.LONG, 1, bytes);
209 add(tiffOutputField);
210 }
211
212 public void add(final TagInfoLongs tagInfo, final int... values) throws ImagingException {
213 if (tagInfo.length > 0 && tagInfo.length != values.length) {
214 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
215 }
216 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
217 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.LONG, values.length, bytes);
218 add(tiffOutputField);
219 }
220
221 public void add(final TagInfoRational tagInfo, final RationalNumber value) throws ImagingException {
222 if (tagInfo.length != 1) {
223 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
224 }
225 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
226 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.RATIONAL, 1, bytes);
227 add(tiffOutputField);
228 }
229
230 public void add(final TagInfoRationals tagInfo, final RationalNumber... values) throws ImagingException {
231 if (tagInfo.length > 0 && tagInfo.length != values.length) {
232 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
233 }
234 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
235 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.RATIONAL, values.length, bytes);
236 add(tiffOutputField);
237 }
238
239 public void add(final TagInfoSByte tagInfo, final byte value) throws ImagingException {
240 if (tagInfo.length != 1) {
241 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
242 }
243 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
244 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SBYTE, 1, bytes);
245 add(tiffOutputField);
246 }
247
248 public void add(final TagInfoSBytes tagInfo, final byte... values) throws ImagingException {
249 if (tagInfo.length > 0 && tagInfo.length != values.length) {
250 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
251 }
252 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
253 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SBYTE, values.length, bytes);
254 add(tiffOutputField);
255 }
256
257 public void add(final TagInfoShort tagInfo, final short value) throws ImagingException {
258 if (tagInfo.length != 1) {
259 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
260 }
261 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
262 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, 1, bytes);
263 add(tiffOutputField);
264 }
265
266 public void add(final TagInfoShortOrLong tagInfo, final int... values) throws ImagingException {
267 if (tagInfo.length > 0 && tagInfo.length != values.length) {
268 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
269 }
270 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
271 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.LONG, values.length, bytes);
272 add(tiffOutputField);
273 }
274
275 public void add(final TagInfoShortOrLong tagInfo, final short... values) throws ImagingException {
276 if (tagInfo.length > 0 && tagInfo.length != values.length) {
277 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
278 }
279 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
280 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, values.length, bytes);
281 add(tiffOutputField);
282 }
283
284 public void add(final TagInfoShortOrLongOrRational tagInfo, final int... values) throws ImagingException {
285 if (tagInfo.length > 0 && tagInfo.length != values.length) {
286 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
287 }
288 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
289 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.LONG, values.length, bytes);
290 add(tiffOutputField);
291 }
292
293 public void add(final TagInfoShortOrLongOrRational tagInfo, final RationalNumber... values) throws ImagingException {
294 if (tagInfo.length > 0 && tagInfo.length != values.length) {
295 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
296 }
297 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
298 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.RATIONAL, values.length, bytes);
299 add(tiffOutputField);
300 }
301
302 public void add(final TagInfoShortOrLongOrRational tagInfo, final short... values) throws ImagingException {
303 if (tagInfo.length > 0 && tagInfo.length != values.length) {
304 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
305 }
306 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
307 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, values.length, bytes);
308 add(tiffOutputField);
309 }
310
311 public void add(final TagInfoShortOrRational tagInfo, final RationalNumber... values) throws ImagingException {
312 if (tagInfo.length > 0 && tagInfo.length != values.length) {
313 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
314 }
315 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
316 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.RATIONAL, values.length, bytes);
317 add(tiffOutputField);
318 }
319
320 public void add(final TagInfoShortOrRational tagInfo, final short... values) throws ImagingException {
321 if (tagInfo.length > 0 && tagInfo.length != values.length) {
322 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
323 }
324 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
325 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, values.length, bytes);
326 add(tiffOutputField);
327 }
328
329 public void add(final TagInfoShorts tagInfo, final short... values) throws ImagingException {
330 if (tagInfo.length > 0 && tagInfo.length != values.length) {
331 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
332 }
333 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
334 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SHORT, values.length, bytes);
335 add(tiffOutputField);
336 }
337
338 public void add(final TagInfoSLong tagInfo, final int value) throws ImagingException {
339 if (tagInfo.length != 1) {
340 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
341 }
342 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
343 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SLONG, 1, bytes);
344 add(tiffOutputField);
345 }
346
347 public void add(final TagInfoSLongs tagInfo, final int... values) throws ImagingException {
348 if (tagInfo.length > 0 && tagInfo.length != values.length) {
349 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
350 }
351 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
352 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SLONG, values.length, bytes);
353 add(tiffOutputField);
354 }
355
356 public void add(final TagInfoSRational tagInfo, final RationalNumber value) throws ImagingException {
357 if (tagInfo.length != 1) {
358 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
359 }
360 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
361 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SRATIONAL, 1, bytes);
362 add(tiffOutputField);
363 }
364
365 public void add(final TagInfoSRationals tagInfo, final RationalNumber... values) throws ImagingException {
366 if (tagInfo.length > 0 && tagInfo.length != values.length) {
367 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
368 }
369 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
370 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SRATIONAL, values.length, bytes);
371 add(tiffOutputField);
372 }
373
374 public void add(final TagInfoSShort tagInfo, final short value) throws ImagingException {
375 if (tagInfo.length != 1) {
376 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not 1");
377 }
378 final byte[] bytes = tagInfo.encodeValue(byteOrder, value);
379 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SSHORT, 1, bytes);
380 add(tiffOutputField);
381 }
382
383 public void add(final TagInfoSShorts tagInfo, final short... values) throws ImagingException {
384 if (tagInfo.length > 0 && tagInfo.length != values.length) {
385 throw new ImagingException("Tag expects " + tagInfo.length + " value(s), not " + values.length);
386 }
387 final byte[] bytes = tagInfo.encodeValue(byteOrder, values);
388 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.SSHORT, values.length, bytes);
389 add(tiffOutputField);
390 }
391
392 public void add(final TagInfoXpString tagInfo, final String value) throws ImagingException {
393 final byte[] bytes = tagInfo.encodeValue(AbstractFieldType.BYTE, value, byteOrder);
394 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, tagInfo, AbstractFieldType.BYTE, bytes.length, bytes);
395 add(tiffOutputField);
396 }
397
398 public void add(final TiffOutputField field) {
399 fields.add(field);
400 }
401
402 public String description() {
403 return TiffDirectory.description(getType());
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417 public TiffOutputField findField(final int tag) {
418 for (final TiffOutputField field : fields) {
419 if (field.tag == tag) {
420 return field;
421 }
422 }
423 return null;
424 }
425
426
427
428
429
430
431
432
433
434
435
436
437 public TiffOutputField findField(final TagInfo tagInfo) {
438 return findField(tagInfo.tag);
439 }
440
441 public List<TiffOutputField> getFields() {
442 return new ArrayList<>(fields);
443 }
444
445 @Override
446 public String getItemDescription() {
447 final TiffDirectoryType dirType = TiffDirectoryType.getExifDirectoryType(getType());
448 return "Directory: " + dirType.name + " (" + getType() + ")";
449 }
450
451 @Override
452 public int getItemLength() {
453 return TIFF_ENTRY_LENGTH * fields.size() + TIFF_DIRECTORY_HEADER_LENGTH + TIFF_DIRECTORY_FOOTER_LENGTH;
454 }
455
456 protected List<AbstractTiffOutputItem> getOutputItems(final TiffOutputSummary outputSummary) throws ImagingException {
457
458
459 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT);
460 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
461
462 TiffOutputField jpegOffsetField = null;
463 if (null != jpegImageData) {
464 jpegOffsetField = new TiffOutputField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT, AbstractFieldType.LONG, 1,
465 new byte[TIFF_ENTRY_MAX_VALUE_LENGTH]);
466 add(jpegOffsetField);
467
468 final byte[] lengthValue = AbstractFieldType.LONG.writeData(jpegImageData.length, outputSummary.byteOrder);
469
470 final TiffOutputField jpegLengthField = new TiffOutputField(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, AbstractFieldType.LONG, 1,
471 lengthValue);
472 add(jpegLengthField);
473
474 }
475
476 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS);
477 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS);
478 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_OFFSETS);
479 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS);
480
481 TiffOutputField imageDataOffsetField;
482 ImageDataOffsets imageDataInfo = null;
483 if (null != abstractTiffImageData) {
484 final boolean stripsNotTiles = abstractTiffImageData.stripsNotTiles();
485
486 TagInfo offsetTag;
487 TagInfo byteCountsTag;
488 if (stripsNotTiles) {
489 offsetTag = TiffTagConstants.TIFF_TAG_STRIP_OFFSETS;
490 byteCountsTag = TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS;
491 } else {
492 offsetTag = TiffTagConstants.TIFF_TAG_TILE_OFFSETS;
493 byteCountsTag = TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS;
494 }
495
496 final AbstractTiffElement.DataElement[] imageData = abstractTiffImageData.getImageData();
497
498
499
500 final int[] imageDataOffsets = Allocator.intArray(imageData.length);
501 final int[] imageDataByteCounts = Allocator.intArray(imageData.length);
502 Arrays.setAll(imageDataByteCounts, i -> imageData[i].length);
503
504
505 imageDataOffsetField = new TiffOutputField(offsetTag, AbstractFieldType.LONG, imageDataOffsets.length,
506 AbstractFieldType.LONG.writeData(imageDataOffsets, outputSummary.byteOrder));
507 add(imageDataOffsetField);
508
509 final byte[] data = AbstractFieldType.LONG.writeData(imageDataByteCounts, outputSummary.byteOrder);
510 final TiffOutputField byteCountsField = new TiffOutputField(byteCountsTag, AbstractFieldType.LONG, imageDataByteCounts.length, data);
511 add(byteCountsField);
512
513 imageDataInfo = new ImageDataOffsets(imageData, imageDataOffsets, imageDataOffsetField);
514 }
515
516 final List<AbstractTiffOutputItem> result = new ArrayList<>();
517 result.add(this);
518 sortFields();
519
520 for (final TiffOutputField field : fields) {
521 if (field.isLocalValue()) {
522 continue;
523 }
524
525 final AbstractTiffOutputItem item = field.getSeperateValue();
526 result.add(item);
527
528 }
529
530 if (null != imageDataInfo) {
531 Collections.addAll(result, imageDataInfo.outputItems);
532
533 outputSummary.addTiffImageData(imageDataInfo);
534 }
535
536 if (null != jpegImageData) {
537 final AbstractTiffOutputItem item = new AbstractTiffOutputItem.Value("JPEG image data", jpegImageData.getData());
538 result.add(item);
539 outputSummary.add(item, jpegOffsetField);
540 }
541
542 return result;
543 }
544
545 public JpegImageData getRawJpegImageData() {
546 return jpegImageData;
547 }
548
549 public AbstractTiffImageData getRawTiffImageData() {
550 return abstractTiffImageData;
551 }
552
553 public int getType() {
554 return type;
555 }
556
557 @Override
558 public Iterator<TiffOutputField> iterator() {
559 return fields.iterator();
560 }
561
562 public void removeField(final int tag) {
563 final List<TiffOutputField> matches = new ArrayList<>();
564 for (final TiffOutputField field : fields) {
565 if (field.tag == tag) {
566 matches.add(field);
567 }
568 }
569 fields.removeAll(matches);
570 }
571
572 public void removeField(final TagInfo tagInfo) {
573 removeField(tagInfo.tag);
574 }
575
576 private void removeFieldIfPresent(final TagInfo tagInfo) {
577 final TiffOutputField field = findField(tagInfo);
578 if (null != field) {
579 fields.remove(field);
580 }
581 }
582
583 public void setJpegImageData(final JpegImageData rawJpegImageData) {
584 this.jpegImageData = rawJpegImageData;
585 }
586
587 public void setNextDirectory(final TiffOutputDirectory nextDirectory) {
588 this.nextDirectory = nextDirectory;
589 }
590
591 public void setTiffImageData(final AbstractTiffImageData rawTiffImageData) {
592 this.abstractTiffImageData = rawTiffImageData;
593 }
594
595 public void sortFields() {
596 final Comparator<TiffOutputField> comparator = (e1, e2) -> {
597 if (e1.tag != e2.tag) {
598 return e1.tag - e2.tag;
599 }
600 return e1.getSortHint() - e2.getSortHint();
601 };
602 fields.sort(comparator);
603 }
604
605 @Override
606 public void writeItem(final BinaryOutputStream bos) throws IOException, ImagingException {
607
608 bos.write2Bytes(fields.size());
609
610
611 for (final TiffOutputField field : fields) {
612 field.writeField(bos);
613
614
615
616
617
618 }
619
620 long nextDirectoryOffset = 0;
621 if (nextDirectory != null) {
622 nextDirectoryOffset = nextDirectory.getOffset();
623 }
624
625
626 if (nextDirectoryOffset == UNDEFINED_VALUE) {
627 bos.write4Bytes(0);
628 } else {
629 bos.write4Bytes((int) nextDirectoryOffset);
630 }
631 }
632 }