1 7 8 package com.sun.imageio.plugins.png; 9 10 import java.awt.image.ColorModel ; 11 import java.awt.image.IndexColorModel ; 12 import java.awt.image.SampleModel ; 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.StringTokenizer ; 16 import javax.imageio.ImageTypeSpecifier ; 17 import javax.imageio.metadata.IIOInvalidTreeException ; 18 import javax.imageio.metadata.IIOMetadata ; 19 import javax.imageio.metadata.IIOMetadataFormat ; 20 import javax.imageio.metadata.IIOMetadataFormatImpl ; 21 import javax.imageio.metadata.IIOMetadataNode ; 22 import org.w3c.dom.Node ; 23 24 27 public class PNGMetadata extends IIOMetadata implements Cloneable { 28 29 public static final String 31 nativeMetadataFormatName = "javax_imageio_png_1.0"; 32 33 protected static final String nativeMetadataFormatClassName 34 = "com.sun.imageio.plugins.png.PNGMetadataFormat"; 35 36 public static final String [] IHDR_colorTypeNames = { 38 "Grayscale", null, "RGB", "Palette", 39 "GrayAlpha", null, "RGBAlpha" 40 }; 41 42 public static final int[] IHDR_numChannels = { 43 1, 0, 3, 3, 2, 0, 4 44 }; 45 46 public static final String [] IHDR_bitDepths = { 48 "1", "2", "4", "8", "16" 49 }; 50 51 public static final String [] IHDR_compressionMethodNames = { 53 "deflate" 54 }; 55 56 public static final String [] IHDR_filterMethodNames = { 58 "adaptive" 59 }; 60 61 public static final String [] IHDR_interlaceMethodNames = { 63 "none", "adam7" 64 }; 65 66 public static final String [] iCCP_compressionMethodNames = { 68 "deflate" 69 }; 70 71 public static final String [] zTXt_compressionMethodNames = { 73 "deflate" 74 }; 75 76 public static final int PHYS_UNIT_UNKNOWN = 0; 78 79 public static final int PHYS_UNIT_METER = 1; 81 82 public static final String [] unitSpecifierNames = { 84 "unknown", "meter" 85 }; 86 87 public static final String [] renderingIntentNames = { 89 "Perceptual", "Relative colorimetric", "Saturation", "Absolute colorimetric" 94 }; 95 96 public static final String [] colorSpaceTypeNames = { 98 "GRAY", null, "RGB", "RGB", 99 "GRAY", null, "RGB" 100 }; 101 102 public boolean IHDR_present; 104 public int IHDR_width; 105 public int IHDR_height; 106 public int IHDR_bitDepth; 107 public int IHDR_colorType; 108 public int IHDR_compressionMethod; 109 public int IHDR_filterMethod; 110 public int IHDR_interlaceMethod; 112 public boolean PLTE_present; 114 public byte[] PLTE_red; 115 public byte[] PLTE_green; 116 public byte[] PLTE_blue; 117 118 public int[] PLTE_order = null; 124 125 public boolean bKGD_present; 129 public int bKGD_colorType; public int bKGD_index; 131 public int bKGD_gray; 132 public int bKGD_red; 133 public int bKGD_green; 134 public int bKGD_blue; 135 136 public boolean cHRM_present; 138 public int cHRM_whitePointX; 139 public int cHRM_whitePointY; 140 public int cHRM_redX; 141 public int cHRM_redY; 142 public int cHRM_greenX; 143 public int cHRM_greenY; 144 public int cHRM_blueX; 145 public int cHRM_blueY; 146 147 public boolean gAMA_present; 149 public int gAMA_gamma; 150 151 public boolean hIST_present; 153 public char[] hIST_histogram; 154 155 public boolean iCCP_present; 157 public String iCCP_profileName; 158 public int iCCP_compressionMethod; 159 public byte[] iCCP_compressedProfile; 160 161 public ArrayList iTXt_keyword = new ArrayList (); public ArrayList iTXt_compressionFlag = new ArrayList (); public ArrayList iTXt_compressionMethod = new ArrayList (); public ArrayList iTXt_languageTag = new ArrayList (); public ArrayList iTXt_translatedKeyword = new ArrayList (); public ArrayList iTXt_text = new ArrayList (); 169 public boolean pHYs_present; 171 public int pHYs_pixelsPerUnitXAxis; 172 public int pHYs_pixelsPerUnitYAxis; 173 public int pHYs_unitSpecifier; 175 public boolean sBIT_present; 177 public int sBIT_colorType; public int sBIT_grayBits; 179 public int sBIT_redBits; 180 public int sBIT_greenBits; 181 public int sBIT_blueBits; 182 public int sBIT_alphaBits; 183 184 public boolean sPLT_present; 186 public String sPLT_paletteName; public int sPLT_sampleDepth; public int[] sPLT_red; 189 public int[] sPLT_green; 190 public int[] sPLT_blue; 191 public int[] sPLT_alpha; 192 public int[] sPLT_frequency; 193 194 public boolean sRGB_present; 196 public int sRGB_renderingIntent; 197 198 public ArrayList tEXt_keyword = new ArrayList (); public ArrayList tEXt_text = new ArrayList (); 202 public boolean tIME_present; 204 public int tIME_year; 205 public int tIME_month; 206 public int tIME_day; 207 public int tIME_hour; 208 public int tIME_minute; 209 public int tIME_second; 210 211 public boolean tRNS_present; 215 public int tRNS_colorType; public byte[] tRNS_alpha; public int tRNS_gray; 218 public int tRNS_red; 219 public int tRNS_green; 220 public int tRNS_blue; 221 222 public ArrayList zTXt_keyword = new ArrayList (); public ArrayList zTXt_compressionMethod = new ArrayList (); public ArrayList zTXt_text = new ArrayList (); 227 public ArrayList unknownChunkType = new ArrayList (); public ArrayList unknownChunkData = new ArrayList (); 231 public PNGMetadata() { 232 super(true, 233 nativeMetadataFormatName, 234 nativeMetadataFormatClassName, 235 null, null); 236 } 237 238 public PNGMetadata(IIOMetadata metadata) { 239 } 241 242 247 public void initialize(ImageTypeSpecifier imageType, int numBands) { 248 ColorModel colorModel = imageType.getColorModel(); 249 SampleModel sampleModel = imageType.getSampleModel(); 250 251 int[] sampleSize = sampleModel.getSampleSize(); 253 int bitDepth = sampleSize[0]; 254 for (int i = 1; i < sampleSize.length; i++) { 257 if (sampleSize[i] > bitDepth) { 258 bitDepth = sampleSize[i]; 259 } 260 } 261 if (sampleSize.length > 1 && bitDepth < 8) { 263 bitDepth = 8; 264 } 265 266 if (bitDepth > 2 && bitDepth < 4) { 268 bitDepth = 4; 269 } else if (bitDepth > 4 && bitDepth < 8) { 270 bitDepth = 8; 271 } else if (bitDepth > 8 && bitDepth < 16) { 272 bitDepth = 16; 273 } else if (bitDepth > 16) { 274 throw new RuntimeException ("bitDepth > 16!"); 275 } 276 IHDR_bitDepth = bitDepth; 277 278 if (colorModel instanceof IndexColorModel ) { 280 IndexColorModel icm = (IndexColorModel )colorModel; 281 int size = icm.getMapSize(); 282 283 byte[] reds = new byte[size]; 284 icm.getReds(reds); 285 byte[] greens = new byte[size]; 286 icm.getGreens(greens); 287 byte[] blues = new byte[size]; 288 icm.getBlues(blues); 289 290 boolean isGray = false; 293 if (!IHDR_present || 294 (IHDR_colorType != PNGImageReader.PNG_COLOR_PALETTE)) { 295 isGray = true; 296 int scale = 255/((1 << IHDR_bitDepth) - 1); 297 for (int i = 0; i < size; i++) { 298 byte red = reds[i]; 299 if ((red != (byte)(i*scale)) || 300 (red != greens[i]) || 301 (red != blues[i])) { 302 isGray = false; 303 break; 304 } 305 } 306 } 307 308 boolean hasAlpha = colorModel.hasAlpha(); 310 311 byte[] alpha = null; 312 if (hasAlpha) { 313 alpha = new byte[size]; 314 icm.getAlphas(alpha); 315 } 316 317 325 326 if (isGray && hasAlpha && (bitDepth == 8 || bitDepth == 16)) { 327 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA; 328 } else if (isGray && !hasAlpha) { 329 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY; 330 } else { 331 IHDR_colorType = PNGImageReader.PNG_COLOR_PALETTE; 332 PLTE_present = true; 333 PLTE_order = null; 334 PLTE_red = (byte[])reds.clone(); 335 PLTE_green = (byte[])greens.clone(); 336 PLTE_blue = (byte[])blues.clone(); 337 338 if (hasAlpha) { 339 tRNS_present = true; 340 tRNS_colorType = PNGImageReader.PNG_COLOR_PALETTE; 341 342 PLTE_order = new int[alpha.length]; 343 344 351 byte[] newAlpha = new byte[alpha.length]; 352 353 int newIndex = 0; 356 for (int i = 0; i < alpha.length; i++) { 357 if (alpha[i] != (byte)255) { 358 PLTE_order[i] = newIndex; 359 newAlpha[newIndex] = alpha[i]; 360 ++newIndex; 361 } 362 } 363 int numTransparent = newIndex; 364 365 for (int i = 0; i < alpha.length; i++) { 368 if (alpha[i] == (byte)255) { 369 PLTE_order[i] = newIndex++; 370 } 371 } 372 373 byte[] oldRed = PLTE_red; 375 byte[] oldGreen = PLTE_green; 376 byte[] oldBlue = PLTE_blue; 377 int len = oldRed.length; PLTE_red = new byte[len]; 379 PLTE_green = new byte[len]; 380 PLTE_blue = new byte[len]; 381 for (int i = 0; i < len; i++) { 382 PLTE_red[PLTE_order[i]] = oldRed[i]; 383 PLTE_green[PLTE_order[i]] = oldGreen[i]; 384 PLTE_blue[PLTE_order[i]] = oldBlue[i]; 385 } 386 387 tRNS_alpha = new byte[numTransparent]; 389 System.arraycopy(newAlpha, 0, 390 tRNS_alpha, 0, numTransparent); 391 } 392 } 393 } else { 394 if (numBands == 1) { 395 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY; 396 } else if (numBands == 2) { 397 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA; 398 } else if (numBands == 3) { 399 IHDR_colorType = PNGImageReader.PNG_COLOR_RGB; 400 } else if (numBands == 4) { 401 IHDR_colorType = PNGImageReader.PNG_COLOR_RGB_ALPHA; 402 } else { 403 throw new RuntimeException ("Number of bands not 1-4!"); 404 } 405 } 406 407 IHDR_present = true; 408 } 409 410 public boolean isReadOnly() { 411 return false; 412 } 413 414 private ArrayList cloneBytesArrayList(ArrayList in) { 415 if (in == null) { 416 return null; 417 } else { 418 ArrayList list = new ArrayList (in.size()); 419 Iterator iter = in.iterator(); 420 while (iter.hasNext()) { 421 Object o = iter.next(); 422 if (o == null) { 423 list.add(null); 424 } else { 425 list.add(((byte[])o).clone()); 426 } 427 } 428 429 return list; 430 } 431 } 432 433 public Object clone() { 435 PNGMetadata metadata; 436 try { 437 metadata = (PNGMetadata)super.clone(); 438 } catch (CloneNotSupportedException e) { 439 return null; 440 } 441 442 metadata.unknownChunkData = 444 cloneBytesArrayList(this.unknownChunkData); 445 446 return metadata; 447 } 448 449 public Node getAsTree(String formatName) { 450 if (formatName.equals(nativeMetadataFormatName)) { 451 return getNativeTree(); 452 } else if (formatName.equals 453 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 454 return getStandardTree(); 455 } else { 456 throw new IllegalArgumentException ("Not a recognized format!"); 457 } 458 } 459 460 private Node getNativeTree() { 461 IIOMetadataNode node = null; IIOMetadataNode root = new IIOMetadataNode (nativeMetadataFormatName); 463 464 if (IHDR_present) { 466 IIOMetadataNode IHDR_node = new IIOMetadataNode ("IHDR"); 467 IHDR_node.setAttribute("width", Integer.toString(IHDR_width)); 468 IHDR_node.setAttribute("height", Integer.toString(IHDR_height)); 469 IHDR_node.setAttribute("bitDepth", 470 Integer.toString(IHDR_bitDepth)); 471 IHDR_node.setAttribute("colorType", 472 IHDR_colorTypeNames[IHDR_colorType]); 473 IHDR_node.setAttribute("compressionMethod", 475 IHDR_compressionMethodNames[IHDR_compressionMethod]); 476 IHDR_node.setAttribute("filterMethod", 478 IHDR_filterMethodNames[IHDR_filterMethod]); 479 IHDR_node.setAttribute("interlaceMethod", 480 IHDR_interlaceMethodNames[IHDR_interlaceMethod]); 481 root.appendChild(IHDR_node); 482 } 483 484 if (PLTE_present) { 486 IIOMetadataNode PLTE_node = new IIOMetadataNode ("PLTE"); 487 int numEntries = PLTE_red.length; 488 for (int i = 0; i < numEntries; i++) { 489 IIOMetadataNode entry = new IIOMetadataNode ("PLTEEntry"); 490 entry.setAttribute("index", Integer.toString(i)); 491 entry.setAttribute("red", 492 Integer.toString(PLTE_red[i] & 0xff)); 493 entry.setAttribute("green", 494 Integer.toString(PLTE_green[i] & 0xff)); 495 entry.setAttribute("blue", 496 Integer.toString(PLTE_blue[i] & 0xff)); 497 PLTE_node.appendChild(entry); 498 } 499 500 root.appendChild(PLTE_node); 501 } 502 503 if (bKGD_present) { 505 IIOMetadataNode bKGD_node = new IIOMetadataNode ("bKGD"); 506 507 if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) { 508 node = new IIOMetadataNode ("bKGD_Palette"); 509 node.setAttribute("index", Integer.toString(bKGD_index)); 510 } else if (bKGD_colorType == PNGImageReader.PNG_COLOR_GRAY) { 511 node = new IIOMetadataNode ("bKGD_Grayscale"); 512 node.setAttribute("gray", Integer.toString(bKGD_gray)); 513 } else if (bKGD_colorType == PNGImageReader.PNG_COLOR_RGB) { 514 node = new IIOMetadataNode ("bKGD_RGB"); 515 node.setAttribute("red", Integer.toString(bKGD_red)); 516 node.setAttribute("green", Integer.toString(bKGD_green)); 517 node.setAttribute("blue", Integer.toString(bKGD_blue)); 518 } 519 bKGD_node.appendChild(node); 520 521 root.appendChild(bKGD_node); 522 } 523 524 if (cHRM_present) { 526 IIOMetadataNode cHRM_node = new IIOMetadataNode ("cHRM"); 527 cHRM_node.setAttribute("whitePointX", 528 Integer.toString(cHRM_whitePointX)); 529 cHRM_node.setAttribute("whitePointY", 530 Integer.toString(cHRM_whitePointY)); 531 cHRM_node.setAttribute("redX", Integer.toString(cHRM_redX)); 532 cHRM_node.setAttribute("redY", Integer.toString(cHRM_redY)); 533 cHRM_node.setAttribute("greenX", Integer.toString(cHRM_greenX)); 534 cHRM_node.setAttribute("greenY", Integer.toString(cHRM_greenY)); 535 cHRM_node.setAttribute("blueX", Integer.toString(cHRM_blueX)); 536 cHRM_node.setAttribute("blueY", Integer.toString(cHRM_blueY)); 537 538 root.appendChild(cHRM_node); 539 } 540 541 if (gAMA_present) { 543 IIOMetadataNode gAMA_node = new IIOMetadataNode ("gAMA"); 544 gAMA_node.setAttribute("value", Integer.toString(gAMA_gamma)); 545 546 root.appendChild(gAMA_node); 547 } 548 549 if (hIST_present) { 551 IIOMetadataNode hIST_node = new IIOMetadataNode ("hIST"); 552 553 for (int i = 0; i < hIST_histogram.length; i++) { 554 IIOMetadataNode hist = 555 new IIOMetadataNode ("hISTEntry"); 556 hist.setAttribute("index", Integer.toString(i)); 557 hist.setAttribute("value", 558 Integer.toString(hIST_histogram[i])); 559 hIST_node.appendChild(hist); 560 } 561 562 root.appendChild(hIST_node); 563 } 564 565 if (iCCP_present) { 567 IIOMetadataNode iCCP_node = new IIOMetadataNode ("iCCP"); 568 iCCP_node.setAttribute("profileName", iCCP_profileName); 569 iCCP_node.setAttribute("compressionMethod", 570 iCCP_compressionMethodNames[iCCP_compressionMethod]); 571 572 Object profile = iCCP_compressedProfile; 573 if (profile != null) { 574 profile = ((byte[])profile).clone(); 575 } 576 iCCP_node.setUserObject(profile); 577 578 root.appendChild(iCCP_node); 579 } 580 581 if (iTXt_keyword.size() > 0) { 583 IIOMetadataNode iTXt_parent = new IIOMetadataNode ("iTXt"); 584 for (int i = 0; i < iTXt_keyword.size(); i++) { 585 Integer val; 586 587 IIOMetadataNode iTXt_node = new IIOMetadataNode ("iTXtEntry"); 588 iTXt_node.setAttribute("keyword", (String )iTXt_keyword.get(i)); 589 val = (Integer )iTXt_compressionFlag.get(i); 590 iTXt_node.setAttribute("compressionFlag", val.toString()); 591 val = (Integer )iTXt_compressionMethod.get(i); 592 iTXt_node.setAttribute("compressionMethod", val.toString()); 593 iTXt_node.setAttribute("languageTag", 594 (String )iTXt_languageTag.get(i)); 595 iTXt_node.setAttribute("translatedKeyword", 596 (String )iTXt_translatedKeyword.get(i)); 597 iTXt_node.setAttribute("text", (String )iTXt_text.get(i)); 598 599 iTXt_parent.appendChild(iTXt_node); 600 } 601 602 root.appendChild(iTXt_parent); 603 } 604 605 if (pHYs_present) { 607 IIOMetadataNode pHYs_node = new IIOMetadataNode ("pHYs"); 608 pHYs_node.setAttribute("pixelsPerUnitXAxis", 609 Integer.toString(pHYs_pixelsPerUnitXAxis)); 610 pHYs_node.setAttribute("pixelsPerUnitYAxis", 611 Integer.toString(pHYs_pixelsPerUnitYAxis)); 612 pHYs_node.setAttribute("unitSpecifier", 613 unitSpecifierNames[pHYs_unitSpecifier]); 614 615 root.appendChild(pHYs_node); 616 } 617 618 if (sBIT_present) { 620 IIOMetadataNode sBIT_node = new IIOMetadataNode ("sBIT"); 621 622 if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY) { 623 node = new IIOMetadataNode ("sBIT_Grayscale"); 624 node.setAttribute("gray", 625 Integer.toString(sBIT_grayBits)); 626 } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) { 627 node = new IIOMetadataNode ("sBIT_GrayAlpha"); 628 node.setAttribute("gray", 629 Integer.toString(sBIT_grayBits)); 630 node.setAttribute("alpha", 631 Integer.toString(sBIT_alphaBits)); 632 } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_RGB) { 633 node = new IIOMetadataNode ("sBIT_RGB"); 634 node.setAttribute("red", 635 Integer.toString(sBIT_redBits)); 636 node.setAttribute("green", 637 Integer.toString(sBIT_greenBits)); 638 node.setAttribute("blue", 639 Integer.toString(sBIT_blueBits)); 640 } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) { 641 node = new IIOMetadataNode ("sBIT_RGBAlpha"); 642 node.setAttribute("red", 643 Integer.toString(sBIT_redBits)); 644 node.setAttribute("green", 645 Integer.toString(sBIT_greenBits)); 646 node.setAttribute("blue", 647 Integer.toString(sBIT_blueBits)); 648 node.setAttribute("alpha", 649 Integer.toString(sBIT_alphaBits)); 650 } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_PALETTE) { 651 node = new IIOMetadataNode ("sBIT_Palette"); 652 node.setAttribute("red", 653 Integer.toString(sBIT_redBits)); 654 node.setAttribute("green", 655 Integer.toString(sBIT_greenBits)); 656 node.setAttribute("blue", 657 Integer.toString(sBIT_blueBits)); 658 } 659 sBIT_node.appendChild(node); 660 661 root.appendChild(sBIT_node); 662 } 663 664 if (sPLT_present) { 666 IIOMetadataNode sPLT_node = new IIOMetadataNode ("sPLT"); 667 668 sPLT_node.setAttribute("name", sPLT_paletteName); 669 sPLT_node.setAttribute("sampleDepth", 670 Integer.toString(sPLT_sampleDepth)); 671 672 int numEntries = sPLT_red.length; 673 for (int i = 0; i < numEntries; i++) { 674 IIOMetadataNode entry = new IIOMetadataNode ("sPLTEntry"); 675 entry.setAttribute("index", Integer.toString(i)); 676 entry.setAttribute("red", Integer.toString(sPLT_red[i])); 677 entry.setAttribute("green", Integer.toString(sPLT_green[i])); 678 entry.setAttribute("blue", Integer.toString(sPLT_blue[i])); 679 entry.setAttribute("alpha", Integer.toString(sPLT_alpha[i])); 680 entry.setAttribute("frequency", 681 Integer.toString(sPLT_frequency[i])); 682 sPLT_node.appendChild(entry); 683 } 684 685 root.appendChild(sPLT_node); 686 } 687 688 if (sRGB_present) { 690 IIOMetadataNode sRGB_node = new IIOMetadataNode ("sRGB"); 691 sRGB_node.setAttribute("renderingIntent", 692 renderingIntentNames[sRGB_renderingIntent]); 693 694 root.appendChild(sRGB_node); 695 } 696 697 if (tEXt_keyword.size() > 0) { 699 IIOMetadataNode tEXt_parent = new IIOMetadataNode ("tEXt"); 700 for (int i = 0; i < tEXt_keyword.size(); i++) { 701 IIOMetadataNode tEXt_node = new IIOMetadataNode ("tEXtEntry"); 702 tEXt_node.setAttribute("keyword" , (String )tEXt_keyword.get(i)); 703 tEXt_node.setAttribute("value" , (String )tEXt_text.get(i)); 704 705 tEXt_parent.appendChild(tEXt_node); 706 } 707 708 root.appendChild(tEXt_parent); 709 } 710 711 if (tIME_present) { 713 IIOMetadataNode tIME_node = new IIOMetadataNode ("tIME"); 714 tIME_node.setAttribute("year", Integer.toString(tIME_year)); 715 tIME_node.setAttribute("month", Integer.toString(tIME_month)); 716 tIME_node.setAttribute("day", Integer.toString(tIME_day)); 717 tIME_node.setAttribute("hour", Integer.toString(tIME_hour)); 718 tIME_node.setAttribute("minute", Integer.toString(tIME_minute)); 719 tIME_node.setAttribute("second", Integer.toString(tIME_second)); 720 721 root.appendChild(tIME_node); 722 } 723 724 if (tRNS_present) { 726 IIOMetadataNode tRNS_node = new IIOMetadataNode ("tRNS"); 727 728 if (tRNS_colorType == PNGImageReader.PNG_COLOR_PALETTE) { 729 node = new IIOMetadataNode ("tRNS_Palette"); 730 731 for (int i = 0; i < tRNS_alpha.length; i++) { 732 IIOMetadataNode entry = 733 new IIOMetadataNode ("tRNS_PaletteEntry"); 734 entry.setAttribute("index", Integer.toString(i)); 735 entry.setAttribute("alpha", 736 Integer.toString(tRNS_alpha[i] & 0xff)); 737 node.appendChild(entry); 738 } 739 } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_GRAY) { 740 node = new IIOMetadataNode ("tRNS_Grayscale"); 741 node.setAttribute("gray", Integer.toString(tRNS_gray)); 742 } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_RGB) { 743 node = new IIOMetadataNode ("tRNS_RGB"); 744 node.setAttribute("red", Integer.toString(tRNS_red)); 745 node.setAttribute("green", Integer.toString(tRNS_green)); 746 node.setAttribute("blue", Integer.toString(tRNS_blue)); 747 } 748 tRNS_node.appendChild(node); 749 750 root.appendChild(tRNS_node); 751 } 752 753 if (zTXt_keyword.size() > 0) { 755 IIOMetadataNode zTXt_parent = new IIOMetadataNode ("zTXt"); 756 for (int i = 0; i < zTXt_keyword.size(); i++) { 757 IIOMetadataNode zTXt_node = new IIOMetadataNode ("zTXtEntry"); 758 zTXt_node.setAttribute("keyword", (String )zTXt_keyword.get(i)); 759 760 int cm = ((Integer )zTXt_compressionMethod.get(i)).intValue(); 761 zTXt_node.setAttribute("compressionMethod", 762 zTXt_compressionMethodNames[cm]); 763 764 zTXt_node.setAttribute("text", (String )zTXt_text.get(i)); 765 766 zTXt_parent.appendChild(zTXt_node); 767 } 768 769 root.appendChild(zTXt_parent); 770 } 771 772 if (unknownChunkType.size() > 0) { 774 IIOMetadataNode unknown_parent = 775 new IIOMetadataNode ("UnknownChunks"); 776 for (int i = 0; i < unknownChunkType.size(); i++) { 777 IIOMetadataNode unknown_node = 778 new IIOMetadataNode ("UnknownChunk"); 779 unknown_node.setAttribute("type", 780 (String )unknownChunkType.get(i)); 781 unknown_node.setUserObject((byte[])unknownChunkData.get(i)); 782 783 unknown_parent.appendChild(unknown_node); 784 } 785 786 root.appendChild(unknown_parent); 787 } 788 789 return root; 790 } 791 792 private int getNumChannels() { 793 int numChannels = IHDR_numChannels[IHDR_colorType]; 796 if (IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE && 797 tRNS_present && tRNS_colorType == IHDR_colorType) { 798 numChannels = 4; 799 } 800 return numChannels; 801 } 802 803 public IIOMetadataNode getStandardChromaNode() { 804 IIOMetadataNode chroma_node = new IIOMetadataNode ("Chroma"); 805 IIOMetadataNode node = null; 807 node = new IIOMetadataNode ("ColorSpaceType"); 808 node.setAttribute("name", colorSpaceTypeNames[IHDR_colorType]); 809 chroma_node.appendChild(node); 810 811 node = new IIOMetadataNode ("NumChannels"); 812 node.setAttribute("value", Integer.toString(getNumChannels())); 813 chroma_node.appendChild(node); 814 815 if (gAMA_present) { 816 node = new IIOMetadataNode ("Gamma"); 817 node.setAttribute("value", Float.toString(gAMA_gamma*1.0e-5F)); 818 chroma_node.appendChild(node); 819 } 820 821 node = new IIOMetadataNode ("BlackIsZero"); 822 node.setAttribute("value", "true"); 823 chroma_node.appendChild(node); 824 825 if (PLTE_present) { 826 boolean hasAlpha = tRNS_present && 827 (tRNS_colorType == PNGImageReader.PNG_COLOR_PALETTE); 828 829 node = new IIOMetadataNode ("Palette"); 830 for (int i = 0; i < PLTE_red.length; i++) { 831 IIOMetadataNode entry = 832 new IIOMetadataNode ("PaletteEntry"); 833 entry.setAttribute("index", Integer.toString(i)); 834 entry.setAttribute("red", 835 Integer.toString(PLTE_red[i] & 0xff)); 836 entry.setAttribute("green", 837 Integer.toString(PLTE_green[i] & 0xff)); 838 entry.setAttribute("blue", 839 Integer.toString(PLTE_blue[i] & 0xff)); 840 if (hasAlpha) { 841 int alpha = (i < tRNS_alpha.length) ? 842 (tRNS_alpha[i] & 0xff) : 255; 843 entry.setAttribute("alpha", Integer.toString(alpha)); 844 } 845 node.appendChild(entry); 846 } 847 chroma_node.appendChild(node); 848 } 849 850 if (bKGD_present) { 851 if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) { 852 node = new IIOMetadataNode ("BackgroundIndex"); 853 node.setAttribute("value", Integer.toString(bKGD_index)); 854 } else { 855 node = new IIOMetadataNode ("BackgroundColor"); 856 int r, g, b; 857 858 if (bKGD_colorType == PNGImageReader.PNG_COLOR_GRAY) { 859 r = g = b = bKGD_gray; 860 } else { 861 r = bKGD_red; 862 g = bKGD_green; 863 b = bKGD_blue; 864 } 865 node.setAttribute("red", Integer.toString(r)); 866 node.setAttribute("green", Integer.toString(g)); 867 node.setAttribute("blue", Integer.toString(b)); 868 } 869 chroma_node.appendChild(node); 870 } 871 872 return chroma_node; 873 } 874 875 public IIOMetadataNode getStandardCompressionNode() { 876 IIOMetadataNode compression_node = new IIOMetadataNode ("Compression"); 877 IIOMetadataNode node = null; 879 node = new IIOMetadataNode ("CompressionTypeName"); 880 node.setAttribute("value", "deflate"); 881 compression_node.appendChild(node); 882 883 node = new IIOMetadataNode ("Lossless"); 884 node.setAttribute("value", "true"); 885 compression_node.appendChild(node); 886 887 node = new IIOMetadataNode ("NumProgressiveScans"); 888 node.setAttribute("value", 889 (IHDR_interlaceMethod == 0) ? "1" : "7"); 890 compression_node.appendChild(node); 891 892 return compression_node; 893 } 894 895 private String repeat(String s, int times) { 896 if (times == 1) { 897 return s; 898 } 899 StringBuffer sb = new StringBuffer ((s.length() + 1)*times - 1); 900 sb.append(s); 901 for (int i = 1; i < times; i++) { 902 sb.append(" "); 903 sb.append(s); 904 } 905 return sb.toString(); 906 } 907 908 public IIOMetadataNode getStandardDataNode() { 909 IIOMetadataNode data_node = new IIOMetadataNode ("Data"); 910 IIOMetadataNode node = null; 912 node = new IIOMetadataNode ("PlanarConfiguration"); 913 node.setAttribute("value", "PixelInterleaved"); 914 data_node.appendChild(node); 915 916 node = new IIOMetadataNode ("SampleFormat"); 917 node.setAttribute("value", 918 IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE ? 919 "Index" : "UnsignedIntegral"); 920 data_node.appendChild(node); 921 922 String bitDepth = Integer.toString(IHDR_bitDepth); 923 node = new IIOMetadataNode ("BitsPerSample"); 924 node.setAttribute("value", repeat(bitDepth, getNumChannels())); 925 data_node.appendChild(node); 926 927 if (sBIT_present) { 928 node = new IIOMetadataNode ("SignificantBitsPerSample"); 929 String sbits; 930 if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY || 931 sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) { 932 sbits = Integer.toString(sBIT_grayBits); 933 } else { sbits = Integer.toString(sBIT_redBits) + " " + 936 Integer.toString(sBIT_greenBits) + " " + 937 Integer.toString(sBIT_blueBits); 938 } 939 940 if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA || 941 sBIT_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) { 942 sbits += " " + Integer.toString(sBIT_alphaBits); 943 } 944 945 node.setAttribute("value", sbits); 946 data_node.appendChild(node); 947 } 948 949 951 return data_node; 952 } 953 954 public IIOMetadataNode getStandardDimensionNode() { 955 IIOMetadataNode dimension_node = new IIOMetadataNode ("Dimension"); 956 IIOMetadataNode node = null; 958 node = new IIOMetadataNode ("PixelAspectRatio"); 959 float ratio = pHYs_present ? 960 (float)pHYs_pixelsPerUnitXAxis/pHYs_pixelsPerUnitYAxis : 1.0F; 961 node.setAttribute("value", Float.toString(ratio)); 962 dimension_node.appendChild(node); 963 964 node = new IIOMetadataNode ("ImageOrientation"); 965 node.setAttribute("value", "Normal"); 966 dimension_node.appendChild(node); 967 968 if (pHYs_present && pHYs_unitSpecifier == PHYS_UNIT_METER) { 969 node = new IIOMetadataNode ("HorizontalPixelSize"); 970 node.setAttribute("value", 971 Float.toString(1000.0F/pHYs_pixelsPerUnitXAxis)); 972 dimension_node.appendChild(node); 973 974 node = new IIOMetadataNode ("VerticalPixelSize"); 975 node.setAttribute("value", 976 Float.toString(1000.0F/pHYs_pixelsPerUnitYAxis)); 977 dimension_node.appendChild(node); 978 } 979 980 return dimension_node; 981 } 982 983 public IIOMetadataNode getStandardDocumentNode() { 984 if (!tIME_present) { 985 return null; 986 } 987 988 IIOMetadataNode document_node = new IIOMetadataNode ("Document"); 989 IIOMetadataNode node = null; 991 node = new IIOMetadataNode ("ImageModificationTime"); 992 node.setAttribute("year", Integer.toString(tIME_year)); 993 node.setAttribute("month", Integer.toString(tIME_month)); 994 node.setAttribute("day", Integer.toString(tIME_day)); 995 node.setAttribute("hour", Integer.toString(tIME_hour)); 996 node.setAttribute("minute", Integer.toString(tIME_minute)); 997 node.setAttribute("second", Integer.toString(tIME_second)); 998 document_node.appendChild(node); 999 1000 return document_node; 1001 } 1002 1003 public IIOMetadataNode getStandardTextNode() { 1004 int numEntries = tEXt_keyword.size() + 1005 iTXt_keyword.size() + zTXt_keyword.size(); 1006 if (numEntries == 0) { 1007 return null; 1008 } 1009 1010 IIOMetadataNode text_node = new IIOMetadataNode ("Text"); 1011 IIOMetadataNode node = null; 1013 for (int i = 0; i < tEXt_keyword.size(); i++) { 1014 node = new IIOMetadataNode ("TextEntry"); 1015 node.setAttribute("keyword", (String )tEXt_keyword.get(i)); 1016 node.setAttribute("value", (String )tEXt_text.get(i)); 1017 node.setAttribute("encoding", "ISO-8859-1"); 1018 node.setAttribute("compression", "none"); 1019 1020 text_node.appendChild(node); 1021 } 1022 1023 for (int i = 0; i < iTXt_keyword.size(); i++) { 1024 node = new IIOMetadataNode ("TextEntry"); 1025 node.setAttribute("keyword", (String )iTXt_keyword.get(i)); 1026 node.setAttribute("value", (String )iTXt_text.get(i)); 1027 node.setAttribute("language", 1028 (String )iTXt_languageTag.get(i)); 1029 if (((Integer )iTXt_compressionFlag.get(i)).intValue() == 1) { 1030 node.setAttribute("compression", "deflate"); 1031 } else { 1032 node.setAttribute("compression", "none"); 1033 } 1034 1035 text_node.appendChild(node); 1036 } 1037 1038 for (int i = 0; i < zTXt_keyword.size(); i++) { 1039 node = new IIOMetadataNode ("TextEntry"); 1040 node.setAttribute("keyword", (String )zTXt_keyword.get(i)); 1041 node.setAttribute("value", (String )zTXt_text.get(i)); 1042 node.setAttribute("compression", "deflate"); 1043 1044 text_node.appendChild(node); 1045 } 1046 1047 return text_node; 1048 } 1049 1050 public IIOMetadataNode getStandardTransparencyNode() { 1051 IIOMetadataNode transparency_node = 1052 new IIOMetadataNode ("Transparency"); 1053 IIOMetadataNode node = null; 1055 node = new IIOMetadataNode ("Alpha"); 1056 boolean hasAlpha = 1057 (IHDR_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) || 1058 (IHDR_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) || 1059 (IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE && 1060 tRNS_present && 1061 (tRNS_colorType == IHDR_colorType) && 1062 (tRNS_alpha != null)); 1063 node.setAttribute("value", hasAlpha ? "nonpremultipled" : "none"); 1064 transparency_node.appendChild(node); 1065 1066 if (tRNS_present) { 1067 node = new IIOMetadataNode ("TransparentColor"); 1068 if (tRNS_colorType == PNGImageReader.PNG_COLOR_RGB) { 1069 node.setAttribute("value", 1070 Integer.toString(tRNS_red) + " " + 1071 Integer.toString(tRNS_green) + " " + 1072 Integer.toString(tRNS_blue)); 1073 } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_GRAY) { 1074 node.setAttribute("value", Integer.toString(tRNS_gray)); 1075 } 1076 transparency_node.appendChild(node); 1077 } 1078 1079 return transparency_node; 1080 } 1081 1082 private void fatal(Node node, String reason) 1084 throws IIOInvalidTreeException { 1085 throw new IIOInvalidTreeException (reason, node); 1086 } 1087 1088 private String getStringAttribute(Node node, String name, 1090 String defaultValue, boolean required) 1091 throws IIOInvalidTreeException { 1092 Node attr = node.getAttributes().getNamedItem(name); 1093 if (attr == null) { 1094 if (!required) { 1095 return defaultValue; 1096 } else { 1097 fatal(node, "Required attribute " + name + " not present!"); 1098 } 1099 } 1100 return attr.getNodeValue(); 1101 } 1102 1103 1104 private int getIntAttribute(Node node, String name, 1106 int defaultValue, boolean required) 1107 throws IIOInvalidTreeException { 1108 String value = getStringAttribute(node, name, null, required); 1109 if (value == null) { 1110 return defaultValue; 1111 } 1112 return Integer.parseInt(value); 1113 } 1114 1115 private float getFloatAttribute(Node node, String name, 1117 float defaultValue, boolean required) 1118 throws IIOInvalidTreeException { 1119 String value = getStringAttribute(node, name, null, required); 1120 if (value == null) { 1121 return defaultValue; 1122 } 1123 return Float.parseFloat(value); 1124 } 1125 1126 private int getIntAttribute(Node node, String name) 1128 throws IIOInvalidTreeException { 1129 return getIntAttribute(node, name, -1, true); 1130 } 1131 1132 private float getFloatAttribute(Node node, String name) 1134 throws IIOInvalidTreeException { 1135 return getFloatAttribute(node, name, -1.0F, true); 1136 } 1137 1138 private boolean getBooleanAttribute(Node node, String name, 1140 boolean defaultValue, 1141 boolean required) 1142 throws IIOInvalidTreeException { 1143 Node attr = node.getAttributes().getNamedItem(name); 1144 if (attr == null) { 1145 if (!required) { 1146 return defaultValue; 1147 } else { 1148 fatal(node, "Required attribute " + name + " not present!"); 1149 } 1150 } 1151 String value = attr.getNodeValue(); 1152 if (value.equals("true")) { 1153 return true; 1154 } else if (value.equals("false")) { 1155 return false; 1156 } else { 1157 fatal(node, "Attribute " + name + " must be 'true' or 'false'!"); 1158 return false; 1159 } 1160 } 1161 1162 private boolean getBooleanAttribute(Node node, String name) 1164 throws IIOInvalidTreeException { 1165 return getBooleanAttribute(node, name, false, true); 1166 } 1167 1168 private int getEnumeratedAttribute(Node node, 1170 String name, String [] legalNames, 1171 int defaultValue, boolean required) 1172 throws IIOInvalidTreeException { 1173 Node attr = node.getAttributes().getNamedItem(name); 1174 if (attr == null) { 1175 if (!required) { 1176 return defaultValue; 1177 } else { 1178 fatal(node, "Required attribute " + name + " not present!"); 1179 } 1180 } 1181 String value = attr.getNodeValue(); 1182 for (int i = 0; i < legalNames.length; i++) { 1183 if (value.equals(legalNames[i])) { 1184 return i; 1185 } 1186 } 1187 1188 fatal(node, "Illegal value for attribute " + name + "!"); 1189 return -1; 1190 } 1191 1192 private int getEnumeratedAttribute(Node node, 1194 String name, String [] legalNames) 1195 throws IIOInvalidTreeException { 1196 return getEnumeratedAttribute(node, name, legalNames, -1, true); 1197 } 1198 1199 private String getAttribute(Node node, String name, 1201 String defaultValue, boolean required) 1202 throws IIOInvalidTreeException { 1203 Node attr = node.getAttributes().getNamedItem(name); 1204 if (attr == null) { 1205 if (!required) { 1206 return defaultValue; 1207 } else { 1208 fatal(node, "Required attribute " + name + " not present!"); 1209 } 1210 } 1211 return attr.getNodeValue(); 1212 } 1213 1214 private String getAttribute(Node node, String name) 1216 throws IIOInvalidTreeException { 1217 return getAttribute(node, name, null, true); 1218 } 1219 1220 public void mergeTree(String formatName, Node root) 1221 throws IIOInvalidTreeException { 1222 if (formatName.equals(nativeMetadataFormatName)) { 1223 if (root == null) { 1224 throw new IllegalArgumentException ("root == null!"); 1225 } 1226 mergeNativeTree(root); 1227 } else if (formatName.equals 1228 (IIOMetadataFormatImpl.standardMetadataFormatName)) { 1229 if (root == null) { 1230 throw new IllegalArgumentException ("root == null!"); 1231 } 1232 mergeStandardTree(root); 1233 } else { 1234 throw new IllegalArgumentException ("Not a recognized format!"); 1235 } 1236 } 1237 1238 private void mergeNativeTree(Node root) 1239 throws IIOInvalidTreeException { 1240 Node node = root; 1241 if (!node.getNodeName().equals(nativeMetadataFormatName)) { 1242 fatal(node, "Root must be " + nativeMetadataFormatName); 1243 } 1244 1245 node = node.getFirstChild(); 1246 while (node != null) { 1247 String name = node.getNodeName(); 1248 1249 if (name.equals("IHDR")) { 1250 IHDR_width = getIntAttribute(node, "width"); 1251 IHDR_height = getIntAttribute(node, "height"); 1252 IHDR_bitDepth = getEnumeratedAttribute(node, "bitDepth", 1253 IHDR_bitDepths); 1254 IHDR_colorType = getEnumeratedAttribute(node, "colorType", 1255 IHDR_colorTypeNames); 1256 IHDR_compressionMethod = 1257 getEnumeratedAttribute(node, "compressionMethod", 1258 IHDR_compressionMethodNames); 1259 IHDR_filterMethod = 1260 getEnumeratedAttribute(node, 1261 "filterMethod", 1262 IHDR_filterMethodNames); 1263 IHDR_interlaceMethod = 1264 getEnumeratedAttribute(node, "interlaceMethod", 1265 IHDR_interlaceMethodNames); 1266 IHDR_present = true; 1267 } else if (name.equals("PLTE")) { 1268 byte[] red = new byte[256]; 1269 byte[] green = new byte[256]; 1270 byte[] blue = new byte[256]; 1271 int maxindex = -1; 1272 1273 Node PLTE_entry = node.getFirstChild(); 1274 if (PLTE_entry == null) { 1275 fatal(node, "Palette has no entries!"); 1276 } 1277 1278 while (PLTE_entry != null) { 1279 if (!PLTE_entry.getNodeName().equals("PLTEEntry")) { 1280 fatal(node, 1281 "Only a PLTEEntry may be a child of a PLTE!"); 1282 } 1283 1284 int index = getIntAttribute(PLTE_entry, "index"); 1285 if (index < 0 || index > 255) { 1286 fatal(node, 1287 "Bad value for PLTEEntry attribute index!"); 1288 } 1289 if (index > maxindex) { 1290 maxindex = index; 1291 } 1292 red[index] = 1293 (byte)getIntAttribute(PLTE_entry, "red"); 1294 green[index] = 1295 (byte)getIntAttribute(PLTE_entry, "green"); 1296 blue[index] = 1297 (byte)getIntAttribute(PLTE_entry, "blue"); 1298 1299 PLTE_entry = PLTE_entry.getNextSibling(); 1300 } 1301 1302 int numEntries = maxindex + 1; 1303 PLTE_red = new byte[numEntries]; 1304 PLTE_green = new byte[numEntries]; 1305 PLTE_blue = new byte[numEntries]; 1306 System.arraycopy(red, 0, PLTE_red, 0, numEntries); 1307 System.arraycopy(green, 0, PLTE_green, 0, numEntries); 1308 System.arraycopy(blue, 0, PLTE_blue, 0, numEntries); 1309 PLTE_present = true; 1310 } else if (name.equals("bKGD")) { 1311 bKGD_present = false; Node bKGD_node = node.getFirstChild(); 1313 if (bKGD_node == null) { 1314 fatal(node, "bKGD node has no children!"); 1315 } 1316 String bKGD_name = bKGD_node.getNodeName(); 1317 if (bKGD_name.equals("bKGD_Palette")) { 1318 bKGD_index = getIntAttribute(bKGD_node, "index"); 1319 bKGD_colorType = PNGImageReader.PNG_COLOR_PALETTE; 1320 } else if (bKGD_name.equals("bKGD_Grayscale")) { 1321 bKGD_gray = getIntAttribute(bKGD_node, "gray"); 1322 bKGD_colorType = PNGImageReader.PNG_COLOR_GRAY; 1323 } else if (bKGD_name.equals("bKGD_RGB")) { 1324 bKGD_red = getIntAttribute(bKGD_node, "red"); 1325 bKGD_green = getIntAttribute(bKGD_node, "green"); 1326 bKGD_blue = getIntAttribute(bKGD_node, "blue"); 1327 bKGD_colorType = PNGImageReader.PNG_COLOR_RGB; 1328 } else { 1329 fatal(node, "Bad child of a bKGD node!"); 1330 } 1331 if (bKGD_node.getNextSibling() != null) { 1332 fatal(node, "bKGD node has more than one child!"); 1333 } 1334 1335 bKGD_present = true; 1336 } else if (name.equals("cHRM")) { 1337 cHRM_whitePointX = getIntAttribute(node, "whitePointX"); 1338 cHRM_whitePointY = getIntAttribute(node, "whitePointY"); 1339 cHRM_redX = getIntAttribute(node, "redX"); 1340 cHRM_redY = getIntAttribute(node, "redY"); 1341 cHRM_greenX = getIntAttribute(node, "greenX"); 1342 cHRM_greenY = getIntAttribute(node, "greenY"); 1343 cHRM_blueX = getIntAttribute(node, "blueX"); 1344 cHRM_blueY = getIntAttribute(node, "blueY"); 1345 1346 cHRM_present = true; 1347 } else if (name.equals("gAMA")) { 1348 gAMA_gamma = getIntAttribute(node, "value"); 1349 gAMA_present = true; 1350 } else if (name.equals("hIST")) { 1351 char[] hist = new char[256]; 1352 int maxindex = -1; 1353 1354 Node hIST_entry = node.getFirstChild(); 1355 if (hIST_entry == null) { 1356 fatal(node, "hIST node has no children!"); 1357 } 1358 1359 while (hIST_entry != null) { 1360 if (!hIST_entry.getNodeName().equals("hISTEntry")) { 1361 fatal(node, 1362 "Only a hISTEntry may be a child of a hIST!"); 1363 } 1364 1365 int index = getIntAttribute(hIST_entry, "index"); 1366 if (index < 0 || index > 255) { 1367 fatal(node, 1368 "Bad value for histEntry attribute index!"); 1369 } 1370 if (index > maxindex) { 1371 maxindex = index; 1372 } 1373 hist[index] = 1374 (char)getIntAttribute(hIST_entry, "value"); 1375 1376 hIST_entry = hIST_entry.getNextSibling(); 1377 } 1378 1379 int numEntries = maxindex + 1; 1380 hIST_histogram = new char[numEntries]; 1381 System.arraycopy(hist, 0, hIST_histogram, 0, numEntries); 1382 1383 hIST_present = true; 1384 } else if (name.equals("iCCP")) { 1385 iCCP_profileName = getAttribute(node, "profileName"); 1386 iCCP_compressionMethod = 1387 getEnumeratedAttribute(node, "compressionMethod", 1388 iCCP_compressionMethodNames); 1389 Object compressedProfile = 1390 ((IIOMetadataNode )node).getUserObject(); 1391 if (compressedProfile == null) { 1392 fatal(node, "No ICCP profile present in user object!"); 1393 } 1394 if (!(compressedProfile instanceof byte[])) { 1395 fatal(node, "User object not a byte array!"); 1396 } 1397 1398 iCCP_compressedProfile = 1399 (byte[])((byte[])compressedProfile).clone(); 1400 1401 iCCP_present = true; 1402 } else if (name.equals("iTXt")) { 1403 Node iTXt_node = node.getFirstChild(); 1404 while (iTXt_node != null) { 1405 if (!iTXt_node.getNodeName().equals("iTXtEntry")) { 1406 fatal(node, 1407 "Only an iTXtEntry may be a child of an iTXt!"); 1408 } 1409 1410 String keyword = getAttribute(iTXt_node, "keyword"); 1411 iTXt_keyword.add(keyword); 1412 1413 boolean compressionFlag = 1414 getBooleanAttribute(iTXt_node, "compressionFlag"); 1415 iTXt_compressionFlag.add(new Boolean (compressionFlag)); 1416 1417 String compressionMethod = 1418 getAttribute(iTXt_node, "compressionMethod"); 1419 iTXt_compressionMethod.add(compressionMethod); 1420 1421 String languageTag = 1422 getAttribute(iTXt_node, "languageTag"); 1423 iTXt_languageTag.add(languageTag); 1424 1425 String translatedKeyword = 1426 getAttribute(iTXt_node, "translatedKeyword"); 1427 iTXt_translatedKeyword.add(translatedKeyword); 1428 1429 String text = getAttribute(iTXt_node, "text"); 1430 iTXt_text.add(text); 1431 1432 iTXt_node = iTXt_node.getNextSibling(); 1433 } 1434 } else if (name.equals("pHYs")) { 1435 pHYs_pixelsPerUnitXAxis = 1436 getIntAttribute(node, "pixelsPerUnitXAxis"); 1437 pHYs_pixelsPerUnitYAxis = 1438 getIntAttribute(node, "pixelsPerUnitYAxis"); 1439 pHYs_unitSpecifier = 1440 getEnumeratedAttribute(node, "unitSpecifier", 1441 unitSpecifierNames); 1442 1443 pHYs_present = true; 1444 } else if (name.equals("sBIT")) { 1445 sBIT_present = false; Node sBIT_node = node.getFirstChild(); 1447 if (sBIT_node == null) { 1448 fatal(node, "sBIT node has no children!"); 1449 } 1450 String sBIT_name = sBIT_node.getNodeName(); 1451 if (sBIT_name.equals("sBIT_Grayscale")) { 1452 sBIT_grayBits = getIntAttribute(sBIT_node, "gray"); 1453 sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY; 1454 } else if (sBIT_name.equals("sBIT_GrayAlpha")) { 1455 sBIT_grayBits = getIntAttribute(sBIT_node, "gray"); 1456 sBIT_alphaBits = getIntAttribute(sBIT_node, "alpha"); 1457 sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA; 1458 } else if (sBIT_name.equals("sBIT_RGB")) { 1459 sBIT_redBits = getIntAttribute(sBIT_node, "red"); 1460 sBIT_greenBits = getIntAttribute(sBIT_node, "green"); 1461 sBIT_blueBits = getIntAttribute(sBIT_node, "blue"); 1462 sBIT_colorType = PNGImageReader.PNG_COLOR_RGB; 1463 } else if (sBIT_name.equals("sBIT_RGBAlpha")) { 1464 sBIT_redBits = getIntAttribute(sBIT_node, "red"); 1465 sBIT_greenBits = getIntAttribute(sBIT_node, "green"); 1466 sBIT_blueBits = getIntAttribute(sBIT_node, "blue"); 1467 sBIT_alphaBits = getIntAttribute(sBIT_node, "alpha"); 1468 sBIT_colorType = PNGImageReader.PNG_COLOR_RGB_ALPHA; 1469 } else if (sBIT_name.equals("sBIT_Palette")) { 1470 sBIT_redBits = getIntAttribute(sBIT_node, "red"); 1471 sBIT_greenBits = getIntAttribute(sBIT_node, "green"); 1472 sBIT_blueBits = getIntAttribute(sBIT_node, "blue"); 1473 sBIT_colorType = PNGImageReader.PNG_COLOR_PALETTE; 1474 } else { 1475 fatal(node, "Bad child of an sBIT node!"); 1476 } 1477 if (sBIT_node.getNextSibling() != null) { 1478 fatal(node, "sBIT node has more than one child!"); 1479 } 1480 1481 sBIT_present = true; 1482 } else if (name.equals("sPLT")) { 1483 sPLT_paletteName = getAttribute(node, "name"); 1484 sPLT_sampleDepth = getIntAttribute(node, "sampleDepth"); 1485 1486 int[] red = new int[256]; 1487 int[] green = new int[256]; 1488 int[] blue = new int[256]; 1489 int[] alpha = new int[256]; 1490 int[] frequency = new int[256]; 1491 int maxindex = -1; 1492 1493 Node sPLT_entry = node.getFirstChild(); 1494 if (sPLT_entry == null) { 1495 fatal(node, "sPLT node has no children!"); 1496 } 1497 1498 while (sPLT_entry != null) { 1499 if (!sPLT_entry.getNodeName().equals("sPLTEntry")) { 1500 fatal(node, 1501 "Only an sPLTEntry may be a child of an sPLT!"); 1502 } 1503 1504 int index = getIntAttribute(sPLT_entry, "index"); 1505 if (index < 0 || index > 255) { 1506 fatal(node, 1507 "Bad value for PLTEEntry attribute index!"); 1508 } 1509 if (index > maxindex) { 1510 maxindex = index; 1511 } 1512 red[index] = getIntAttribute(sPLT_entry, "red"); 1513 green[index] = getIntAttribute(sPLT_entry, "green"); 1514 blue[index] = getIntAttribute(sPLT_entry, "blue"); 1515 alpha[index] = getIntAttribute(sPLT_entry, "alpha"); 1516 frequency[index] = 1517 getIntAttribute(sPLT_entry, "frequency"); 1518 1519 sPLT_entry = sPLT_entry.getNextSibling(); 1520 } 1521 1522 int numEntries = maxindex + 1; 1523 sPLT_red = new int[numEntries]; 1524 sPLT_green = new int[numEntries]; 1525 sPLT_blue = new int[numEntries]; 1526 sPLT_alpha = new int[numEntries]; 1527 sPLT_frequency = new int[numEntries]; 1528 System.arraycopy(red, 0, sPLT_red, 0, numEntries); 1529 System.arraycopy(green, 0, sPLT_green, 0, numEntries); 1530 System.arraycopy(blue, 0, sPLT_blue, 0, numEntries); 1531 System.arraycopy(alpha, 0, sPLT_alpha, 0, numEntries); 1532 System.arraycopy(frequency, 0, 1533 sPLT_frequency, 0, numEntries); 1534 1535 sPLT_present = true; 1536 } else if (name.equals("sRGB")) { 1537 sRGB_renderingIntent = 1538 getEnumeratedAttribute(node, "renderingIntent", 1539 renderingIntentNames); 1540 1541 sRGB_present = true; 1542 } else if (name.equals("tEXt")) { 1543 Node tEXt_node = node.getFirstChild(); 1544 while (tEXt_node != null) { 1545 if (!tEXt_node.getNodeName().equals("tEXtEntry")) { 1546 fatal(node, 1547 "Only an tEXtEntry may be a child of an tEXt!"); 1548 } 1549 1550 String keyword = getAttribute(tEXt_node, "keyword"); 1551 tEXt_keyword.add(keyword); 1552 1553 String text = getAttribute(tEXt_node, "value"); 1554 tEXt_text.add(text); 1555 1556 tEXt_node = tEXt_node.getNextSibling(); 1557 } 1558 } else if (name.equals("tIME")) { 1559 tIME_year = getIntAttribute(node, "year"); 1560 tIME_month = getIntAttribute(node, "month"); 1561 tIME_day = getIntAttribute(node, "day"); 1562 tIME_hour = getIntAttribute(node, "hour"); 1563 tIME_minute = getIntAttribute(node, "minute"); 1564 tIME_second = getIntAttribute(node, "second"); 1565 1566 tIME_present = true; 1567 } else if (name.equals("tRNS")) { 1568 tRNS_present = false; Node tRNS_node = node.getFirstChild(); 1570 if (tRNS_node == null) { 1571 fatal(node, "tRNS node has no children!"); 1572 } 1573 String tRNS_name = tRNS_node.getNodeName(); 1574 if (tRNS_name.equals("tRNS_Palette")) { 1575 byte[] alpha = new byte[256]; 1576 int maxindex = -1; 1577 1578 Node tRNS_paletteEntry = tRNS_node.getFirstChild(); 1579 if (tRNS_paletteEntry == null) { 1580 fatal(node, "tRNS_Palette node has no children!"); 1581 } 1582 while (tRNS_paletteEntry != null) { 1583 if (!tRNS_paletteEntry.getNodeName().equals( 1584 "tRNS_PaletteEntry")) { 1585 fatal(node, 1586 "Only a tRNS_PaletteEntry may be a child of a tRNS_Palette!"); 1587 } 1588 int index = 1589 getIntAttribute(tRNS_paletteEntry, "index"); 1590 if (index < 0 || index > 255) { 1591 fatal(node, 1592 "Bad value for tRNS_PaletteEntry attribute index!"); 1593 } 1594 if (index > maxindex) { 1595 maxindex = index; 1596 } 1597 alpha[index] = 1598 (byte)getIntAttribute(tRNS_paletteEntry, 1599 "alpha"); 1600 1601 tRNS_paletteEntry = 1602 tRNS_paletteEntry.getNextSibling(); 1603 } 1604 1605 int numEntries = maxindex + 1; 1606 tRNS_alpha = new byte[numEntries]; 1607 tRNS_colorType = PNGImageReader.PNG_COLOR_PALETTE; 1608 System.arraycopy(alpha, 0, tRNS_alpha, 0, numEntries); 1609 } else if (tRNS_name.equals("tRNS_Grayscale")) { 1610 tRNS_gray = getIntAttribute(tRNS_node, "gray"); 1611 tRNS_colorType = PNGImageReader.PNG_COLOR_GRAY; 1612 } else if (tRNS_name.equals("tRNS_RGB")) { 1613 tRNS_red = getIntAttribute(tRNS_node, "red"); 1614 tRNS_green = getIntAttribute(tRNS_node, "green"); 1615 tRNS_blue = getIntAttribute(tRNS_node, "blue"); 1616 tRNS_colorType = PNGImageReader.PNG_COLOR_RGB; 1617 } else { 1618 fatal(node, "Bad child of a tRNS node!"); 1619 } 1620 if (tRNS_node.getNextSibling() != null) { 1621 fatal(node, "tRNS node has more than one child!"); 1622 } 1623 1624 tRNS_present = true; 1625 } else if (name.equals("zTXt")) { 1626 Node zTXt_node = node.getFirstChild(); 1627 while (zTXt_node != null) { 1628 if (!zTXt_node.getNodeName().equals("zTXtEntry")) { 1629 fatal(node, 1630 "Only an zTXtEntry may be a child of an zTXt!"); 1631 } 1632 1633 String keyword = getAttribute(zTXt_node, "keyword"); 1634 zTXt_keyword.add(keyword); 1635 1636 int compressionMethod = 1637 getEnumeratedAttribute(zTXt_node, "compressionMethod", 1638 zTXt_compressionMethodNames); 1639 zTXt_compressionMethod.add(new Integer (compressionMethod)); 1640 1641 String text = getAttribute(zTXt_node, "text"); 1642 zTXt_text.add(text); 1643 1644 zTXt_node = zTXt_node.getNextSibling(); 1645 } 1646 } else if (name.equals("UnknownChunks")) { 1647 Node unknown_node = node.getFirstChild(); 1648 while (unknown_node != null) { 1649 if (!unknown_node.getNodeName().equals("UnknownChunk")) { 1650 fatal(node, 1651 "Only an UnknownChunk may be a child of an UnknownChunks!"); 1652 } 1653 String chunkType = getAttribute(unknown_node, "type"); 1654 Object chunkData = 1655 ((IIOMetadataNode )unknown_node).getUserObject(); 1656 1657 if (chunkType.length() != 4) { 1658 fatal(unknown_node, 1659 "Chunk type must be 4 characters!"); 1660 } 1661 if (chunkData == null) { 1662 fatal(unknown_node, 1663 "No chunk data present in user object!"); 1664 } 1665 if (!(chunkData instanceof byte[])) { 1666 fatal(unknown_node, 1667 "User object not a byte array!"); 1668 } 1669 unknownChunkType.add(chunkType); 1670 unknownChunkData.add(((byte[])chunkData).clone()); 1671 1672 unknown_node = unknown_node.getNextSibling(); 1673 } 1674 } else { 1675 fatal(node, "Unknown child of root node!"); 1676 } 1677 1678 node = node.getNextSibling(); 1679 } 1680 } 1681 1682 private boolean isISOLatin(String s) { 1683 int len = s.length(); 1684 for (int i = 0; i < len; i++) { 1685 if (s.charAt(i) > 255) { 1686 return false; 1687 } 1688 } 1689 return true; 1690 } 1691 1692 private void mergeStandardTree(Node root) 1693 throws IIOInvalidTreeException { 1694 Node node = root; 1695 if (!node.getNodeName() 1696 .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) { 1697 fatal(node, "Root must be " + 1698 IIOMetadataFormatImpl.standardMetadataFormatName); 1699 } 1700 1701 node = node.getFirstChild(); 1702 while (node != null) { 1703 String name = node.getNodeName(); 1704 1705 if (name.equals("Chroma")) { 1706 Node child = node.getFirstChild(); 1707 while (child != null) { 1708 String childName = child.getNodeName(); 1709 if (childName.equals("Gamma")) { 1710 float gamma = getFloatAttribute(child, "value"); 1711 gAMA_present = true; 1712 gAMA_gamma = (int)(gamma*100000 + 0.5); 1713 } else if (childName.equals("Palette")) { 1714 byte[] red = new byte[256]; 1715 byte[] green = new byte[256]; 1716 byte[] blue = new byte[256]; 1717 int maxindex = -1; 1718 1719 Node entry = child.getFirstChild(); 1720 while (entry != null) { 1721 int index = getIntAttribute(entry, "index"); 1722 if (index >= 0 && index <= 255) { 1723 red[index] = 1724 (byte)getIntAttribute(entry, "red"); 1725 green[index] = 1726 (byte)getIntAttribute(entry, "green"); 1727 blue[index] = 1728 (byte)getIntAttribute(entry, "blue"); 1729 if (index > maxindex) { 1730 maxindex = index; 1731 } 1732 } 1733 entry = entry.getNextSibling(); 1734 } 1735 1736 int numEntries = maxindex + 1; 1737 PLTE_red = new byte[numEntries]; 1738 PLTE_green = new byte[numEntries]; 1739 PLTE_blue = new byte[numEntries]; 1740 System.arraycopy(red, 0, PLTE_red, 0, numEntries); 1741 System.arraycopy(green, 0, PLTE_green, 0, numEntries); 1742 System.arraycopy(blue, 0, PLTE_blue, 0, numEntries); 1743 PLTE_present = true; 1744 } else if (childName.equals("BackgroundIndex")) { 1745 bKGD_present = true; 1746 bKGD_colorType = PNGImageReader.PNG_COLOR_PALETTE; 1747 bKGD_index = getIntAttribute(child, "value"); 1748 } else if (childName.equals("BackgroundColor")) { 1749 int red = getIntAttribute(child, "red"); 1750 int green = getIntAttribute(child, "green"); 1751 int blue = getIntAttribute(child, "blue"); 1752 if (red == green && red == blue) { 1753 bKGD_colorType = PNGImageReader.PNG_COLOR_GRAY; 1754 bKGD_gray = red; 1755 } else { 1756 bKGD_red = red; 1757 bKGD_green = green; 1758 bKGD_blue = blue; 1759 } 1760 bKGD_present = true; 1761 } 1762 1765 child = child.getNextSibling(); 1766 } 1767 } else if (name.equals("Compression")) { 1768 Node child = node.getFirstChild(); 1769 while (child != null) { 1770 String childName = child.getNodeName(); 1771 if (childName.equals("NumProgressiveScans")) { 1772 int scans = getIntAttribute(child, "value"); 1774 IHDR_interlaceMethod = (scans > 1) ? 1 : 0; 1775 } 1779 child = child.getNextSibling(); 1780 } 1781 } else if (name.equals("Data")) { 1782 Node child = node.getFirstChild(); 1783 while (child != null) { 1784 String childName = child.getNodeName(); 1785 if (childName.equals("BitsPerSample")) { 1786 String s = getAttribute(child, "value"); 1787 StringTokenizer t = new StringTokenizer (s); 1788 int maxBits = -1; 1789 while (t.hasMoreTokens()) { 1790 int bits = Integer.parseInt(t.nextToken()); 1791 if (bits > maxBits) { 1792 maxBits = bits; 1793 } 1794 } 1795 if (maxBits < 1) { 1796 maxBits = 1; 1797 } 1798 if (maxBits == 3) maxBits = 4; 1799 if (maxBits > 4 || maxBits < 8) { 1800 maxBits = 8; 1801 } 1802 if (maxBits > 8) { 1803 maxBits = 16; 1804 } 1805 IHDR_bitDepth = maxBits; 1806 } else if (childName.equals("SignificantBitsPerSample")) { 1807 String s = getAttribute(child, "value"); 1808 StringTokenizer t = new StringTokenizer (s); 1809 int numTokens = t.countTokens(); 1810 if (numTokens == 1) { 1811 sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY; 1812 sBIT_grayBits = Integer.parseInt(t.nextToken()); 1813 } else if (numTokens == 2) { 1814 sBIT_colorType = 1815 PNGImageReader.PNG_COLOR_GRAY_ALPHA; 1816 sBIT_grayBits = Integer.parseInt(t.nextToken()); 1817 sBIT_alphaBits = Integer.parseInt(t.nextToken()); 1818 } else if (numTokens == 3) { 1819 sBIT_colorType = PNGImageReader.PNG_COLOR_RGB; 1820 sBIT_redBits = Integer.parseInt(t.nextToken()); 1821 sBIT_greenBits = Integer.parseInt(t.nextToken()); 1822 sBIT_blueBits = Integer.parseInt(t.nextToken()); 1823 } else if (numTokens == 4) { 1824 sBIT_colorType = 1825 PNGImageReader.PNG_COLOR_RGB_ALPHA; 1826 sBIT_redBits = Integer.parseInt(t.nextToken()); 1827 sBIT_greenBits = Integer.parseInt(t.nextToken()); 1828 sBIT_blueBits = Integer.parseInt(t.nextToken()); 1829 sBIT_alphaBits = Integer.parseInt(t.nextToken()); 1830 } 1831 if (numTokens >= 1 && numTokens <= 4) { 1832 sBIT_present = true; 1833 } 1834 } 1838 child = child.getNextSibling(); 1839 } 1840 } else if (name.equals("Dimension")) { 1841 boolean gotWidth = false; 1842 boolean gotHeight = false; 1843 boolean gotAspectRatio = false; 1844 1845 float width = -1.0F; 1846 float height = -1.0F; 1847 float aspectRatio = -1.0F; 1848 1849 Node child = node.getFirstChild(); 1850 while (child != null) { 1851 String childName = child.getNodeName(); 1852 if (childName.equals("PixelAspectRatio")) { 1853 aspectRatio = getFloatAttribute(child, "value"); 1854 gotAspectRatio = true; 1855 } else if (childName.equals("HorizontalPixelSize")) { 1856 width = getFloatAttribute(child, "value"); 1857 gotWidth = true; 1858 } else if (childName.equals("VerticalPixelSize")) { 1859 height = getFloatAttribute(child, "value"); 1860 gotHeight = true; 1861 } 1871 child = child.getNextSibling(); 1872 } 1873 1874 if (gotWidth && gotHeight) { 1875 pHYs_present = true; 1876 pHYs_unitSpecifier = 1; 1877 pHYs_pixelsPerUnitXAxis = (int)(width*1000 + 0.5F); 1878 pHYs_pixelsPerUnitYAxis = (int)(height*1000 + 0.5F); 1879 } else if (gotAspectRatio) { 1880 pHYs_present = true; 1881 pHYs_unitSpecifier = 0; 1882 1883 int denom = 1; 1885 for (; denom < 100; denom++) { 1886 int num = (int)(aspectRatio*denom); 1887 if (Math.abs(num/denom - aspectRatio) < 0.001) { 1888 break; 1889 } 1890 } 1891 pHYs_pixelsPerUnitXAxis = (int)(aspectRatio*denom); 1892 pHYs_pixelsPerUnitYAxis = denom; 1893 } 1894 } else if (name.equals("Document")) { 1895 Node child = node.getFirstChild(); 1896 while (child != null) { 1897 String childName = child.getNodeName(); 1898 if (childName.equals("ImageModificationTime")) { 1899 tIME_present = true; 1900 tIME_year = getIntAttribute(child, "year"); 1901 tIME_month = getIntAttribute(child, "month"); 1902 tIME_day = getIntAttribute(child, "day"); 1903 tIME_hour = 1904 getIntAttribute(child, "hour", 0, false); 1905 tIME_minute = 1906 getIntAttribute(child, "minute", 0, false); 1907 tIME_second = 1908 getIntAttribute(child, "second", 0, false); 1909 } 1912 child = child.getNextSibling(); 1913 } 1914 } else if (name.equals("Text")) { 1915 Node child = node.getFirstChild(); 1916 while (child != null) { 1917 String childName = child.getNodeName(); 1918 if (childName.equals("TextEntry")) { 1919 String keyword = getAttribute(child, "keyword"); 1920 String value = getAttribute(child, "value"); 1921 String encoding = getAttribute(child, "encoding"); 1922 String language = getAttribute(child, "language"); 1923 String compression = 1924 getAttribute(child, "compression"); 1925 1926 if (isISOLatin(value)) { 1927 if (compression.equals("zip")) { 1928 zTXt_keyword.add(keyword); 1930 zTXt_text.add(value); 1931 zTXt_compressionMethod.add(new Integer (0)); 1932 } else { 1933 tEXt_keyword.add(keyword); 1935 tEXt_text.add(value); 1936 } 1937 } else { 1938 int flag = compression.equals("zip") ? 1939 1 : 0; 1940 1941 iTXt_keyword.add(keyword); 1943 iTXt_compressionFlag.add(new Integer (flag)); 1944 iTXt_compressionMethod.add(new Integer (0)); 1945 iTXt_languageTag.add(language); 1946 iTXt_translatedKeyword.add(keyword); iTXt_text.add(value); 1948 } 1949 } 1950 child = child.getNextSibling(); 1951 } 1952 } 1967 1968 node = node.getNextSibling(); 1969 } 1970 } 1971 1972 public void reset() { 1974 IHDR_present = false; 1975 PLTE_present = false; 1976 bKGD_present = false; 1977 cHRM_present = false; 1978 gAMA_present = false; 1979 hIST_present = false; 1980 iCCP_present = false; 1981 iTXt_keyword = new ArrayList (); 1982 iTXt_compressionFlag = new ArrayList (); 1983 iTXt_compressionMethod = new ArrayList (); 1984 iTXt_languageTag = new ArrayList (); 1985 iTXt_translatedKeyword = new ArrayList (); 1986 iTXt_text = new ArrayList (); 1987 pHYs_present = false; 1988 sBIT_present = false; 1989 sPLT_present = false; 1990 sRGB_present = false; 1991 tEXt_keyword = new ArrayList (); 1992 tEXt_text = new ArrayList (); 1993 tIME_present = false; 1994 tRNS_present = false; 1995 zTXt_keyword = new ArrayList (); 1996 zTXt_compressionMethod = new ArrayList (); 1997 zTXt_text = new ArrayList (); 1998 unknownChunkType = new ArrayList (); 1999 unknownChunkData = new ArrayList (); 2000 } 2001} 2002 | Popular Tags |