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.write; 018 019import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_DIRECTORY_FOOTER_LENGTH; 020import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_DIRECTORY_HEADER_LENGTH; 021import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_LENGTH; 022import static org.apache.commons.imaging.formats.tiff.constants.TiffConstants.TIFF_ENTRY_MAX_VALUE_LENGTH; 023 024import java.io.IOException; 025import java.nio.ByteOrder; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.Comparator; 029import java.util.List; 030 031import org.apache.commons.imaging.ImageWriteException; 032import org.apache.commons.imaging.common.BinaryOutputStream; 033import org.apache.commons.imaging.common.RationalNumber; 034import org.apache.commons.imaging.formats.tiff.JpegImageData; 035import org.apache.commons.imaging.formats.tiff.TiffDirectory; 036import org.apache.commons.imaging.formats.tiff.TiffElement; 037import org.apache.commons.imaging.formats.tiff.TiffImageData; 038import org.apache.commons.imaging.formats.tiff.constants.TiffDirectoryType; 039import org.apache.commons.imaging.formats.tiff.constants.TiffTagConstants; 040import org.apache.commons.imaging.formats.tiff.fieldtypes.FieldType; 041import org.apache.commons.imaging.formats.tiff.taginfos.TagInfo; 042import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAscii; 043import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAsciiOrByte; 044import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoAsciiOrRational; 045import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoByte; 046import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoByteOrShort; 047import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoBytes; 048import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDouble; 049import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoDoubles; 050import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloat; 051import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoFloats; 052import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoGpsText; 053import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLong; 054import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoLongs; 055import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRational; 056import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoRationals; 057import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSByte; 058import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSBytes; 059import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLong; 060import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSLongs; 061import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRational; 062import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSRationals; 063import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShort; 064import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoSShorts; 065import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShort; 066import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrLong; 067import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrLongOrRational; 068import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShortOrRational; 069import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoShorts; 070import org.apache.commons.imaging.formats.tiff.taginfos.TagInfoXpString; 071 072public final class TiffOutputDirectory extends TiffOutputItem { 073 public final int type; 074 private final List<TiffOutputField> fields = new ArrayList<>(); 075 private final ByteOrder byteOrder; 076 private TiffOutputDirectory nextDirectory; 077 public static final Comparator<TiffOutputDirectory> COMPARATOR = Comparator.comparingInt(o -> o.type); 078 private JpegImageData jpegImageData; 079 private TiffImageData tiffImageData; 080 081 public void setNextDirectory(final TiffOutputDirectory nextDirectory) { 082 this.nextDirectory = nextDirectory; 083 } 084 085 public TiffOutputDirectory(final int type, final ByteOrder byteOrder) { 086 this.type = type; 087 this.byteOrder = byteOrder; 088 } 089 090 public void add(final TagInfoByte tagInfo, final byte value) 091 throws ImageWriteException { 092 if (tagInfo.length != 1) { 093 throw new ImageWriteException("Tag expects " + tagInfo.length 094 + " value(s), not 1"); 095 } 096 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 097 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 098 tagInfo, FieldType.BYTE, bytes.length, bytes); 099 add(tiffOutputField); 100 } 101 102 public void add(final TagInfoBytes tagInfo, final byte... values) 103 throws ImageWriteException { 104 if (tagInfo.length > 0 && tagInfo.length != values.length) { 105 throw new ImageWriteException("Tag expects " + tagInfo.length 106 + " value(s), not " + values.length); 107 } 108 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 109 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 110 tagInfo, FieldType.BYTE, values.length, 111 bytes); 112 add(tiffOutputField); 113 } 114 115 public void add(final TagInfoAscii tagInfo, final String... values) 116 throws ImageWriteException { 117 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 118 if (tagInfo.length > 0 && tagInfo.length != bytes.length) { 119 throw new ImageWriteException("Tag expects " + tagInfo.length 120 + " byte(s), not " + values.length); 121 } 122 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 123 tagInfo, FieldType.ASCII, bytes.length, 124 bytes); 125 add(tiffOutputField); 126 } 127 128 public void add(final TagInfoShort tagInfo, final short value) 129 throws ImageWriteException { 130 if (tagInfo.length != 1) { 131 throw new ImageWriteException("Tag expects " + tagInfo.length 132 + " value(s), not 1"); 133 } 134 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 135 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 136 tagInfo, FieldType.SHORT, 1, bytes); 137 add(tiffOutputField); 138 } 139 140 public void add(final TagInfoShorts tagInfo, final short... values) 141 throws ImageWriteException { 142 if (tagInfo.length > 0 && tagInfo.length != values.length) { 143 throw new ImageWriteException("Tag expects " + tagInfo.length 144 + " value(s), not " + values.length); 145 } 146 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 147 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 148 tagInfo, FieldType.SHORT, 149 values.length, bytes); 150 add(tiffOutputField); 151 } 152 153 public void add(final TagInfoLong tagInfo, final int value) 154 throws ImageWriteException { 155 if (tagInfo.length != 1) { 156 throw new ImageWriteException("Tag expects " + tagInfo.length 157 + " value(s), not 1"); 158 } 159 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 160 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 161 tagInfo, FieldType.LONG, 1, bytes); 162 add(tiffOutputField); 163 } 164 165 public void add(final TagInfoLongs tagInfo, final int... values) 166 throws ImageWriteException { 167 if (tagInfo.length > 0 && tagInfo.length != values.length) { 168 throw new ImageWriteException("Tag expects " + tagInfo.length 169 + " value(s), not " + values.length); 170 } 171 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 172 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 173 tagInfo, FieldType.LONG, values.length, 174 bytes); 175 add(tiffOutputField); 176 } 177 178 public void add(final TagInfoRational tagInfo, final RationalNumber value) 179 throws ImageWriteException { 180 if (tagInfo.length != 1) { 181 throw new ImageWriteException("Tag expects " + tagInfo.length 182 + " value(s), not 1"); 183 } 184 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 185 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 186 tagInfo, FieldType.RATIONAL, 1, bytes); 187 add(tiffOutputField); 188 } 189 190 public void add(final TagInfoRationals tagInfo, final RationalNumber... values) 191 throws ImageWriteException { 192 if (tagInfo.length > 0 && tagInfo.length != values.length) { 193 throw new ImageWriteException("Tag expects " + tagInfo.length 194 + " value(s), not " + values.length); 195 } 196 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 197 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 198 tagInfo, FieldType.RATIONAL, 199 values.length, bytes); 200 add(tiffOutputField); 201 } 202 203 public void add(final TagInfoSByte tagInfo, final byte value) 204 throws ImageWriteException { 205 if (tagInfo.length != 1) { 206 throw new ImageWriteException("Tag expects " + tagInfo.length 207 + " value(s), not 1"); 208 } 209 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 210 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 211 tagInfo, FieldType.SBYTE, 1, bytes); 212 add(tiffOutputField); 213 } 214 215 public void add(final TagInfoSBytes tagInfo, final byte... values) 216 throws ImageWriteException { 217 if (tagInfo.length > 0 && tagInfo.length != values.length) { 218 throw new ImageWriteException("Tag expects " + tagInfo.length 219 + " value(s), not " + values.length); 220 } 221 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 222 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 223 tagInfo, FieldType.SBYTE, 224 values.length, bytes); 225 add(tiffOutputField); 226 } 227 228 public void add(final TagInfoSShort tagInfo, final short value) 229 throws ImageWriteException { 230 if (tagInfo.length != 1) { 231 throw new ImageWriteException("Tag expects " + tagInfo.length 232 + " value(s), not 1"); 233 } 234 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 235 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 236 tagInfo, FieldType.SSHORT, 1, bytes); 237 add(tiffOutputField); 238 } 239 240 public void add(final TagInfoSShorts tagInfo, final short... values) 241 throws ImageWriteException { 242 if (tagInfo.length > 0 && tagInfo.length != values.length) { 243 throw new ImageWriteException("Tag expects " + tagInfo.length 244 + " value(s), not " + values.length); 245 } 246 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 247 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 248 tagInfo, FieldType.SSHORT, 249 values.length, bytes); 250 add(tiffOutputField); 251 } 252 253 public void add(final TagInfoSLong tagInfo, final int value) 254 throws ImageWriteException { 255 if (tagInfo.length != 1) { 256 throw new ImageWriteException("Tag expects " + tagInfo.length 257 + " value(s), not 1"); 258 } 259 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 260 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 261 tagInfo, FieldType.SLONG, 1, bytes); 262 add(tiffOutputField); 263 } 264 265 public void add(final TagInfoSLongs tagInfo, final int... values) 266 throws ImageWriteException { 267 if (tagInfo.length > 0 && tagInfo.length != values.length) { 268 throw new ImageWriteException("Tag expects " + tagInfo.length 269 + " value(s), not " + values.length); 270 } 271 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 272 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 273 tagInfo, FieldType.SLONG, 274 values.length, bytes); 275 add(tiffOutputField); 276 } 277 278 public void add(final TagInfoSRational tagInfo, final RationalNumber value) 279 throws ImageWriteException { 280 if (tagInfo.length != 1) { 281 throw new ImageWriteException("Tag expects " + tagInfo.length 282 + " value(s), not 1"); 283 } 284 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 285 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 286 tagInfo, FieldType.SRATIONAL, 1, bytes); 287 add(tiffOutputField); 288 } 289 290 public void add(final TagInfoSRationals tagInfo, final RationalNumber... values) 291 throws ImageWriteException { 292 if (tagInfo.length > 0 && tagInfo.length != values.length) { 293 throw new ImageWriteException("Tag expects " + tagInfo.length 294 + " value(s), not " + values.length); 295 } 296 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 297 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 298 tagInfo, FieldType.SRATIONAL, 299 values.length, bytes); 300 add(tiffOutputField); 301 } 302 303 public void add(final TagInfoFloat tagInfo, final float value) 304 throws ImageWriteException { 305 if (tagInfo.length != 1) { 306 throw new ImageWriteException("Tag expects " + tagInfo.length 307 + " value(s), not 1"); 308 } 309 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 310 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 311 tagInfo, FieldType.FLOAT, 1, bytes); 312 add(tiffOutputField); 313 } 314 315 public void add(final TagInfoFloats tagInfo, final float... values) 316 throws ImageWriteException { 317 if (tagInfo.length > 0 && tagInfo.length != values.length) { 318 throw new ImageWriteException("Tag expects " + tagInfo.length 319 + " value(s), not " + values.length); 320 } 321 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 322 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 323 tagInfo, FieldType.FLOAT, 324 values.length, bytes); 325 add(tiffOutputField); 326 } 327 328 public void add(final TagInfoDouble tagInfo, final double value) 329 throws ImageWriteException { 330 if (tagInfo.length != 1) { 331 throw new ImageWriteException("Tag expects " + tagInfo.length 332 + " value(s), not 1"); 333 } 334 final byte[] bytes = tagInfo.encodeValue(byteOrder, value); 335 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 336 tagInfo, FieldType.DOUBLE, 1, bytes); 337 add(tiffOutputField); 338 } 339 340 public void add(final TagInfoDoubles tagInfo, final double... values) 341 throws ImageWriteException { 342 if (tagInfo.length > 0 && tagInfo.length != values.length) { 343 throw new ImageWriteException("Tag expects " + tagInfo.length 344 + " value(s), not " + values.length); 345 } 346 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 347 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 348 tagInfo, FieldType.DOUBLE, 349 values.length, bytes); 350 add(tiffOutputField); 351 } 352 353 public void add(final TagInfoByteOrShort tagInfo, final byte... values) 354 throws ImageWriteException { 355 if (tagInfo.length > 0 && tagInfo.length != values.length) { 356 throw new ImageWriteException("Tag expects " + tagInfo.length 357 + " value(s), not " + values.length); 358 } 359 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 360 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 361 tagInfo, FieldType.BYTE, values.length, 362 bytes); 363 add(tiffOutputField); 364 } 365 366 public void add(final TagInfoByteOrShort tagInfo, final short... values) 367 throws ImageWriteException { 368 if (tagInfo.length > 0 && tagInfo.length != values.length) { 369 throw new ImageWriteException("Tag expects " + tagInfo.length 370 + " value(s), not " + values.length); 371 } 372 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 373 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 374 tagInfo, FieldType.SHORT, 375 values.length, bytes); 376 add(tiffOutputField); 377 } 378 379 public void add(final TagInfoShortOrLong tagInfo, final short... values) 380 throws ImageWriteException { 381 if (tagInfo.length > 0 && tagInfo.length != values.length) { 382 throw new ImageWriteException("Tag expects " + tagInfo.length 383 + " value(s), not " + values.length); 384 } 385 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 386 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 387 tagInfo, FieldType.SHORT, 388 values.length, bytes); 389 add(tiffOutputField); 390 } 391 392 public void add(final TagInfoShortOrLong tagInfo, final int... values) 393 throws ImageWriteException { 394 if (tagInfo.length > 0 && tagInfo.length != values.length) { 395 throw new ImageWriteException("Tag expects " + tagInfo.length 396 + " value(s), not " + values.length); 397 } 398 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 399 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 400 tagInfo, FieldType.LONG, values.length, 401 bytes); 402 add(tiffOutputField); 403 } 404 405 public void add(final TagInfoShortOrLongOrRational tagInfo, final short... values) 406 throws ImageWriteException { 407 if (tagInfo.length > 0 && tagInfo.length != values.length) { 408 throw new ImageWriteException("Tag expects " + tagInfo.length 409 + " value(s), not " + values.length); 410 } 411 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 412 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 413 tagInfo, FieldType.SHORT, 414 values.length, bytes); 415 add(tiffOutputField); 416 } 417 418 public void add(final TagInfoShortOrLongOrRational tagInfo, final int... values) 419 throws ImageWriteException { 420 if (tagInfo.length > 0 && tagInfo.length != values.length) { 421 throw new ImageWriteException("Tag expects " + tagInfo.length 422 + " value(s), not " + values.length); 423 } 424 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 425 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 426 tagInfo, FieldType.LONG, values.length, 427 bytes); 428 add(tiffOutputField); 429 } 430 431 public void add(final TagInfoShortOrLongOrRational tagInfo, 432 final RationalNumber... values) throws ImageWriteException { 433 if (tagInfo.length > 0 && tagInfo.length != values.length) { 434 throw new ImageWriteException("Tag expects " + tagInfo.length 435 + " value(s), not " + values.length); 436 } 437 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 438 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 439 tagInfo, FieldType.RATIONAL, 440 values.length, bytes); 441 add(tiffOutputField); 442 } 443 444 public void add(final TagInfoShortOrRational tagInfo, final short... values) 445 throws ImageWriteException { 446 if (tagInfo.length > 0 && tagInfo.length != values.length) { 447 throw new ImageWriteException("Tag expects " + tagInfo.length 448 + " value(s), not " + values.length); 449 } 450 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 451 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 452 tagInfo, FieldType.SHORT, 453 values.length, bytes); 454 add(tiffOutputField); 455 } 456 457 public void add(final TagInfoShortOrRational tagInfo, final RationalNumber... values) 458 throws ImageWriteException { 459 if (tagInfo.length > 0 && tagInfo.length != values.length) { 460 throw new ImageWriteException("Tag expects " + tagInfo.length 461 + " value(s), not " + values.length); 462 } 463 final byte[] bytes = tagInfo.encodeValue(byteOrder, values); 464 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 465 tagInfo, FieldType.RATIONAL, 466 values.length, bytes); 467 add(tiffOutputField); 468 } 469 470 public void add(final TagInfoGpsText tagInfo, final String value) 471 throws ImageWriteException { 472 final byte[] bytes = tagInfo.encodeValue( 473 FieldType.UNDEFINED, value, byteOrder); 474 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 475 tagInfo, tagInfo.dataTypes.get(0), bytes.length, bytes); 476 add(tiffOutputField); 477 } 478 479 public void add(final TagInfoXpString tagInfo, final String value) 480 throws ImageWriteException { 481 final byte[] bytes = tagInfo.encodeValue( 482 FieldType.BYTE, value, byteOrder); 483 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 484 tagInfo, FieldType.BYTE, bytes.length, 485 bytes); 486 add(tiffOutputField); 487 } 488 489 public void add(final TagInfoAsciiOrByte tagInfo, final String... values) 490 throws ImageWriteException { 491 final byte[] bytes = tagInfo.encodeValue( 492 FieldType.ASCII, values, byteOrder); 493 if (tagInfo.length > 0 && tagInfo.length != bytes.length) { 494 throw new ImageWriteException("Tag expects " + tagInfo.length 495 + " byte(s), not " + values.length); 496 } 497 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 498 tagInfo, FieldType.ASCII, bytes.length, 499 bytes); 500 add(tiffOutputField); 501 } 502 503 public void add(final TagInfoAsciiOrRational tagInfo, final String... values) 504 throws ImageWriteException { 505 final byte[] bytes = tagInfo.encodeValue( 506 FieldType.ASCII, values, byteOrder); 507 if (tagInfo.length > 0 && tagInfo.length != bytes.length) { 508 throw new ImageWriteException("Tag expects " + tagInfo.length 509 + " byte(s), not " + values.length); 510 } 511 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 512 tagInfo, FieldType.ASCII, bytes.length, 513 bytes); 514 add(tiffOutputField); 515 } 516 517 public void add(final TagInfoAsciiOrRational tagInfo, final RationalNumber... values) 518 throws ImageWriteException { 519 if (tagInfo.length > 0 && tagInfo.length != values.length) { 520 throw new ImageWriteException("Tag expects " + tagInfo.length 521 + " value(s), not " + values.length); 522 } 523 final byte[] bytes = tagInfo.encodeValue( 524 FieldType.RATIONAL, values, byteOrder); 525 final TiffOutputField tiffOutputField = new TiffOutputField(tagInfo.tag, 526 tagInfo, FieldType.RATIONAL, 527 bytes.length, bytes); 528 add(tiffOutputField); 529 } 530 531 public void add(final TiffOutputField field) { 532 fields.add(field); 533 } 534 535 public List<TiffOutputField> getFields() { 536 return new ArrayList<>(fields); 537 } 538 539 public void removeField(final TagInfo tagInfo) { 540 removeField(tagInfo.tag); 541 } 542 543 public void removeField(final int tag) { 544 final List<TiffOutputField> matches = new ArrayList<>(); 545 for (final TiffOutputField field : fields) { 546 if (field.tag == tag) { 547 matches.add(field); 548 } 549 } 550 fields.removeAll(matches); 551 } 552 553 /** 554 * Finds the TiffOutputField for the given TagInfo from this TiffOutputDirectory. 555 * 556 * <p> 557 * If there is no field matching the given TagInfo, null will be returned. 558 * </p> 559 * 560 * @param tagInfo the TagInfo specifying the field 561 * @return the field matching tagInfo or null, if the field isn't present 562 * @see #findField(int) 563 */ 564 public TiffOutputField findField(final TagInfo tagInfo) { 565 return findField(tagInfo.tag); 566 } 567 568 /** 569 * Finds the TiffOutputField for the given tag from this TiffOutputDirectory. 570 * 571 * <p> 572 * If there is no field matching the given tag, null will be returned. 573 * </p> 574 * 575 * @param tag the tag specifying the field 576 * @return the field matching tagInfo or null, if the field isn't present 577 * @see #findField(TagInfo) 578 */ 579 public TiffOutputField findField(final int tag) { 580 for (final TiffOutputField field : fields) { 581 if (field.tag == tag) { 582 return field; 583 } 584 } 585 return null; 586 } 587 588 public void sortFields() { 589 final Comparator<TiffOutputField> comparator = (e1, e2) -> { 590 if (e1.tag != e2.tag) { 591 return e1.tag - e2.tag; 592 } 593 return e1.getSortHint() - e2.getSortHint(); 594 }; 595 fields.sort(comparator); 596 } 597 598 public String description() { 599 return TiffDirectory.description(type); 600 } 601 602 @Override 603 public void writeItem(final BinaryOutputStream bos) throws IOException, 604 ImageWriteException { 605 // Write Directory Field Count 606 bos.write2Bytes(fields.size()); // DirectoryFieldCount 607 608 // Write Fields 609 for (final TiffOutputField field : fields) { 610 field.writeField(bos); 611 612 // Debug.debug("\t" + "writing field (" + field.tag + ", 0x" + 613 // Integer.toHexString(field.tag) + ")", field.tagInfo); 614 // if(field.tagInfo.isOffset()) 615 // Debug.debug("\t\tOFFSET!", field.bytes); 616 } 617 618 long nextDirectoryOffset = 0; 619 if (nextDirectory != null) { 620 nextDirectoryOffset = nextDirectory.getOffset(); 621 } 622 623 // Write nextDirectoryOffset 624 if (nextDirectoryOffset == UNDEFINED_VALUE) { 625 bos.write4Bytes(0); 626 } else { 627 bos.write4Bytes((int) nextDirectoryOffset); 628 } 629 } 630 631 public void setJpegImageData(final JpegImageData rawJpegImageData) { 632 this.jpegImageData = rawJpegImageData; 633 } 634 635 public JpegImageData getRawJpegImageData() { 636 return jpegImageData; 637 } 638 639 public void setTiffImageData(final TiffImageData rawTiffImageData) { 640 this.tiffImageData = rawTiffImageData; 641 } 642 643 public TiffImageData getRawTiffImageData() { 644 return tiffImageData; 645 } 646 647 @Override 648 public int getItemLength() { 649 return TIFF_ENTRY_LENGTH * fields.size() + TIFF_DIRECTORY_HEADER_LENGTH 650 + TIFF_DIRECTORY_FOOTER_LENGTH; 651 } 652 653 @Override 654 public String getItemDescription() { 655 final TiffDirectoryType dirType = TiffDirectoryType.getExifDirectoryType(type); 656 return "Directory: " + dirType.name + " (" + type + ")"; 657 } 658 659 private void removeFieldIfPresent(final TagInfo tagInfo) { 660 final TiffOutputField field = findField(tagInfo); 661 if (null != field) { 662 fields.remove(field); 663 } 664 } 665 666 protected List<TiffOutputItem> getOutputItems( 667 final TiffOutputSummary outputSummary) throws ImageWriteException { 668 // first validate directory fields. 669 670 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT); 671 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH); 672 673 TiffOutputField jpegOffsetField = null; 674 if (null != jpegImageData) { 675 jpegOffsetField = new TiffOutputField( 676 TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT, 677 FieldType.LONG, 1, new byte[TIFF_ENTRY_MAX_VALUE_LENGTH]); 678 add(jpegOffsetField); 679 680 final byte[] lengthValue = FieldType.LONG.writeData( 681 jpegImageData.length, 682 outputSummary.byteOrder); 683 684 final TiffOutputField jpegLengthField = new TiffOutputField( 685 TiffTagConstants.TIFF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, 686 FieldType.LONG, 1, lengthValue); 687 add(jpegLengthField); 688 689 } 690 691 // -------------------------------------------------------------- 692 693 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_OFFSETS); 694 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS); 695 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_OFFSETS); 696 removeFieldIfPresent(TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS); 697 698 TiffOutputField imageDataOffsetField; 699 ImageDataOffsets imageDataInfo = null; 700 if (null != tiffImageData) { 701 final boolean stripsNotTiles = tiffImageData.stripsNotTiles(); 702 703 TagInfo offsetTag; 704 TagInfo byteCountsTag; 705 if (stripsNotTiles) { 706 offsetTag = TiffTagConstants.TIFF_TAG_STRIP_OFFSETS; 707 byteCountsTag = TiffTagConstants.TIFF_TAG_STRIP_BYTE_COUNTS; 708 } else { 709 offsetTag = TiffTagConstants.TIFF_TAG_TILE_OFFSETS; 710 byteCountsTag = TiffTagConstants.TIFF_TAG_TILE_BYTE_COUNTS; 711 } 712 713 // -------- 714 715 final TiffElement.DataElement[] imageData = tiffImageData.getImageData(); 716 717 // TiffOutputField imageDataOffsetsField = null; 718 719 final int[] imageDataOffsets = new int[imageData.length]; 720 final int[] imageDataByteCounts = new int[imageData.length]; 721 for (int i = 0; i < imageData.length; i++) { 722 imageDataByteCounts[i] = imageData[i].length; 723 } 724 725 // -------- 726 727 // Append imageData-related fields to first directory 728 imageDataOffsetField = new TiffOutputField(offsetTag, 729 FieldType.LONG, imageDataOffsets.length, 730 FieldType.LONG.writeData(imageDataOffsets, 731 outputSummary.byteOrder)); 732 add(imageDataOffsetField); 733 734 // -------- 735 736 final byte[] data = FieldType.LONG.writeData(imageDataByteCounts, outputSummary.byteOrder); 737 final TiffOutputField byteCountsField = new TiffOutputField( 738 byteCountsTag, FieldType.LONG, imageDataByteCounts.length, 739 data); 740 add(byteCountsField); 741 742 // -------- 743 744 imageDataInfo = new ImageDataOffsets(imageData, imageDataOffsets, imageDataOffsetField); 745 } 746 747 // -------------------------------------------------------------- 748 749 final List<TiffOutputItem> result = new ArrayList<>(); 750 result.add(this); 751 sortFields(); 752 753 for (final TiffOutputField field : fields) { 754 if (field.isLocalValue()) { 755 continue; 756 } 757 758 final TiffOutputItem item = field.getSeperateValue(); 759 result.add(item); 760 // outputSummary.add(item, field); 761 } 762 763 if (null != imageDataInfo) { 764 Collections.addAll(result, imageDataInfo.outputItems); 765 766 outputSummary.addTiffImageData(imageDataInfo); 767 } 768 769 if (null != jpegImageData) { 770 final TiffOutputItem item = new TiffOutputItem.Value("JPEG image data", 771 jpegImageData.getData()); 772 result.add(item); 773 outputSummary.add(item, jpegOffsetField); 774 } 775 776 return result; 777 } 778}