001/* 002 * $RCSfile: TIFFImageMetadata.java,v $ 003 * 004 * 005 * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 011 * - Redistribution of source code must retain the above copyright 012 * notice, this list of conditions and the following disclaimer. 013 * 014 * - Redistribution in binary form must reproduce the above copyright 015 * notice, this list of conditions and the following disclaimer in 016 * the documentation and/or other materials provided with the 017 * distribution. 018 * 019 * Neither the name of Sun Microsystems, Inc. or the names of 020 * contributors may be used to endorse or promote products derived 021 * from this software without specific prior written permission. 022 * 023 * This software is provided "AS IS," without a warranty of any 024 * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 025 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 026 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY 027 * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 028 * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 029 * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS 030 * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 031 * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, 032 * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND 033 * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR 034 * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE 035 * POSSIBILITY OF SUCH DAMAGES. 036 * 037 * You acknowledge that this software is not designed or intended for 038 * use in the design, construction, operation or maintenance of any 039 * nuclear facility. 040 * 041 * $Revision: 1.11 $ 042 * $Date: 2006/07/21 22:56:55 $ 043 * $State: Exp $ 044 */ 045package com.github.jaiimageio.impl.plugins.tiff; 046 047import java.io.IOException; 048import java.lang.reflect.InvocationTargetException; 049import java.lang.reflect.Method; 050import java.util.ArrayList; 051import java.util.Arrays; 052import java.util.HashMap; 053import java.util.Iterator; 054import java.util.List; 055import java.util.StringTokenizer; 056 057import javax.imageio.metadata.IIOInvalidTreeException; 058import javax.imageio.metadata.IIOMetadata; 059import javax.imageio.metadata.IIOMetadataFormatImpl; 060import javax.imageio.metadata.IIOMetadataNode; 061import javax.imageio.stream.ImageInputStream; 062 063import org.w3c.dom.NamedNodeMap; 064import org.w3c.dom.Node; 065import org.w3c.dom.NodeList; 066 067import com.github.jaiimageio.plugins.tiff.BaselineTIFFTagSet; 068import com.github.jaiimageio.plugins.tiff.EXIFParentTIFFTagSet; 069import com.github.jaiimageio.plugins.tiff.TIFFField; 070import com.github.jaiimageio.plugins.tiff.TIFFTag; 071import com.github.jaiimageio.plugins.tiff.TIFFTagSet; 072 073public class TIFFImageMetadata extends IIOMetadata { 074 075 // package scope 076 077 public static final String SUN_BaselineTIFFTagSetClassName = 078 "com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet" ; 079 080 public static final String THISJAI_BaselineTIFFTagSetClassName = 081 "com.github.jaiimageio.plugins.tiff.BaselineTIFFTagSet"; 082 083 public static final String nativeMetadataFormatName = 084 "com_sun_media_imageio_plugins_tiff_image_1.0"; 085 086 public static final String nativeMetadataFormatClassName = 087 "com.github.jaiimageio.impl.plugins.tiff.TIFFImageMetadataFormat"; 088 089 List tagSets; 090 091 TIFFIFD rootIFD; 092 093 public TIFFImageMetadata(List tagSets) { 094 super(true, 095 nativeMetadataFormatName, 096 nativeMetadataFormatClassName, 097 null, null); 098 099 this.tagSets = tagSets; 100 this.rootIFD = new TIFFIFD(tagSets); 101 } 102 103 public TIFFImageMetadata(TIFFIFD ifd) { 104 super(true, 105 nativeMetadataFormatName, 106 nativeMetadataFormatClassName, 107 null, null); 108 this.tagSets = ifd.getTagSetList(); 109 this.rootIFD = ifd; 110 } 111 112 public void initializeFromStream(ImageInputStream stream, 113 boolean ignoreUnknownFields) 114 throws IOException { 115 rootIFD.initialize(stream, ignoreUnknownFields); 116 } 117 118 public void addShortOrLongField(int tagNumber, int value) { 119 TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value); 120 rootIFD.addTIFFField(field); 121 } 122 123// public void initializeFromImageType(ImageTypeSpecifier imageType) { 124// SampleModel sampleModel = imageType.getSampleModel(); 125// ColorModel colorModel = imageType.getColorModel(); 126 127// int numBands = sampleModel.getNumBands(); 128// char[] bitsPerSample = new char[numBands]; 129// for (int i = 0; i < numBands; i++) { 130// bitsPerSample[i] = (char)(sampleModel.getSampleSize(i)); 131// } 132// TIFFField bitsPerSampleField = 133// new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE), 134// TIFFTag.TIFF_SHORT, 135// numBands, 136// bitsPerSample); 137// rootIFD.addTIFFField(bitsPerSampleField); 138// } 139 140 public boolean isReadOnly() { 141 return false; 142 } 143 144 private Node getIFDAsTree(TIFFIFD ifd, 145 String parentTagName, int parentTagNumber) { 146 IIOMetadataNode IFDRoot = new IIOMetadataNode("TIFFIFD"); 147 if (parentTagNumber != 0) { 148 IFDRoot.setAttribute("parentTagNumber", 149 Integer.toString(parentTagNumber)); 150 } 151 if (parentTagName != null) { 152 IFDRoot.setAttribute("parentTagName", parentTagName); 153 } 154 155 List tagSets = ifd.getTagSetList(); 156 if (tagSets.size() > 0) { 157 Iterator iter = tagSets.iterator(); 158 String tagSetNames = ""; 159 while (iter.hasNext()) { 160 TIFFTagSet tagSet = (TIFFTagSet)iter.next(); 161 tagSetNames += tagSet.getClass().getName(); 162 if (iter.hasNext()) { 163 tagSetNames += ","; 164 } 165 } 166 167 IFDRoot.setAttribute("tagSets", tagSetNames); 168 } 169 170 Iterator iter = ifd.iterator(); 171 while (iter.hasNext()) { 172 TIFFField f = (TIFFField)iter.next(); 173 int tagNumber = f.getTagNumber(); 174 TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSets); 175 176 Node node = null; 177 if (tag == null) { 178 node = f.getAsNativeNode(); 179 } else if (tag.isIFDPointer()) { 180 Object data = f.getData(); 181 if (data instanceof TIFFIFD) { 182 TIFFIFD subIFD = (TIFFIFD) f.getData(); 183 184 // Recurse 185 node = getIFDAsTree(subIFD, tag.getName(), tag.getNumber()); 186 } 187 } else { 188 node = f.getAsNativeNode(); 189 } 190 191 if (node != null) { 192 IFDRoot.appendChild(node); 193 } 194 } 195 196 return IFDRoot; 197 } 198 199 public Node getAsTree(String formatName) { 200 if (formatName.equals(nativeMetadataFormatName)) { 201 return getNativeTree(); 202 } else if (formatName.equals 203 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 204 return getStandardTree(); 205 } else { 206 throw new IllegalArgumentException("Not a recognized format!"); 207 } 208 } 209 210 private Node getNativeTree() { 211 IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName); 212 213 Node IFDNode = getIFDAsTree(rootIFD, null, 0); 214 root.appendChild(IFDNode); 215 216 return root; 217 } 218 219 private static final String[] colorSpaceNames = { 220 "GRAY", // WhiteIsZero 221 "GRAY", // BlackIsZero 222 "RGB", // RGB 223 "RGB", // PaletteColor 224 "GRAY", // TransparencyMask 225 "CMYK", // CMYK 226 "YCbCr", // YCbCr 227 "Lab", // CIELab 228 "Lab", // ICCLab 229 }; 230 231 public IIOMetadataNode getStandardChromaNode() { 232 IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); 233 IIOMetadataNode node = null; // scratch node 234 235 TIFFField f; 236 237 // Set the PhotometricInterpretation and the palette color flag. 238 int photometricInterpretation = -1; 239 boolean isPaletteColor = false; 240 f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); 241 if (f != null) { 242 photometricInterpretation = f.getAsInt(0); 243 244 isPaletteColor = 245 photometricInterpretation == 246 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR; 247 } 248 249 // Determine the number of channels. 250 int numChannels = -1; 251 if(isPaletteColor) { 252 numChannels = 3; 253 } else { 254 f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); 255 if (f != null) { 256 numChannels = f.getAsInt(0); 257 } else { // f == null 258 f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); 259 if(f != null) { 260 numChannels = f.getCount(); 261 } 262 } 263 } 264 265 if(photometricInterpretation != -1) { 266 if (photometricInterpretation >= 0 && 267 photometricInterpretation < colorSpaceNames.length) { 268 node = new IIOMetadataNode("ColorSpaceType"); 269 String csName; 270 if(photometricInterpretation == 271 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK && 272 numChannels == 3) { 273 csName = "CMY"; 274 } else { 275 csName = colorSpaceNames[photometricInterpretation]; 276 } 277 node.setAttribute("name", csName); 278 chroma_node.appendChild(node); 279 } 280 281 node = new IIOMetadataNode("BlackIsZero"); 282 node.setAttribute("value", 283 (photometricInterpretation == 284 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) 285 ? "FALSE" : "TRUE"); 286 chroma_node.appendChild(node); 287 } 288 289 if(numChannels != -1) { 290 node = new IIOMetadataNode("NumChannels"); 291 node.setAttribute("value", Integer.toString(numChannels)); 292 chroma_node.appendChild(node); 293 } 294 295 f = getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP); 296 if (f != null) { 297 // NOTE: The presence of hasAlpha is vestigial: there is 298 // no way in TIFF to represent an alpha component in a palette 299 // color image. See bug 5086341. 300 boolean hasAlpha = false; 301 302 node = new IIOMetadataNode("Palette"); 303 int len = f.getCount()/(hasAlpha ? 4 : 3); 304 for (int i = 0; i < len; i++) { 305 IIOMetadataNode entry = 306 new IIOMetadataNode("PaletteEntry"); 307 entry.setAttribute("index", Integer.toString(i)); 308 309 int r = (f.getAsInt(i)*255)/65535; 310 int g = (f.getAsInt(len + i)*255)/65535; 311 int b = (f.getAsInt(2*len + i)*255)/65535; 312 313 entry.setAttribute("red", Integer.toString(r)); 314 entry.setAttribute("green", Integer.toString(g)); 315 entry.setAttribute("blue", Integer.toString(b)); 316 if (hasAlpha) { 317 int alpha = 0; 318 entry.setAttribute("alpha", Integer.toString(alpha)); 319 } 320 node.appendChild(entry); 321 } 322 chroma_node.appendChild(node); 323 } 324 325 return chroma_node; 326 } 327 328 public IIOMetadataNode getStandardCompressionNode() { 329 IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); 330 IIOMetadataNode node = null; // scratch node 331 332 TIFFField f; 333 334 f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION); 335 if (f != null) { 336 String compressionTypeName = null; 337 int compression = f.getAsInt(0); 338 boolean isLossless = true; // obligate initialization. 339 if(compression == BaselineTIFFTagSet.COMPRESSION_NONE) { 340 compressionTypeName = "None"; 341 isLossless = true; 342 } else { 343 int[] compressionNumbers = TIFFImageWriter.compressionNumbers; 344 for(int i = 0; i < compressionNumbers.length; i++) { 345 if(compression == compressionNumbers[i]) { 346 compressionTypeName = 347 TIFFImageWriter.compressionTypes[i]; 348 isLossless = 349 TIFFImageWriter.isCompressionLossless[i]; 350 break; 351 } 352 } 353 } 354 355 if (compressionTypeName != null) { 356 node = new IIOMetadataNode("CompressionTypeName"); 357 node.setAttribute("value", compressionTypeName); 358 compression_node.appendChild(node); 359 360 node = new IIOMetadataNode("Lossless"); 361 node.setAttribute("value", isLossless ? "TRUE" : "FALSE"); 362 compression_node.appendChild(node); 363 } 364 } 365 366 node = new IIOMetadataNode("NumProgressiveScans"); 367 node.setAttribute("value", "1"); 368 compression_node.appendChild(node); 369 370 return compression_node; 371 } 372 373 private String repeat(String s, int times) { 374 if (times == 1) { 375 return s; 376 } 377 StringBuffer sb = new StringBuffer((s.length() + 1)*times - 1); 378 sb.append(s); 379 for (int i = 1; i < times; i++) { 380 sb.append(" "); 381 sb.append(s); 382 } 383 return sb.toString(); 384 } 385 386 public IIOMetadataNode getStandardDataNode() { 387 IIOMetadataNode data_node = new IIOMetadataNode("Data"); 388 IIOMetadataNode node = null; // scratch node 389 390 TIFFField f; 391 392 boolean isPaletteColor = false; 393 f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); 394 if (f != null) { 395 isPaletteColor = 396 f.getAsInt(0) == 397 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR; 398 } 399 400 f = getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION); 401 String planarConfiguration = "PixelInterleaved"; 402 if (f != null && 403 f.getAsInt(0) == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) { 404 planarConfiguration = "PlaneInterleaved"; 405 } 406 407 node = new IIOMetadataNode("PlanarConfiguration"); 408 node.setAttribute("value", planarConfiguration); 409 data_node.appendChild(node); 410 411 f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); 412 if (f != null) { 413 int photometricInterpretation = f.getAsInt(0); 414 String sampleFormat = "UnsignedIntegral"; 415 416 if (photometricInterpretation == 417 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR) { 418 sampleFormat = "Index"; 419 } else { 420 f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT); 421 if (f != null) { 422 int format = f.getAsInt(0); 423 if (format == 424 BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) { 425 sampleFormat = "SignedIntegral"; 426 } else if (format == 427 BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER) { 428 sampleFormat = "UnsignedIntegral"; 429 } else if (format == 430 BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) { 431 sampleFormat = "Real"; 432 } else { 433 sampleFormat = null; // don't know 434 } 435 } 436 } 437 if (sampleFormat != null) { 438 node = new IIOMetadataNode("SampleFormat"); 439 node.setAttribute("value", sampleFormat); 440 data_node.appendChild(node); 441 } 442 } 443 444 f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); 445 int[] bitsPerSample = null; 446 if(f != null) { 447 bitsPerSample = f.getAsInts(); 448 } else { 449 f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION); 450 int compression = f != null ? 451 f.getAsInt(0) : BaselineTIFFTagSet.COMPRESSION_NONE; 452 if(getTIFFField(EXIFParentTIFFTagSet.TAG_EXIF_IFD_POINTER) != 453 null || 454 compression == BaselineTIFFTagSet.COMPRESSION_JPEG || 455 compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG || 456 getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) != 457 null) { 458 f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); 459 if(f != null && 460 (f.getAsInt(0) == 461 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO || 462 f.getAsInt(0) == 463 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO)) { 464 bitsPerSample = new int[] {8}; 465 } else { 466 bitsPerSample = new int[] {8, 8, 8}; 467 } 468 } else { 469 bitsPerSample = new int[] {1}; 470 } 471 } 472 StringBuffer sb = new StringBuffer(); 473 for (int i = 0; i < bitsPerSample.length; i++) { 474 if (i > 0) { 475 sb.append(" "); 476 } 477 sb.append(Integer.toString(bitsPerSample[i])); 478 } 479 node = new IIOMetadataNode("BitsPerSample"); 480 if(isPaletteColor) { 481 node.setAttribute("value", repeat(sb.toString(), 3)); 482 } else { 483 node.setAttribute("value", sb.toString()); 484 } 485 data_node.appendChild(node); 486 487 // SampleMSB 488 f = getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); 489 int fillOrder = f != null ? 490 f.getAsInt(0) : BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT; 491 sb = new StringBuffer(); 492 for (int i = 0; i < bitsPerSample.length; i++) { 493 if (i > 0) { 494 sb.append(" "); 495 } 496 int maxBitIndex = bitsPerSample[i] == 1 ? 497 7 : bitsPerSample[i] - 1; 498 int msb = 499 fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT ? 500 maxBitIndex : 0; 501 sb.append(Integer.toString(msb)); 502 } 503 node = new IIOMetadataNode("SampleMSB"); 504 if(isPaletteColor) { 505 node.setAttribute("value", repeat(sb.toString(), 3)); 506 } else { 507 node.setAttribute("value", sb.toString()); 508 } 509 data_node.appendChild(node); 510 511 return data_node; 512 } 513 514 private static final String[] orientationNames = { 515 null, 516 "Normal", 517 "FlipH", 518 "Rotate180", 519 "FlipV", 520 "FlipHRotate90", 521 "Rotate270", 522 "FlipVRotate90", 523 "Rotate90", 524 }; 525 526 public IIOMetadataNode getStandardDimensionNode() { 527 IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); 528 IIOMetadataNode node = null; // scratch node 529 530 TIFFField f; 531 532 long[] xres = null; 533 long[] yres = null; 534 535 f = getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION); 536 if (f != null) { 537 xres = (long[])f.getAsRational(0).clone(); 538 } 539 540 f = getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION); 541 if (f != null) { 542 yres = (long[])f.getAsRational(0).clone(); 543 } 544 545 if (xres != null && yres != null) { 546 node = new IIOMetadataNode("PixelAspectRatio"); 547 548 // Compute (1/xres)/(1/yres) 549 // (xres_denom/xres_num)/(yres_denom/yres_num) = 550 // (xres_denom/xres_num)*(yres_num/yres_denom) = 551 // (xres_denom*yres_num)/(xres_num*yres_denom) 552 float ratio = (float)((double)xres[1]*yres[0])/(xres[0]*yres[1]); 553 node.setAttribute("value", Float.toString(ratio)); 554 dimension_node.appendChild(node); 555 } 556 557 if (xres != null || yres != null) { 558 // Get unit field. 559 f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT); 560 561 // Set resolution unit. 562 int resolutionUnit = f != null ? 563 f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH; 564 565 // Have size if either centimeters or inches. 566 boolean gotPixelSize = 567 resolutionUnit != BaselineTIFFTagSet.RESOLUTION_UNIT_NONE; 568 569 // Convert pixels/inch to pixels/centimeter. 570 if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { 571 // Divide xres by 2.54 572 if (xres != null) { 573 xres[0] *= 100; 574 xres[1] *= 254; 575 } 576 577 // Divide yres by 2.54 578 if (yres != null) { 579 yres[0] *= 100; 580 yres[1] *= 254; 581 } 582 } 583 584 if (gotPixelSize) { 585 if (xres != null) { 586 float horizontalPixelSize = (float)(10.0*xres[1]/xres[0]); 587 node = new IIOMetadataNode("HorizontalPixelSize"); 588 node.setAttribute("value", 589 Float.toString(horizontalPixelSize)); 590 dimension_node.appendChild(node); 591 } 592 593 if (yres != null) { 594 float verticalPixelSize = (float)(10.0*yres[1]/yres[0]); 595 node = new IIOMetadataNode("VerticalPixelSize"); 596 node.setAttribute("value", 597 Float.toString(verticalPixelSize)); 598 dimension_node.appendChild(node); 599 } 600 } 601 } 602 603 f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT); 604 int resolutionUnit = f != null ? 605 f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH; 606 if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH || 607 resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER) { 608 f = getTIFFField(BaselineTIFFTagSet.TAG_X_POSITION); 609 if(f != null) { 610 long[] xpos = (long[])f.getAsRational(0); 611 float xPosition = (float)xpos[0]/(float)xpos[1]; 612 // Convert to millimeters. 613 if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { 614 xPosition *= 254F; 615 } else { 616 xPosition *= 10F; 617 } 618 node = new IIOMetadataNode("HorizontalPosition"); 619 node.setAttribute("value", 620 Float.toString(xPosition)); 621 dimension_node.appendChild(node); 622 } 623 624 f = getTIFFField(BaselineTIFFTagSet.TAG_Y_POSITION); 625 if(f != null) { 626 long[] ypos = (long[])f.getAsRational(0); 627 float yPosition = (float)ypos[0]/(float)ypos[1]; 628 // Convert to millimeters. 629 if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { 630 yPosition *= 254F; 631 } else { 632 yPosition *= 10F; 633 } 634 node = new IIOMetadataNode("VerticalPosition"); 635 node.setAttribute("value", 636 Float.toString(yPosition)); 637 dimension_node.appendChild(node); 638 } 639 } 640 641 f = getTIFFField(BaselineTIFFTagSet.TAG_ORIENTATION); 642 if (f != null) { 643 int o = f.getAsInt(0); 644 if (o >= 0 && o < orientationNames.length) { 645 node = new IIOMetadataNode("ImageOrientation"); 646 node.setAttribute("value", orientationNames[o]); 647 dimension_node.appendChild(node); 648 } 649 } 650 651 return dimension_node; 652 } 653 654 public IIOMetadataNode getStandardDocumentNode() { 655 IIOMetadataNode document_node = new IIOMetadataNode("Document"); 656 IIOMetadataNode node = null; // scratch node 657 658 TIFFField f; 659 660 node = new IIOMetadataNode("FormatVersion"); 661 node.setAttribute("value", "6.0"); 662 document_node.appendChild(node); 663 664 f = getTIFFField(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE); 665 if(f != null) { 666 int newSubFileType = f.getAsInt(0); 667 String value = null; 668 if((newSubFileType & 669 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY) != 0) { 670 value = "TransparencyMask"; 671 } else if((newSubFileType & 672 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION) != 0) { 673 value = "ReducedResolution"; 674 } else if((newSubFileType & 675 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE) != 0) { 676 value = "SinglePage"; 677 } 678 if(value != null) { 679 node = new IIOMetadataNode("SubimageInterpretation"); 680 node.setAttribute("value", value); 681 document_node.appendChild(node); 682 } 683 } 684 685 f = getTIFFField(BaselineTIFFTagSet.TAG_DATE_TIME); 686 if (f != null) { 687 String s = f.getAsString(0); 688 689 // DateTime should be formatted as "YYYY:MM:DD hh:mm:ss". 690 if(s.length() == 19) { 691 node = new IIOMetadataNode("ImageCreationTime"); 692 693 // Files with incorrect DateTime format have been 694 // observed so anticipate an exception from substring() 695 // and only add the node if the format is presumably 696 // correct. 697 boolean appendNode; 698 try { 699 node.setAttribute("year", s.substring(0, 4)); 700 node.setAttribute("month", s.substring(5, 7)); 701 node.setAttribute("day", s.substring(8, 10)); 702 node.setAttribute("hour", s.substring(11, 13)); 703 node.setAttribute("minute", s.substring(14, 16)); 704 node.setAttribute("second", s.substring(17, 19)); 705 appendNode = true; 706 } catch(IndexOutOfBoundsException e) { 707 appendNode = false; 708 } 709 710 if(appendNode) { 711 document_node.appendChild(node); 712 } 713 } 714 } 715 716 return document_node; 717 } 718 719 public IIOMetadataNode getStandardTextNode() { 720 IIOMetadataNode text_node = null; 721 IIOMetadataNode node = null; // scratch node 722 723 TIFFField f; 724 725 int[] textFieldTagNumbers = new int[] { 726 BaselineTIFFTagSet.TAG_DOCUMENT_NAME, 727 BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION, 728 BaselineTIFFTagSet.TAG_MAKE, 729 BaselineTIFFTagSet.TAG_MODEL, 730 BaselineTIFFTagSet.TAG_PAGE_NAME, 731 BaselineTIFFTagSet.TAG_SOFTWARE, 732 BaselineTIFFTagSet.TAG_ARTIST, 733 BaselineTIFFTagSet.TAG_HOST_COMPUTER, 734 BaselineTIFFTagSet.TAG_INK_NAMES, 735 BaselineTIFFTagSet.TAG_COPYRIGHT 736 }; 737 738 for(int i = 0; i < textFieldTagNumbers.length; i++) { 739 f = getTIFFField(textFieldTagNumbers[i]); 740 if(f != null) { 741 String value = f.getAsString(0); 742 if(text_node == null) { 743 text_node = new IIOMetadataNode("Text"); 744 } 745 node = new IIOMetadataNode("TextEntry"); 746 node.setAttribute("keyword", f.getTag().getName()); 747 node.setAttribute("value", value); 748 text_node.appendChild(node); 749 } 750 } 751 752 return text_node; 753 } 754 755 public IIOMetadataNode getStandardTransparencyNode() { 756 IIOMetadataNode transparency_node = 757 new IIOMetadataNode("Transparency"); 758 IIOMetadataNode node = null; // scratch node 759 760 TIFFField f; 761 762 node = new IIOMetadataNode("Alpha"); 763 String value = "none"; 764 765 f = getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES); 766 if(f != null) { 767 int[] extraSamples = f.getAsInts(); 768 for(int i = 0; i < extraSamples.length; i++) { 769 if(extraSamples[i] == 770 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) { 771 value = "premultiplied"; 772 break; 773 } else if(extraSamples[i] == 774 BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA) { 775 value = "nonpremultiplied"; 776 break; 777 } 778 } 779 } 780 781 node.setAttribute("value", value); 782 transparency_node.appendChild(node); 783 784 return transparency_node; 785 } 786 787 // Shorthand for throwing an IIOInvalidTreeException 788 private static void fatal(Node node, String reason) 789 throws IIOInvalidTreeException { 790 throw new IIOInvalidTreeException(reason, node); 791 } 792 793 private int[] listToIntArray(String list) { 794 StringTokenizer st = new StringTokenizer(list, " "); 795 ArrayList intList = new ArrayList(); 796 while (st.hasMoreTokens()) { 797 String nextInteger = st.nextToken(); 798 Integer nextInt = new Integer(nextInteger); 799 intList.add(nextInt); 800 } 801 802 int[] intArray = new int[intList.size()]; 803 for(int i = 0; i < intArray.length; i++) { 804 intArray[i] = ((Integer)intList.get(i)).intValue(); 805 } 806 807 return intArray; 808 } 809 810 private char[] listToCharArray(String list) { 811 StringTokenizer st = new StringTokenizer(list, " "); 812 ArrayList intList = new ArrayList(); 813 while (st.hasMoreTokens()) { 814 String nextInteger = st.nextToken(); 815 Integer nextInt = new Integer(nextInteger); 816 intList.add(nextInt); 817 } 818 819 char[] charArray = new char[intList.size()]; 820 for(int i = 0; i < charArray.length; i++) { 821 charArray[i] = (char)((Integer)intList.get(i)).intValue(); 822 } 823 824 return charArray; 825 } 826 827 private void mergeStandardTree(Node root) 828 throws IIOInvalidTreeException { 829 TIFFField f; 830 TIFFTag tag; 831 832 Node node = root; 833 if (!node.getNodeName() 834 .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) { 835 fatal(node, "Root must be " + 836 IIOMetadataFormatImpl.standardMetadataFormatName); 837 } 838 839 // Obtain the sample format and set the palette flag if appropriate. 840 String sampleFormat = null; 841 Node dataNode = getChildNode(root, "Data"); 842 boolean isPaletteColor = false; 843 if(dataNode != null) { 844 Node sampleFormatNode = getChildNode(dataNode, "SampleFormat"); 845 if(sampleFormatNode != null) { 846 sampleFormat = getAttribute(sampleFormatNode, "value"); 847 isPaletteColor = sampleFormat.equals("Index"); 848 } 849 } 850 851 // If palette flag not set check for palette. 852 if(!isPaletteColor) { 853 Node chromaNode = getChildNode(root, "Chroma"); 854 if(chromaNode != null && 855 getChildNode(chromaNode, "Palette") != null) { 856 isPaletteColor = true; 857 } 858 } 859 860 node = node.getFirstChild(); 861 while (node != null) { 862 String name = node.getNodeName(); 863 864 if (name.equals("Chroma")) { 865 String colorSpaceType = null; 866 String blackIsZero = null; 867 boolean gotPalette = false; 868 Node child = node.getFirstChild(); 869 while (child != null) { 870 String childName = child.getNodeName(); 871 if (childName.equals("ColorSpaceType")) { 872 colorSpaceType = getAttribute(child, "name"); 873 } else if (childName.equals("NumChannels")) { 874 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); 875 int samplesPerPixel = isPaletteColor ? 876 1 : Integer.parseInt(getAttribute(child, "value")); 877 f = new TIFFField(tag, samplesPerPixel); 878 rootIFD.addTIFFField(f); 879 } else if (childName.equals("BlackIsZero")) { 880 blackIsZero = getAttribute(child, "value"); 881 } else if (childName.equals("Palette")) { 882 Node entry = child.getFirstChild(); 883 HashMap palette = new HashMap(); 884 int maxIndex = -1; 885 while(entry != null) { 886 String entryName = entry.getNodeName(); 887 if(entryName.equals("PaletteEntry")) { 888 String idx = getAttribute(entry, "index"); 889 int id = Integer.parseInt(idx); 890 if(id > maxIndex) { 891 maxIndex = id; 892 } 893 char red = 894 (char)Integer.parseInt(getAttribute(entry, 895 "red")); 896 char green = 897 (char)Integer.parseInt(getAttribute(entry, 898 "green")); 899 char blue = 900 (char)Integer.parseInt(getAttribute(entry, 901 "blue")); 902 palette.put(new Integer(id), 903 new char[] {red, green, blue}); 904 905 gotPalette = true; 906 } 907 entry = entry.getNextSibling(); 908 } 909 910 if(gotPalette) { 911 int mapSize = maxIndex + 1; 912 int paletteLength = 3*mapSize; 913 char[] paletteEntries = new char[paletteLength]; 914 Iterator paletteIter = palette.keySet().iterator(); 915 while(paletteIter.hasNext()) { 916 Integer index = (Integer)paletteIter.next(); 917 char[] rgb = (char[])palette.get(index); 918 int idx = index.intValue(); 919 paletteEntries[idx] = 920 (char)((rgb[0]*65535)/255); 921 paletteEntries[mapSize + idx] = 922 (char)((rgb[1]*65535)/255); 923 paletteEntries[2*mapSize + idx] = 924 (char)((rgb[2]*65535)/255); 925 } 926 927 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COLOR_MAP); 928 f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 929 paletteLength, paletteEntries); 930 rootIFD.addTIFFField(f); 931 } 932 } 933 934 child = child.getNextSibling(); 935 } 936 937 int photometricInterpretation = -1; 938 if((colorSpaceType == null || colorSpaceType.equals("GRAY")) && 939 blackIsZero != null && 940 blackIsZero.equalsIgnoreCase("FALSE")) { 941 photometricInterpretation = 942 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO; 943 } else if(colorSpaceType != null) { 944 if(colorSpaceType.equals("GRAY")) { 945 boolean isTransparency = false; 946 if(root instanceof IIOMetadataNode) { 947 IIOMetadataNode iioRoot = (IIOMetadataNode)root; 948 NodeList siNodeList = 949 iioRoot.getElementsByTagName("SubimageInterpretation"); 950 if(siNodeList.getLength() == 1) { 951 Node siNode = siNodeList.item(0); 952 String value = getAttribute(siNode, "value"); 953 if(value.equals("TransparencyMask")) { 954 isTransparency = true; 955 } 956 } 957 } 958 if(isTransparency) { 959 photometricInterpretation = 960 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_TRANSPARENCY_MASK; 961 } else { 962 photometricInterpretation = 963 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO; 964 } 965 } else if(colorSpaceType.equals("RGB")) { 966 photometricInterpretation = 967 gotPalette ? 968 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR : 969 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB; 970 } else if(colorSpaceType.equals("YCbCr")) { 971 photometricInterpretation = 972 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR; 973 } else if(colorSpaceType.equals("CMYK")) { 974 photometricInterpretation = 975 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK; 976 } else if(colorSpaceType.equals("Lab")) { 977 photometricInterpretation = 978 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB; 979 } 980 } 981 982 if(photometricInterpretation != -1) { 983 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); 984 f = new TIFFField(tag, photometricInterpretation); 985 rootIFD.addTIFFField(f); 986 } 987 } else if (name.equals("Compression")) { 988 Node child = node.getFirstChild(); 989 while (child != null) { 990 String childName = child.getNodeName(); 991 if (childName.equals("CompressionTypeName")) { 992 int compression = -1; 993 String compressionTypeName = 994 getAttribute(child, "value"); 995 if(compressionTypeName.equalsIgnoreCase("None")) { 996 compression = 997 BaselineTIFFTagSet.COMPRESSION_NONE; 998 } else { 999 String[] compressionNames = 1000 TIFFImageWriter.compressionTypes; 1001 for(int i = 0; i < compressionNames.length; i++) { 1002 if(compressionNames[i].equalsIgnoreCase(compressionTypeName)) { 1003 compression = 1004 TIFFImageWriter.compressionNumbers[i]; 1005 break; 1006 } 1007 } 1008 } 1009 1010 if(compression != -1) { 1011 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COMPRESSION); 1012 f = new TIFFField(tag, compression); 1013 rootIFD.addTIFFField(f); 1014 1015 // Lossless is irrelevant. 1016 } 1017 } 1018 1019 child = child.getNextSibling(); 1020 } 1021 } else if (name.equals("Data")) { 1022 Node child = node.getFirstChild(); 1023 while (child != null) { 1024 String childName = child.getNodeName(); 1025 1026 if (childName.equals("PlanarConfiguration")) { 1027 String pc = getAttribute(child, "value"); 1028 int planarConfiguration = -1; 1029 if(pc.equals("PixelInterleaved")) { 1030 planarConfiguration = 1031 BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY; 1032 } else if(pc.equals("PlaneInterleaved")) { 1033 planarConfiguration = 1034 BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR; 1035 } 1036 if(planarConfiguration != -1) { 1037 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION); 1038 f = new TIFFField(tag, planarConfiguration); 1039 rootIFD.addTIFFField(f); 1040 } 1041 } else if (childName.equals("BitsPerSample")) { 1042 String bps = getAttribute(child, "value"); 1043 char[] bitsPerSample = listToCharArray(bps); 1044 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); 1045 if(isPaletteColor) { 1046 f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 1, 1047 new char[] {bitsPerSample[0]}); 1048 } else { 1049 f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 1050 bitsPerSample.length, 1051 bitsPerSample); 1052 } 1053 rootIFD.addTIFFField(f); 1054 } else if (childName.equals("SampleMSB")) { 1055 // Add FillOrder only if lsb-to-msb (right to left) 1056 // for all bands, i.e., SampleMSB is zero for all 1057 // channels. 1058 String sMSB = getAttribute(child, "value"); 1059 int[] sampleMSB = listToIntArray(sMSB); 1060 boolean isRightToLeft = true; 1061 for(int i = 0; i < sampleMSB.length; i++) { 1062 if(sampleMSB[i] != 0) { 1063 isRightToLeft = false; 1064 break; 1065 } 1066 } 1067 int fillOrder = isRightToLeft ? 1068 BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT : 1069 BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT; 1070 tag = 1071 rootIFD.getTag(BaselineTIFFTagSet.TAG_FILL_ORDER); 1072 f = new TIFFField(tag, fillOrder); 1073 rootIFD.addTIFFField(f); 1074 } 1075 1076 child = child.getNextSibling(); 1077 } 1078 } else if (name.equals("Dimension")) { 1079 float pixelAspectRatio = -1.0f; 1080 boolean gotPixelAspectRatio = false; 1081 1082 float horizontalPixelSize = -1.0f; 1083 boolean gotHorizontalPixelSize = false; 1084 1085 float verticalPixelSize = -1.0f; 1086 boolean gotVerticalPixelSize = false; 1087 1088 boolean sizeIsAbsolute = false; 1089 1090 float horizontalPosition = -1.0f; 1091 boolean gotHorizontalPosition = false; 1092 1093 float verticalPosition = -1.0f; 1094 boolean gotVerticalPosition = false; 1095 1096 Node child = node.getFirstChild(); 1097 while (child != null) { 1098 String childName = child.getNodeName(); 1099 if (childName.equals("PixelAspectRatio")) { 1100 String par = getAttribute(child, "value"); 1101 pixelAspectRatio = Float.parseFloat(par); 1102 gotPixelAspectRatio = true; 1103 } else if (childName.equals("ImageOrientation")) { 1104 String orientation = getAttribute(child, "value"); 1105 for (int i = 0; i < orientationNames.length; i++) { 1106 if (orientation.equals(orientationNames[i])) { 1107 char[] oData = new char[1]; 1108 oData[0] = (char)i; 1109 1110 f = new TIFFField( 1111 rootIFD.getTag(BaselineTIFFTagSet.TAG_ORIENTATION), 1112 TIFFTag.TIFF_SHORT, 1113 1, 1114 oData); 1115 1116 rootIFD.addTIFFField(f); 1117 break; 1118 } 1119 } 1120 1121 } else if (childName.equals("HorizontalPixelSize")) { 1122 String hps = getAttribute(child, "value"); 1123 horizontalPixelSize = Float.parseFloat(hps); 1124 gotHorizontalPixelSize = true; 1125 } else if (childName.equals("VerticalPixelSize")) { 1126 String vps = getAttribute(child, "value"); 1127 verticalPixelSize = Float.parseFloat(vps); 1128 gotVerticalPixelSize = true; 1129 } else if (childName.equals("HorizontalPosition")) { 1130 String hp = getAttribute(child, "value"); 1131 horizontalPosition = Float.parseFloat(hp); 1132 gotHorizontalPosition = true; 1133 } else if (childName.equals("VerticalPosition")) { 1134 String vp = getAttribute(child, "value"); 1135 verticalPosition = Float.parseFloat(vp); 1136 gotVerticalPosition = true; 1137 } 1138 1139 child = child.getNextSibling(); 1140 } 1141 1142 sizeIsAbsolute = gotHorizontalPixelSize || 1143 gotVerticalPixelSize; 1144 1145 // Fill in pixel size data from aspect ratio 1146 if (gotPixelAspectRatio) { 1147 if (gotHorizontalPixelSize && !gotVerticalPixelSize) { 1148 verticalPixelSize = 1149 horizontalPixelSize/pixelAspectRatio; 1150 gotVerticalPixelSize = true; 1151 } else if (gotVerticalPixelSize && 1152 !gotHorizontalPixelSize) { 1153 horizontalPixelSize = 1154 verticalPixelSize*pixelAspectRatio; 1155 gotHorizontalPixelSize = true; 1156 } else if (!gotHorizontalPixelSize && 1157 !gotVerticalPixelSize) { 1158 horizontalPixelSize = pixelAspectRatio; 1159 verticalPixelSize = 1.0f; 1160 gotHorizontalPixelSize = true; 1161 gotVerticalPixelSize = true; 1162 } 1163 } 1164 1165 // Compute pixels/centimeter 1166 if (gotHorizontalPixelSize) { 1167 float xResolution = 1168 (sizeIsAbsolute ? 10.0f : 1.0f)/horizontalPixelSize; 1169 long[][] hData = new long[1][2]; 1170 hData[0] = new long[2]; 1171 hData[0][0] = (long)(xResolution*10000.0f); 1172 hData[0][1] = (long)10000; 1173 1174 f = new TIFFField( 1175 rootIFD.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), 1176 TIFFTag.TIFF_RATIONAL, 1177 1, 1178 hData); 1179 rootIFD.addTIFFField(f); 1180 } 1181 1182 if (gotVerticalPixelSize) { 1183 float yResolution = 1184 (sizeIsAbsolute ? 10.0f : 1.0f)/verticalPixelSize; 1185 long[][] vData = new long[1][2]; 1186 vData[0] = new long[2]; 1187 vData[0][0] = (long)(yResolution*10000.0f); 1188 vData[0][1] = (long)10000; 1189 1190 f = new TIFFField( 1191 rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), 1192 TIFFTag.TIFF_RATIONAL, 1193 1, 1194 vData); 1195 rootIFD.addTIFFField(f); 1196 } 1197 1198 // Emit ResolutionUnit tag 1199 char[] res = new char[1]; 1200 res[0] = (char)(sizeIsAbsolute ? 1201 BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER : 1202 BaselineTIFFTagSet.RESOLUTION_UNIT_NONE); 1203 1204 f = new TIFFField( 1205 rootIFD.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), 1206 TIFFTag.TIFF_SHORT, 1207 1, 1208 res); 1209 rootIFD.addTIFFField(f); 1210 1211 // Position 1212 if(sizeIsAbsolute) { 1213 if(gotHorizontalPosition) { 1214 // Convert from millimeters to centimeters via 1215 // numerator multiplier = denominator/10. 1216 long[][] hData = new long[1][2]; 1217 hData[0][0] = (long)(horizontalPosition*10000.0f); 1218 hData[0][1] = (long)100000; 1219 1220 f = new TIFFField( 1221 rootIFD.getTag(BaselineTIFFTagSet.TAG_X_POSITION), 1222 TIFFTag.TIFF_RATIONAL, 1223 1, 1224 hData); 1225 rootIFD.addTIFFField(f); 1226 } 1227 1228 if(gotVerticalPosition) { 1229 // Convert from millimeters to centimeters via 1230 // numerator multiplier = denominator/10. 1231 long[][] vData = new long[1][2]; 1232 vData[0][0] = (long)(verticalPosition*10000.0f); 1233 vData[0][1] = (long)100000; 1234 1235 f = new TIFFField( 1236 rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_POSITION), 1237 TIFFTag.TIFF_RATIONAL, 1238 1, 1239 vData); 1240 rootIFD.addTIFFField(f); 1241 } 1242 } 1243 } else if (name.equals("Document")) { 1244 Node child = node.getFirstChild(); 1245 while (child != null) { 1246 String childName = child.getNodeName(); 1247 1248 if (childName.equals("SubimageInterpretation")) { 1249 String si = getAttribute(child, "value"); 1250 int newSubFileType = -1; 1251 if(si.equals("TransparencyMask")) { 1252 newSubFileType = 1253 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY; 1254 } else if(si.equals("ReducedResolution")) { 1255 newSubFileType = 1256 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION; 1257 } else if(si.equals("SinglePage")) { 1258 newSubFileType = 1259 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE; 1260 } 1261 if(newSubFileType != -1) { 1262 tag = 1263 rootIFD.getTag(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE); 1264 f = new TIFFField(tag, newSubFileType); 1265 rootIFD.addTIFFField(f); 1266 } 1267 } 1268 1269 if (childName.equals("ImageCreationTime")) { 1270 String year = getAttribute(child, "year"); 1271 String month = getAttribute(child, "month"); 1272 String day = getAttribute(child, "day"); 1273 String hour = getAttribute(child, "hour"); 1274 String minute = getAttribute(child, "minute"); 1275 String second = getAttribute(child, "second"); 1276 1277 StringBuffer sb = new StringBuffer(); 1278 sb.append(year); 1279 sb.append(":"); 1280 if(month.length() == 1) { 1281 sb.append("0"); 1282 } 1283 sb.append(month); 1284 sb.append(":"); 1285 if(day.length() == 1) { 1286 sb.append("0"); 1287 } 1288 sb.append(day); 1289 sb.append(" "); 1290 if(hour.length() == 1) { 1291 sb.append("0"); 1292 } 1293 sb.append(hour); 1294 sb.append(":"); 1295 if(minute.length() == 1) { 1296 sb.append("0"); 1297 } 1298 sb.append(minute); 1299 sb.append(":"); 1300 if(second.length() == 1) { 1301 sb.append("0"); 1302 } 1303 sb.append(second); 1304 1305 String[] dt = new String[1]; 1306 dt[0] = sb.toString(); 1307 1308 f = new TIFFField( 1309 rootIFD.getTag(BaselineTIFFTagSet.TAG_DATE_TIME), 1310 TIFFTag.TIFF_ASCII, 1311 1, 1312 dt); 1313 rootIFD.addTIFFField(f); 1314 } 1315 1316 child = child.getNextSibling(); 1317 } 1318 } else if (name.equals("Text")) { 1319 Node child = node.getFirstChild(); 1320 String theAuthor = null; 1321 String theDescription = null; 1322 String theTitle = null; 1323 while (child != null) { 1324 String childName = child.getNodeName(); 1325 if(childName.equals("TextEntry")) { 1326 int tagNumber = -1; 1327 NamedNodeMap childAttrs = child.getAttributes(); 1328 Node keywordNode = childAttrs.getNamedItem("keyword"); 1329 if(keywordNode != null) { 1330 String keyword = keywordNode.getNodeValue(); 1331 String value = getAttribute(child, "value"); 1332 if(!keyword.equals("") && !value.equals("")) { 1333 if(keyword.equalsIgnoreCase("DocumentName")) { 1334 tagNumber = 1335 BaselineTIFFTagSet.TAG_DOCUMENT_NAME; 1336 } else if(keyword.equalsIgnoreCase("ImageDescription")) { 1337 tagNumber = 1338 BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION; 1339 } else if(keyword.equalsIgnoreCase("Make")) { 1340 tagNumber = 1341 BaselineTIFFTagSet.TAG_MAKE; 1342 } else if(keyword.equalsIgnoreCase("Model")) { 1343 tagNumber = 1344 BaselineTIFFTagSet.TAG_MODEL; 1345 } else if(keyword.equalsIgnoreCase("PageName")) { 1346 tagNumber = 1347 BaselineTIFFTagSet.TAG_PAGE_NAME; 1348 } else if(keyword.equalsIgnoreCase("Software")) { 1349 tagNumber = 1350 BaselineTIFFTagSet.TAG_SOFTWARE; 1351 } else if(keyword.equalsIgnoreCase("Artist")) { 1352 tagNumber = 1353 BaselineTIFFTagSet.TAG_ARTIST; 1354 } else if(keyword.equalsIgnoreCase("HostComputer")) { 1355 tagNumber = 1356 BaselineTIFFTagSet.TAG_HOST_COMPUTER; 1357 } else if(keyword.equalsIgnoreCase("InkNames")) { 1358 tagNumber = 1359 BaselineTIFFTagSet.TAG_INK_NAMES; 1360 } else if(keyword.equalsIgnoreCase("Copyright")) { 1361 tagNumber = 1362 BaselineTIFFTagSet.TAG_COPYRIGHT; 1363 } else if(keyword.equalsIgnoreCase("author")) { 1364 theAuthor = value; 1365 } else if(keyword.equalsIgnoreCase("description")) { 1366 theDescription = value; 1367 } else if(keyword.equalsIgnoreCase("title")) { 1368 theTitle = value; 1369 } 1370 if(tagNumber != -1) { 1371 f = new TIFFField(rootIFD.getTag(tagNumber), 1372 TIFFTag.TIFF_ASCII, 1373 1, 1374 new String[] {value}); 1375 rootIFD.addTIFFField(f); 1376 } 1377 } 1378 } 1379 } 1380 child = child.getNextSibling(); 1381 } // child != null 1382 if(theAuthor != null && 1383 getTIFFField(BaselineTIFFTagSet.TAG_ARTIST) == null) { 1384 f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_ARTIST), 1385 TIFFTag.TIFF_ASCII, 1386 1, 1387 new String[] {theAuthor}); 1388 rootIFD.addTIFFField(f); 1389 } 1390 if(theDescription != null && 1391 getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION) == null) { 1392 f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION), 1393 TIFFTag.TIFF_ASCII, 1394 1, 1395 new String[] {theDescription}); 1396 rootIFD.addTIFFField(f); 1397 } 1398 if(theTitle != null && 1399 getTIFFField(BaselineTIFFTagSet.TAG_DOCUMENT_NAME) == null) { 1400 f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_DOCUMENT_NAME), 1401 TIFFTag.TIFF_ASCII, 1402 1, 1403 new String[] {theTitle}); 1404 rootIFD.addTIFFField(f); 1405 } 1406 } else if (name.equals("Transparency")) { 1407 Node child = node.getFirstChild(); 1408 while (child != null) { 1409 String childName = child.getNodeName(); 1410 1411 if (childName.equals("Alpha")) { 1412 String alpha = getAttribute(child, "value"); 1413 1414 f = null; 1415 if (alpha.equals("premultiplied")) { 1416 f = new TIFFField( 1417 rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES), 1418 BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA); 1419 } else if (alpha.equals("nonpremultiplied")) { 1420 f = new TIFFField( 1421 rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES), 1422 BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA); 1423 } 1424 if (f != null) { 1425 rootIFD.addTIFFField(f); 1426 } 1427 } 1428 1429 child = child.getNextSibling(); 1430 } 1431 } 1432 1433 node = node.getNextSibling(); 1434 } 1435 1436 // Set SampleFormat. 1437 if(sampleFormat != null) { 1438 // Derive the value. 1439 int sf = -1; 1440 if(sampleFormat.equals("SignedIntegral")) { 1441 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER; 1442 } else if(sampleFormat.equals("UnsignedIntegral")) { 1443 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER; 1444 } else if(sampleFormat.equals("Real")) { 1445 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT; 1446 } else if(sampleFormat.equals("Index")) { 1447 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER; 1448 } 1449 1450 if(sf != -1) { 1451 // Derive the count. 1452 int count = 1; 1453 1454 // Try SamplesPerPixel first. 1455 f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); 1456 if(f != null) { 1457 count = f.getAsInt(0); 1458 } else { 1459 // Try BitsPerSample. 1460 f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); 1461 if(f != null) { 1462 count = f.getCount(); 1463 } 1464 } 1465 1466 char[] sampleFormatArray = new char[count]; 1467 Arrays.fill(sampleFormatArray, (char)sf); 1468 1469 // Add SampleFormat. 1470 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT); 1471 f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 1472 sampleFormatArray.length, sampleFormatArray); 1473 rootIFD.addTIFFField(f); 1474 } 1475 } 1476 } 1477 1478 private static String getAttribute(Node node, String attrName) { 1479 NamedNodeMap attrs = node.getAttributes(); 1480 Node attr = attrs.getNamedItem(attrName); 1481 return attr != null ? attr.getNodeValue() : null; 1482 } 1483 1484 private Node getChildNode(Node node, String childName) { 1485 Node childNode = null; 1486 if(node.hasChildNodes()) { 1487 NodeList childNodes = node.getChildNodes(); 1488 int length = childNodes.getLength(); 1489 for(int i = 0; i < length; i++) { 1490 Node item = childNodes.item(i); 1491 if(item.getNodeName().equals(childName)) { 1492 childNode = item; 1493 break; 1494 } 1495 } 1496 } 1497 return childNode; 1498 } 1499 1500 public static TIFFIFD parseIFD(Node node) throws IIOInvalidTreeException { 1501 if (!node.getNodeName().equals("TIFFIFD")) { 1502 fatal(node, "Expected \"TIFFIFD\" node"); 1503 } 1504 1505 String tagSetNames = getAttribute(node, "tagSets"); 1506 List tagSets = new ArrayList(5); 1507 1508 if (tagSetNames != null) { 1509 StringTokenizer st = new StringTokenizer(tagSetNames, ","); 1510 while (st.hasMoreTokens()) { 1511 String className = st.nextToken(); 1512 1513 if(className != null) { 1514 className = className.replace(SUN_BaselineTIFFTagSetClassName, THISJAI_BaselineTIFFTagSetClassName); 1515 } 1516 1517 Object o = null; 1518 try { 1519 Class setClass = Class.forName(className); 1520 Method getInstanceMethod = 1521 setClass.getMethod("getInstance", (Class[])null); 1522 o = getInstanceMethod.invoke(null, (Object[])null); 1523 } catch (NoSuchMethodException e) { 1524 throw new RuntimeException(e); 1525 } catch (IllegalAccessException e) { 1526 throw new RuntimeException(e); 1527 } catch (InvocationTargetException e) { 1528 throw new RuntimeException(e); 1529 } catch (ClassNotFoundException e) { 1530 throw new RuntimeException(e); 1531 } 1532 1533 if (!(o instanceof TIFFTagSet)) { 1534 fatal(node, "Specified tag set class \"" + 1535 className + 1536 "\" is not an instance of TIFFTagSet"); 1537 } else { 1538 tagSets.add((TIFFTagSet)o); 1539 } 1540 } 1541 } 1542 1543 TIFFIFD ifd = new TIFFIFD(tagSets); 1544 1545 node = node.getFirstChild(); 1546 while (node != null) { 1547 String name = node.getNodeName(); 1548 1549 TIFFField f = null; 1550 if (name.equals("TIFFIFD")) { 1551 TIFFIFD subIFD = parseIFD(node); 1552 String parentTagName = getAttribute(node, "parentTagName"); 1553 String parentTagNumber = getAttribute(node, "parentTagNumber"); 1554 TIFFTag tag = null; 1555 if(parentTagName != null) { 1556 tag = TIFFIFD.getTag(parentTagName, tagSets); 1557 } else if(parentTagNumber != null) { 1558 int tagNumber = 1559 Integer.valueOf(parentTagNumber).intValue(); 1560 tag = TIFFIFD.getTag(tagNumber, tagSets); 1561 } 1562 1563 if(tag == null) { 1564 tag = new TIFFTag("unknown", 0, 0, null); 1565 } 1566 1567 int type; 1568 if (tag.isDataTypeOK(TIFFTag.TIFF_IFD_POINTER)) { 1569 type = TIFFTag.TIFF_IFD_POINTER; 1570 } else { 1571 type = TIFFTag.TIFF_LONG; 1572 } 1573 1574 f = new TIFFField(tag, type, 1, subIFD); 1575 } else if (name.equals("TIFFField")) { 1576 int number = Integer.parseInt(getAttribute(node, "number")); 1577 1578 TIFFTagSet tagSet = null; 1579 Iterator iter = tagSets.iterator(); 1580 while (iter.hasNext()) { 1581 TIFFTagSet t = (TIFFTagSet)iter.next(); 1582 if (t.getTag(number) != null) { 1583 tagSet = t; 1584 break; 1585 } 1586 } 1587 1588 f = TIFFField.createFromMetadataNode(tagSet, node); 1589 } else { 1590 fatal(node, 1591 "Expected either \"TIFFIFD\" or \"TIFFField\" node, got " 1592 + name); 1593 } 1594 1595 ifd.addTIFFField(f); 1596 node = node.getNextSibling(); 1597 } 1598 1599 return ifd; 1600 } 1601 1602 private void mergeNativeTree(Node root) throws IIOInvalidTreeException { 1603 Node node = root; 1604 if (!node.getNodeName().equals(nativeMetadataFormatName)) { 1605 fatal(node, "Root must be " + nativeMetadataFormatName); 1606 } 1607 1608 node = node.getFirstChild(); 1609 if (node == null || !node.getNodeName().equals("TIFFIFD")) { 1610 fatal(root, "Root must have \"TIFFIFD\" child"); 1611 } 1612 TIFFIFD ifd = parseIFD(node); 1613 1614 List rootIFDTagSets = rootIFD.getTagSetList(); 1615 Iterator tagSetIter = ifd.getTagSetList().iterator(); 1616 while(tagSetIter.hasNext()) { 1617 Object o = tagSetIter.next(); 1618 if(o instanceof TIFFTagSet && !rootIFDTagSets.contains(o)) { 1619 rootIFD.addTagSet((TIFFTagSet)o); 1620 } 1621 } 1622 1623 Iterator ifdIter = ifd.iterator(); 1624 while(ifdIter.hasNext()) { 1625 TIFFField field = (TIFFField)ifdIter.next(); 1626 rootIFD.addTIFFField(field); 1627 } 1628 } 1629 1630 public void mergeTree(String formatName, Node root) 1631 throws IIOInvalidTreeException{ 1632 if (formatName.equals(nativeMetadataFormatName)) { 1633 if (root == null) { 1634 throw new IllegalArgumentException("root == null!"); 1635 } 1636 mergeNativeTree(root); 1637 } else if (formatName.equals 1638 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 1639 if (root == null) { 1640 throw new IllegalArgumentException("root == null!"); 1641 } 1642 mergeStandardTree(root); 1643 } else { 1644 throw new IllegalArgumentException("Not a recognized format!"); 1645 } 1646 } 1647 1648 public void reset() { 1649 rootIFD = new TIFFIFD(tagSets); 1650 } 1651 1652 public TIFFIFD getRootIFD() { 1653 return rootIFD; 1654 } 1655 1656 public TIFFField getTIFFField(int tagNumber) { 1657 return rootIFD.getTIFFField(tagNumber); 1658 } 1659 1660 public void removeTIFFField(int tagNumber) { 1661 rootIFD.removeTIFFField(tagNumber); 1662 } 1663 1664 /** 1665 * Returns a <code>TIFFImageMetadata</code> wherein all fields in the 1666 * root IFD from the <code>BaselineTIFFTagSet</code> are copied by value 1667 * and all other fields copied by reference. 1668 */ 1669 public TIFFImageMetadata getShallowClone() { 1670 return new TIFFImageMetadata(rootIFD.getShallowClone()); 1671 } 1672}