1 18 package org.apache.batik.ext.awt.image.codec; 19 20 import java.awt.Color ; 21 import java.awt.Point ; 22 import java.awt.Transparency ; 23 import java.awt.color.ColorSpace ; 24 import java.awt.image.ColorModel ; 25 import java.awt.image.ComponentColorModel ; 26 import java.awt.image.DataBuffer ; 27 import java.awt.image.DataBufferByte ; 28 import java.awt.image.DataBufferUShort ; 29 import java.awt.image.IndexColorModel ; 30 import java.awt.image.Raster ; 31 import java.awt.image.RenderedImage ; 32 import java.awt.image.SampleModel ; 33 import java.awt.image.WritableRaster ; 34 import java.io.BufferedInputStream ; 35 import java.io.ByteArrayInputStream ; 36 import java.io.DataInputStream ; 37 import java.io.IOException ; 38 import java.io.InputStream ; 39 import java.io.SequenceInputStream ; 40 import java.util.Date ; 41 import java.util.GregorianCalendar ; 42 import java.util.TimeZone ; 43 import java.util.Vector ; 44 import java.util.zip.Inflater ; 45 import java.util.zip.InflaterInputStream ; 46 47 49 public class PNGImageDecoder extends ImageDecoderImpl { 50 51 public PNGImageDecoder(InputStream input, 52 PNGDecodeParam param) { 53 super(input, param); 54 } 55 56 public RenderedImage decodeAsRenderedImage(int page) throws IOException { 57 if (page != 0) { 58 throw new IOException (PropertyUtil.getString("PNGImageDecoder19")); 59 } 60 return new PNGImage(input, (PNGDecodeParam)param); 61 } 62 } 63 64 class PNGChunk { 65 int length; 66 int type; 67 byte[] data; 68 int crc; 69 70 String typeString; 71 72 public PNGChunk(int length, int type, byte[] data, int crc) { 73 this.length = length; 74 this.type = type; 75 this.data = data; 76 this.crc = crc; 77 78 typeString = new String (); 79 typeString += (char)(type >> 24); 80 typeString += (char)((type >> 16) & 0xff); 81 typeString += (char)((type >> 8) & 0xff); 82 typeString += (char)(type & 0xff); 83 } 84 85 public int getLength() { 86 return length; 87 } 88 89 public int getType() { 90 return type; 91 } 92 93 public String getTypeString() { 94 return typeString; 95 } 96 97 public byte[] getData() { 98 return data; 99 } 100 101 public byte getByte(int offset) { 102 return data[offset]; 103 } 104 105 public int getInt1(int offset) { 106 return data[offset] & 0xff; 107 } 108 109 public int getInt2(int offset) { 110 return ((data[offset] & 0xff) << 8) | 111 (data[offset + 1] & 0xff); 112 } 113 114 public int getInt4(int offset) { 115 return ((data[offset] & 0xff) << 24) | 116 ((data[offset + 1] & 0xff) << 16) | 117 ((data[offset + 2] & 0xff) << 8) | 118 (data[offset + 3] & 0xff); 119 } 120 121 public String getString4(int offset) { 122 String s = new String (); 123 s += (char)data[offset]; 124 s += (char)data[offset + 1]; 125 s += (char)data[offset + 2]; 126 s += (char)data[offset + 3]; 127 return s; 128 } 129 130 public boolean isType(String typeName) { 131 return typeString.equals(typeName); 132 } 133 } 134 135 141 class PNGImage extends SimpleRenderedImage { 142 143 public static final int PNG_COLOR_GRAY = 0; 144 public static final int PNG_COLOR_RGB = 2; 145 public static final int PNG_COLOR_PALETTE = 3; 146 public static final int PNG_COLOR_GRAY_ALPHA = 4; 147 public static final int PNG_COLOR_RGB_ALPHA = 6; 148 149 private static final String [] colorTypeNames = { 150 "Grayscale", "Error", "Truecolor", "Index", 151 "Grayscale with alpha", "Error", "Truecolor with alpha" 152 }; 153 154 public static final int PNG_FILTER_NONE = 0; 155 public static final int PNG_FILTER_SUB = 1; 156 public static final int PNG_FILTER_UP = 2; 157 public static final int PNG_FILTER_AVERAGE = 3; 158 public static final int PNG_FILTER_PAETH = 4; 159 160 private static final int RED_OFFSET = 2; 161 private static final int GREEN_OFFSET = 1; 162 private static final int BLUE_OFFSET = 0; 163 164 private int[][] bandOffsets = { 165 null, 166 { 0 }, { 0, 1 }, { 0, 1, 2 }, { 0, 1, 2, 3 } }; 171 172 private int bitDepth; 173 private int colorType; 174 175 private int compressionMethod; 176 private int filterMethod; 177 private int interlaceMethod; 178 179 private int paletteEntries; 180 private byte[] redPalette; 181 private byte[] greenPalette; 182 private byte[] bluePalette; 183 private byte[] alphaPalette; 184 185 private int bkgdRed; 186 private int bkgdGreen; 187 private int bkgdBlue; 188 189 private int grayTransparentAlpha; 190 private int redTransparentAlpha; 191 private int greenTransparentAlpha; 192 private int blueTransparentAlpha; 193 194 private int maxOpacity; 195 196 private int[] significantBits = null; 197 198 private boolean hasBackground = false; 199 200 202 private boolean suppressAlpha = false; 204 205 private boolean expandPalette = false; 207 208 private boolean output8BitGray = false; 210 211 private boolean outputHasAlphaPalette = false; 213 214 private boolean performGammaCorrection = false; 216 217 private boolean expandGrayAlpha = false; 219 220 private boolean generateEncodeParam = false; 222 223 private PNGDecodeParam decodeParam = null; 225 226 private PNGEncodeParam encodeParam = null; 228 229 private boolean emitProperties = true; 230 231 private float fileGamma = 45455/100000.0F; 232 233 private float userExponent = 1.0F; 234 235 private float displayExponent = 2.2F; 236 237 private float[] chromaticity = null; 238 239 private int sRGBRenderingIntent = -1; 240 241 private int postProcess = POST_NONE; 243 244 246 private static final int POST_NONE = 0; 248 249 private static final int POST_GAMMA = 1; 251 252 private static final int POST_GRAY_LUT = 2; 254 255 private static final int POST_GRAY_LUT_ADD_TRANS = 3; 257 258 private static final int POST_PALETTE_TO_RGB = 4; 260 261 private static final int POST_PALETTE_TO_RGBA = 5; 263 264 private static final int POST_ADD_GRAY_TRANS = 6; 266 267 private static final int POST_ADD_RGB_TRANS = 7; 269 270 private static final int POST_REMOVE_GRAY_TRANS = 8; 272 273 private static final int POST_REMOVE_RGB_TRANS = 9; 275 276 private static final int POST_EXP_MASK = 16; 278 279 private static final int POST_GRAY_ALPHA_EXP = 281 POST_NONE | POST_EXP_MASK; 282 283 private static final int POST_GAMMA_EXP = 285 POST_GAMMA | POST_EXP_MASK; 286 287 private static final int POST_GRAY_LUT_ADD_TRANS_EXP = 289 POST_GRAY_LUT_ADD_TRANS | POST_EXP_MASK; 290 291 private static final int POST_ADD_GRAY_TRANS_EXP = 293 POST_ADD_GRAY_TRANS | POST_EXP_MASK; 294 295 private Vector streamVec = new Vector (); 296 private DataInputStream dataStream; 297 298 private int bytesPerPixel; private int inputBands; 300 private int outputBands; 301 302 private int chunkIndex = 0; 304 305 private Vector textKeys = new Vector (); 306 private Vector textStrings = new Vector (); 307 308 private Vector ztextKeys = new Vector (); 309 private Vector ztextStrings = new Vector (); 310 311 private WritableRaster theTile; 312 313 private int[] gammaLut = null; 314 315 private void initGammaLut(int bits) { 316 double exp = (double)userExponent/(fileGamma*displayExponent); 317 int numSamples = 1 << bits; 318 int maxOutSample = (bits == 16) ? 65535 : 255; 319 320 gammaLut = new int[numSamples]; 321 for (int i = 0; i < numSamples; i++) { 322 double gbright = (double)i/(numSamples - 1); 323 double gamma = Math.pow(gbright, exp); 324 int igamma = (int)(gamma*maxOutSample + 0.5); 325 if (igamma > maxOutSample) { 326 igamma = maxOutSample; 327 } 328 gammaLut[i] = igamma; 329 } 330 } 331 332 private final byte[][] expandBits = { 333 null, 334 { (byte)0x00, (byte)0xff }, 335 { (byte)0x00, (byte)0x55, (byte)0xaa, (byte)0xff }, 336 null, 337 { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33, 338 (byte)0x44, (byte)0x55, (byte)0x66, (byte)0x77, 339 (byte)0x88, (byte)0x99, (byte)0xaa, (byte)0xbb, 340 (byte)0xcc, (byte)0xdd, (byte)0xee, (byte)0xff } 341 }; 342 343 private int[] grayLut = null; 344 345 private void initGrayLut(int bits) { 346 int len = 1 << bits; 347 grayLut = new int[len]; 348 349 if (performGammaCorrection) { 350 for (int i = 0; i < len; i++) { 351 grayLut[i] = gammaLut[i]; 352 } 353 } else { 354 for (int i = 0; i < len; i++) { 355 grayLut[i] = expandBits[bits][i]; 356 } 357 } 358 } 359 360 public PNGImage(InputStream stream, PNGDecodeParam decodeParam) 361 throws IOException { 362 363 if (!stream.markSupported()) { 364 stream = new BufferedInputStream (stream); 365 } 366 DataInputStream distream = new DataInputStream (stream); 367 368 if (decodeParam == null) { 369 decodeParam = new PNGDecodeParam(); 370 } 371 this.decodeParam = decodeParam; 372 373 this.suppressAlpha = decodeParam.getSuppressAlpha(); 375 this.expandPalette = decodeParam.getExpandPalette(); 376 this.output8BitGray = decodeParam.getOutput8BitGray(); 377 this.expandGrayAlpha = decodeParam.getExpandGrayAlpha(); 378 if (decodeParam.getPerformGammaCorrection()) { 379 this.userExponent = decodeParam.getUserExponent(); 380 this.displayExponent = decodeParam.getDisplayExponent(); 381 performGammaCorrection = true; 382 output8BitGray = true; 383 } 384 this.generateEncodeParam = decodeParam.getGenerateEncodeParam(); 385 386 if (emitProperties) { 387 properties.put("file_type", "PNG v. 1.0"); 388 } 389 390 try { 391 long magic = distream.readLong(); 392 if (magic != 0x89504e470d0a1a0aL) { 393 String msg = PropertyUtil.getString("PNGImageDecoder0"); 394 throw new RuntimeException (msg); 395 } 396 } catch (Exception e) { 397 e.printStackTrace(); 398 String msg = PropertyUtil.getString("PNGImageDecoder1"); 399 throw new RuntimeException (msg); 400 } 401 402 do { 403 try { 404 PNGChunk chunk; 405 406 String chunkType = getChunkType(distream); 407 if (chunkType.equals("IHDR")) { 408 chunk = readChunk(distream); 409 parse_IHDR_chunk(chunk); 410 } else if (chunkType.equals("PLTE")) { 411 chunk = readChunk(distream); 412 parse_PLTE_chunk(chunk); 413 } else if (chunkType.equals("IDAT")) { 414 chunk = readChunk(distream); 415 streamVec.add(new ByteArrayInputStream (chunk.getData())); 416 } else if (chunkType.equals("IEND")) { 417 chunk = readChunk(distream); 418 parse_IEND_chunk(chunk); 419 break; } else if (chunkType.equals("bKGD")) { 421 chunk = readChunk(distream); 422 parse_bKGD_chunk(chunk); 423 } else if (chunkType.equals("cHRM")) { 424 chunk = readChunk(distream); 425 parse_cHRM_chunk(chunk); 426 } else if (chunkType.equals("gAMA")) { 427 chunk = readChunk(distream); 428 parse_gAMA_chunk(chunk); 429 } else if (chunkType.equals("hIST")) { 430 chunk = readChunk(distream); 431 parse_hIST_chunk(chunk); 432 } else if (chunkType.equals("iCCP")) { 433 chunk = readChunk(distream); 434 parse_iCCP_chunk(chunk); 435 } else if (chunkType.equals("pHYs")) { 436 chunk = readChunk(distream); 437 parse_pHYs_chunk(chunk); 438 } else if (chunkType.equals("sBIT")) { 439 chunk = readChunk(distream); 440 parse_sBIT_chunk(chunk); 441 } else if (chunkType.equals("sRGB")) { 442 chunk = readChunk(distream); 443 parse_sRGB_chunk(chunk); 444 } else if (chunkType.equals("tEXt")) { 445 chunk = readChunk(distream); 446 parse_tEXt_chunk(chunk); 447 } else if (chunkType.equals("tIME")) { 448 chunk = readChunk(distream); 449 parse_tIME_chunk(chunk); 450 } else if (chunkType.equals("tRNS")) { 451 chunk = readChunk(distream); 452 parse_tRNS_chunk(chunk); 453 } else if (chunkType.equals("zTXt")) { 454 chunk = readChunk(distream); 455 parse_zTXt_chunk(chunk); 456 } else { 457 chunk = readChunk(distream); 458 460 String type = chunk.getTypeString(); 461 byte[] data = chunk.getData(); 462 if (encodeParam != null) { 463 encodeParam.addPrivateChunk(type, data); 464 } 465 if (emitProperties) { 466 String key = "chunk_" + chunkIndex++ + ":" + type; 467 properties.put(key.toLowerCase(), data); 468 } 469 } 470 } catch (Exception e) { 471 e.printStackTrace(); 472 String msg = PropertyUtil.getString("PNGImageDecoder2"); 473 throw new RuntimeException (msg); 474 } 475 } while (true); 476 477 479 if (significantBits == null) { 480 significantBits = new int[inputBands]; 481 for (int i = 0; i < inputBands; i++) { 482 significantBits[i] = bitDepth; 483 } 484 485 if (emitProperties) { 486 properties.put("significant_bits", significantBits); 487 } 488 } 489 } 490 491 private static String getChunkType(DataInputStream distream) { 492 try { 493 distream.mark(8); 494 distream.readInt(); 495 int type = distream.readInt(); 496 distream.reset(); 497 498 String typeString = new String (); 499 typeString += (char)(type >> 24); 500 typeString += (char)((type >> 16) & 0xff); 501 typeString += (char)((type >> 8) & 0xff); 502 typeString += (char)(type & 0xff); 503 return typeString; 504 } catch (Exception e) { 505 e.printStackTrace(); 506 return null; 507 } 508 } 509 510 private static PNGChunk readChunk(DataInputStream distream) { 511 try { 512 int length = distream.readInt(); 513 int type = distream.readInt(); 514 byte[] data = new byte[length]; 515 distream.readFully(data); 516 int crc = distream.readInt(); 517 518 return new PNGChunk(length, type, data, crc); 519 } catch (Exception e) { 520 e.printStackTrace(); 521 return null; 522 } 523 } 524 525 private void parse_IHDR_chunk(PNGChunk chunk) { 526 tileWidth = width = chunk.getInt4(0); 527 tileHeight = height = chunk.getInt4(4); 528 529 bitDepth = chunk.getInt1(8); 530 531 if ((bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) && 532 (bitDepth != 8) && (bitDepth != 16)) { 533 String msg = PropertyUtil.getString("PNGImageDecoder3"); 535 throw new RuntimeException (msg); 536 } 537 maxOpacity = (1 << bitDepth) - 1; 538 539 colorType = chunk.getInt1(9); 540 if ((colorType != PNG_COLOR_GRAY) && 541 (colorType != PNG_COLOR_RGB) && 542 (colorType != PNG_COLOR_PALETTE) && 543 (colorType != PNG_COLOR_GRAY_ALPHA) && 544 (colorType != PNG_COLOR_RGB_ALPHA)) { 545 System.out.println(PropertyUtil.getString("PNGImageDecoder4")); 546 } 547 548 if ((colorType == PNG_COLOR_RGB) && (bitDepth < 8)) { 549 String msg = PropertyUtil.getString("PNGImageDecoder5"); 551 throw new RuntimeException (msg); 552 } 553 554 if ((colorType == PNG_COLOR_PALETTE) && (bitDepth == 16)) { 555 String msg = PropertyUtil.getString("PNGImageDecoder6"); 557 throw new RuntimeException (msg); 558 } 559 560 if ((colorType == PNG_COLOR_GRAY_ALPHA) && (bitDepth < 8)) { 561 String msg = PropertyUtil.getString("PNGImageDecoder7"); 563 throw new RuntimeException (msg); 564 } 565 566 if ((colorType == PNG_COLOR_RGB_ALPHA) && (bitDepth < 8)) { 567 String msg = PropertyUtil.getString("PNGImageDecoder8"); 569 throw new RuntimeException (msg); 570 } 571 572 if (emitProperties) { 573 properties.put("color_type", colorTypeNames[colorType]); 574 } 575 576 if (generateEncodeParam) { 577 if (colorType == PNG_COLOR_PALETTE) { 578 encodeParam = new PNGEncodeParam.Palette(); 579 } else if (colorType == PNG_COLOR_GRAY || 580 colorType == PNG_COLOR_GRAY_ALPHA) { 581 encodeParam = new PNGEncodeParam.Gray(); 582 } else { 583 encodeParam = new PNGEncodeParam.RGB(); 584 } 585 decodeParam.setEncodeParam(encodeParam); 586 } 587 588 if (encodeParam != null) { 589 encodeParam.setBitDepth(bitDepth); 590 } 591 if (emitProperties) { 592 properties.put("bit_depth", new Integer (bitDepth)); 593 } 594 595 if (performGammaCorrection) { 596 float gamma = (1.0F/2.2F)*(displayExponent/userExponent); 598 if (encodeParam != null) { 599 encodeParam.setGamma(gamma); 600 } 601 if (emitProperties) { 602 properties.put("gamma", new Float (gamma)); 603 } 604 } 605 606 compressionMethod = chunk.getInt1(10); 607 if (compressionMethod != 0) { 608 String msg = PropertyUtil.getString("PNGImageDecoder9"); 610 throw new RuntimeException (msg); 611 } 612 613 filterMethod = chunk.getInt1(11); 614 if (filterMethod != 0) { 615 String msg = PropertyUtil.getString("PNGImageDecoder10"); 617 throw new RuntimeException (msg); 618 } 619 620 interlaceMethod = chunk.getInt1(12); 621 if (interlaceMethod == 0) { 622 if (encodeParam != null) { 623 encodeParam.setInterlacing(false); 624 } 625 if (emitProperties) { 626 properties.put("interlace_method", "None"); 627 } 628 } else if (interlaceMethod == 1) { 629 if (encodeParam != null) { 630 encodeParam.setInterlacing(true); 631 } 632 if (emitProperties) { 633 properties.put("interlace_method", "Adam7"); 634 } 635 } else { 636 String msg = PropertyUtil.getString("PNGImageDecoder11"); 638 throw new RuntimeException (msg); 639 } 640 641 bytesPerPixel = (bitDepth == 16) ? 2 : 1; 642 643 switch (colorType) { 644 case PNG_COLOR_GRAY: 645 inputBands = 1; 646 outputBands = 1; 647 648 if (output8BitGray && (bitDepth < 8)) { 649 postProcess = POST_GRAY_LUT; 650 } else if (performGammaCorrection) { 651 postProcess = POST_GAMMA; 652 } else { 653 postProcess = POST_NONE; 654 } 655 break; 656 657 case PNG_COLOR_RGB: 658 inputBands = 3; 659 bytesPerPixel *= 3; 660 outputBands = 3; 661 662 if (performGammaCorrection) { 663 postProcess = POST_GAMMA; 664 } else { 665 postProcess = POST_NONE; 666 } 667 break; 668 669 case PNG_COLOR_PALETTE: 670 inputBands = 1; 671 bytesPerPixel = 1; 672 outputBands = expandPalette ? 3 : 1; 673 674 if (expandPalette) { 675 postProcess = POST_PALETTE_TO_RGB; 676 } else { 677 postProcess = POST_NONE; 678 } 679 break; 680 681 case PNG_COLOR_GRAY_ALPHA: 682 inputBands = 2; 683 bytesPerPixel *= 2; 684 685 if (suppressAlpha) { 686 outputBands = 1; 687 postProcess = POST_REMOVE_GRAY_TRANS; 688 } else { 689 if (performGammaCorrection) { 690 postProcess = POST_GAMMA; 691 } else { 692 postProcess = POST_NONE; 693 } 694 if (expandGrayAlpha) { 695 postProcess |= POST_EXP_MASK; 696 outputBands = 4; 697 } else { 698 outputBands = 2; 699 } 700 } 701 break; 702 703 case PNG_COLOR_RGB_ALPHA: 704 inputBands = 4; 705 bytesPerPixel *= 4; 706 outputBands = (!suppressAlpha) ? 4 : 3; 707 708 if (suppressAlpha) { 709 postProcess = POST_REMOVE_RGB_TRANS; 710 } else if (performGammaCorrection) { 711 postProcess = POST_GAMMA; 712 } else { 713 postProcess = POST_NONE; 714 } 715 break; 716 } 717 } 718 719 private void parse_IEND_chunk(PNGChunk chunk) throws Exception { 720 int textLen = textKeys.size(); 722 String [] textArray = new String [2*textLen]; 723 for (int i = 0; i < textLen; i++) { 724 String key = (String )textKeys.elementAt(i); 725 String val = (String )textStrings.elementAt(i); 726 textArray[2*i] = key; 727 textArray[2*i + 1] = val; 728 if (emitProperties) { 729 String uniqueKey = "text_" + i + ":" + key; 730 properties.put(uniqueKey.toLowerCase(), val); 731 } 732 } 733 if (encodeParam != null) { 734 encodeParam.setText(textArray); 735 } 736 737 int ztextLen = ztextKeys.size(); 739 String [] ztextArray = new String [2*ztextLen]; 740 for (int i = 0; i < ztextLen; i++) { 741 String key = (String )ztextKeys.elementAt(i); 742 String val = (String )ztextStrings.elementAt(i); 743 ztextArray[2*i] = key; 744 ztextArray[2*i + 1] = val; 745 if (emitProperties) { 746 String uniqueKey = "ztext_" + i + ":" + key; 747 properties.put(uniqueKey.toLowerCase(), val); 748 } 749 } 750 if (encodeParam != null) { 751 encodeParam.setCompressedText(ztextArray); 752 } 753 754 InputStream seqStream = 756 new SequenceInputStream (streamVec.elements()); 757 InputStream infStream = 758 new InflaterInputStream (seqStream, new Inflater ()); 759 dataStream = new DataInputStream (infStream); 760 761 int depth = bitDepth; 763 if ((colorType == PNG_COLOR_GRAY) && 764 (bitDepth < 8) && output8BitGray) { 765 depth = 8; 766 } 767 if ((colorType == PNG_COLOR_PALETTE) && expandPalette) { 768 depth = 8; 769 } 770 int bytesPerRow = (outputBands*width*depth + 7)/8; 771 int scanlineStride = 772 (depth == 16) ? (bytesPerRow/2) : bytesPerRow; 773 774 theTile = createRaster(width, height, outputBands, 775 scanlineStride, 776 depth); 777 778 if (performGammaCorrection && (gammaLut == null)) { 779 initGammaLut(bitDepth); 780 } 781 if ((postProcess == POST_GRAY_LUT) || 782 (postProcess == POST_GRAY_LUT_ADD_TRANS) || 783 (postProcess == POST_GRAY_LUT_ADD_TRANS_EXP)) { 784 initGrayLut(bitDepth); 785 } 786 787 decodeImage(interlaceMethod == 1); 788 sampleModel = theTile.getSampleModel(); 789 790 if ((colorType == PNG_COLOR_PALETTE) && !expandPalette) { 791 if (outputHasAlphaPalette) { 792 colorModel = new IndexColorModel (bitDepth, 793 paletteEntries, 794 redPalette, 795 greenPalette, 796 bluePalette, 797 alphaPalette); 798 } else { 799 colorModel = new IndexColorModel (bitDepth, 800 paletteEntries, 801 redPalette, 802 greenPalette, 803 bluePalette); 804 } 805 } else if ((colorType == PNG_COLOR_GRAY) && 806 (bitDepth < 8) && !output8BitGray) { 807 byte[] palette = expandBits[bitDepth]; 808 colorModel = new IndexColorModel (bitDepth, 809 palette.length, 810 palette, 811 palette, 812 palette); 813 } else { 814 colorModel = 815 createComponentColorModel(sampleModel); 816 } 817 } 818 819 private static final int[] GrayBits8 = { 8 }; 820 private static final ComponentColorModel colorModelGray8 = 821 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 822 GrayBits8, false, false, 823 Transparency.OPAQUE, 824 DataBuffer.TYPE_BYTE); 825 826 private static final int[] GrayAlphaBits8 = { 8, 8 }; 827 private static final ComponentColorModel colorModelGrayAlpha8 = 828 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 829 GrayAlphaBits8, true, false, 830 Transparency.TRANSLUCENT, 831 DataBuffer.TYPE_BYTE); 832 833 private static final int[] GrayBits16 = { 16 }; 834 private static final ComponentColorModel colorModelGray16 = 835 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 836 GrayBits16, false, false, 837 Transparency.OPAQUE, 838 DataBuffer.TYPE_USHORT); 839 840 private static final int[] GrayAlphaBits16 = { 16, 16 }; 841 private static final ComponentColorModel colorModelGrayAlpha16 = 842 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 843 GrayAlphaBits16, true, false, 844 Transparency.TRANSLUCENT, 845 DataBuffer.TYPE_USHORT); 846 847 private static final int[] GrayBits32 = { 32 }; 848 private static final ComponentColorModel colorModelGray32 = 849 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 850 GrayBits32, false, false, 851 Transparency.OPAQUE, 852 DataBuffer.TYPE_INT); 853 854 private static final int[] GrayAlphaBits32 = { 32, 32 }; 855 private static final ComponentColorModel colorModelGrayAlpha32 = 856 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_GRAY), 857 GrayAlphaBits32, true, false, 858 Transparency.TRANSLUCENT, 859 DataBuffer.TYPE_INT); 860 861 private static final int[] RGBBits8 = { 8, 8, 8 }; 862 private static final ComponentColorModel colorModelRGB8 = 863 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 864 RGBBits8, false, false, 865 Transparency.OPAQUE, 866 DataBuffer.TYPE_BYTE); 867 868 private static final int[] RGBABits8 = { 8, 8, 8, 8 }; 869 private static final ComponentColorModel colorModelRGBA8 = 870 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 871 RGBABits8, true, false, 872 Transparency.TRANSLUCENT, 873 DataBuffer.TYPE_BYTE); 874 875 private static final int[] RGBBits16 = { 16, 16, 16 }; 876 private static final ComponentColorModel colorModelRGB16 = 877 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 878 RGBBits16, false, false, 879 Transparency.OPAQUE, 880 DataBuffer.TYPE_USHORT); 881 882 private static final int[] RGBABits16 = { 16, 16, 16, 16 }; 883 private static final ComponentColorModel colorModelRGBA16 = 884 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 885 RGBABits16, true, false, 886 Transparency.TRANSLUCENT, 887 DataBuffer.TYPE_USHORT); 888 889 private static final int[] RGBBits32 = { 32, 32, 32 }; 890 private static final ComponentColorModel colorModelRGB32 = 891 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 892 RGBBits32, false, false, 893 Transparency.OPAQUE, 894 DataBuffer.TYPE_INT); 895 896 private static final int[] RGBABits32 = { 32, 32, 32, 32 }; 897 private static final ComponentColorModel colorModelRGBA32 = 898 new ComponentColorModel (ColorSpace.getInstance(ColorSpace.CS_sRGB), 899 RGBABits32, true, false, 900 Transparency.TRANSLUCENT, 901 DataBuffer.TYPE_INT); 902 912 public static ColorModel createComponentColorModel(SampleModel sm) { 913 int type = sm.getDataType(); 914 int bands = sm.getNumBands(); 915 ComponentColorModel cm = null; 916 917 if (type == DataBuffer.TYPE_BYTE) { 918 switch (bands) { 919 case 1: 920 cm = colorModelGray8; 921 break; 922 case 2: 923 cm = colorModelGrayAlpha8; 924 break; 925 case 3: 926 cm = colorModelRGB8; 927 break; 928 case 4: 929 cm = colorModelRGBA8; 930 break; 931 } 932 } else if (type == DataBuffer.TYPE_USHORT) { 933 switch (bands) { 934 case 1: 935 cm = colorModelGray16; 936 break; 937 case 2: 938 cm = colorModelGrayAlpha16; 939 break; 940 case 3: 941 cm = colorModelRGB16; 942 break; 943 case 4: 944 cm = colorModelRGBA16; 945 break; 946 } 947 } else if (type == DataBuffer.TYPE_INT) { 948 switch (bands) { 949 case 1: 950 cm = colorModelGray32; 951 break; 952 case 2: 953 cm = colorModelGrayAlpha32; 954 break; 955 case 3: 956 cm = colorModelRGB32; 957 break; 958 case 4: 959 cm = colorModelRGBA32; 960 break; 961 } 962 } 963 964 return cm; 965 } 966 967 private void parse_PLTE_chunk(PNGChunk chunk) { 968 paletteEntries = chunk.getLength()/3; 969 redPalette = new byte[paletteEntries]; 970 greenPalette = new byte[paletteEntries]; 971 bluePalette = new byte[paletteEntries]; 972 973 int pltIndex = 0; 974 975 if (performGammaCorrection) { 977 if (gammaLut == null) { 978 initGammaLut(bitDepth == 16 ? 16 : 8); 979 } 980 981 for (int i = 0; i < paletteEntries; i++) { 982 byte r = chunk.getByte(pltIndex++); 983 byte g = chunk.getByte(pltIndex++); 984 byte b = chunk.getByte(pltIndex++); 985 986 redPalette[i] = (byte)gammaLut[r & 0xff]; 987 greenPalette[i] = (byte)gammaLut[g & 0xff]; 988 bluePalette[i] = (byte)gammaLut[b & 0xff]; 989 } 990 } else { 991 for (int i = 0; i < paletteEntries; i++) { 992 redPalette[i] = chunk.getByte(pltIndex++); 993 greenPalette[i] = chunk.getByte(pltIndex++); 994 bluePalette[i] = chunk.getByte(pltIndex++); 995 } 996 } 997 } 998 999 private void parse_bKGD_chunk(PNGChunk chunk) { 1000 hasBackground = true; 1001 1002 switch (colorType) { 1003 case PNG_COLOR_PALETTE: 1004 int bkgdIndex = chunk.getByte(0) & 0xff; 1005 1006 bkgdRed = redPalette[bkgdIndex] & 0xff; 1007 bkgdGreen = greenPalette[bkgdIndex] & 0xff; 1008 bkgdBlue = bluePalette[bkgdIndex] & 0xff; 1009 1010 if (encodeParam != null) { 1011 ((PNGEncodeParam.Palette)encodeParam). 1012 setBackgroundPaletteIndex(bkgdIndex); 1013 } 1014 break; 1015 case PNG_COLOR_GRAY: case PNG_COLOR_GRAY_ALPHA: 1016 int bkgdGray = chunk.getInt2(0); 1017 bkgdRed = bkgdGreen = bkgdBlue = bkgdGray; 1018 1019 if (encodeParam != null) { 1020 ((PNGEncodeParam.Gray)encodeParam). 1021 setBackgroundGray(bkgdGray); 1022 } 1023 break; 1024 case PNG_COLOR_RGB: case PNG_COLOR_RGB_ALPHA: 1025 bkgdRed = chunk.getInt2(0); 1026 bkgdGreen = chunk.getInt2(2); 1027 bkgdBlue = chunk.getInt2(4); 1028 1029 int[] bkgdRGB = new int[3]; 1030 bkgdRGB[0] = bkgdRed; 1031 bkgdRGB[1] = bkgdGreen; 1032 bkgdRGB[2] = bkgdBlue; 1033 if (encodeParam != null) { 1034 ((PNGEncodeParam.RGB)encodeParam). 1035 setBackgroundRGB(bkgdRGB); 1036 } 1037 break; 1038 } 1039 1040 int r = 0, g = 0, b = 0; 1041 if (bitDepth < 8) { 1042 r = expandBits[bitDepth][bkgdRed]; 1043 g = expandBits[bitDepth][bkgdGreen]; 1044 b = expandBits[bitDepth][bkgdBlue]; 1045 } else if (bitDepth == 8) { 1046 r = bkgdRed; 1047 g = bkgdGreen; 1048 b = bkgdBlue; 1049 } else if (bitDepth == 16) { 1050 r = bkgdRed >> 8; 1051 g = bkgdGreen >> 8; 1052 b = bkgdBlue >> 8; 1053 } 1054 if (emitProperties) { 1055 properties.put("background_color", new Color (r, g, b)); 1056 } 1057 } 1058 1059 private void parse_cHRM_chunk(PNGChunk chunk) { 1060 if (sRGBRenderingIntent != -1) { 1062 return; 1063 } 1064 1065 chromaticity = new float[8]; 1066 chromaticity[0] = chunk.getInt4(0)/100000.0F; 1067 chromaticity[1] = chunk.getInt4(4)/100000.0F; 1068 chromaticity[2] = chunk.getInt4(8)/100000.0F; 1069 chromaticity[3] = chunk.getInt4(12)/100000.0F; 1070 chromaticity[4] = chunk.getInt4(16)/100000.0F; 1071 chromaticity[5] = chunk.getInt4(20)/100000.0F; 1072 chromaticity[6] = chunk.getInt4(24)/100000.0F; 1073 chromaticity[7] = chunk.getInt4(28)/100000.0F; 1074 1075 if (encodeParam != null) { 1076 encodeParam.setChromaticity(chromaticity); 1077 } 1078 if (emitProperties) { 1079 properties.put("white_point_x", new Float (chromaticity[0])); 1080 properties.put("white_point_y", new Float (chromaticity[1])); 1081 properties.put("red_x", new Float (chromaticity[2])); 1082 properties.put("red_y", new Float (chromaticity[3])); 1083 properties.put("green_x", new Float (chromaticity[4])); 1084 properties.put("green_y", new Float (chromaticity[5])); 1085 properties.put("blue_x", new Float (chromaticity[6])); 1086 properties.put("blue_y", new Float (chromaticity[7])); 1087 } 1088 } 1089 1090 private void parse_gAMA_chunk(PNGChunk chunk) { 1091 if (sRGBRenderingIntent != -1) { 1093 return; 1094 } 1095 1096 fileGamma = chunk.getInt4(0)/100000.0F; 1097 1098 float exp = 1099 performGammaCorrection ? displayExponent/userExponent : 1.0F; 1100 if (encodeParam != null) { 1101 encodeParam.setGamma(fileGamma*exp); 1102 } 1103 if (emitProperties) { 1104 properties.put("gamma", new Float (fileGamma*exp)); 1105 } 1106 } 1107 1108 private void parse_hIST_chunk(PNGChunk chunk) { 1109 if (redPalette == null) { 1110 String msg = PropertyUtil.getString("PNGImageDecoder18"); 1111 throw new RuntimeException (msg); 1112 } 1113 1114 int length = redPalette.length; 1115 int[] hist = new int[length]; 1116 for (int i = 0; i < length; i++) { 1117 hist[i] = chunk.getInt2(2*i); 1118 } 1119 1120 if (encodeParam != null) { 1121 encodeParam.setPaletteHistogram(hist); 1122 } 1123 } 1124 1125 private void parse_iCCP_chunk(PNGChunk chunk) { 1126 String name = new String (); 1127 byte b; 1128 1129 int textIndex = 0; 1130 while ((b = chunk.getByte(textIndex++)) != 0) { 1131 name += (char)b; 1132 } 1133 } 1134 1135 private void parse_pHYs_chunk(PNGChunk chunk) { 1136 int xPixelsPerUnit = chunk.getInt4(0); 1137 int yPixelsPerUnit = chunk.getInt4(4); 1138 int unitSpecifier = chunk.getInt1(8); 1139 1140 if (encodeParam != null) { 1141 encodeParam.setPhysicalDimension(xPixelsPerUnit, 1142 yPixelsPerUnit, 1143 unitSpecifier); 1144 } 1145 if (emitProperties) { 1146 properties.put("x_pixels_per_unit", new Integer (xPixelsPerUnit)); 1147 properties.put("y_pixels_per_unit", new Integer (yPixelsPerUnit)); 1148 properties.put("pixel_aspect_ratio", 1149 new Float ((float)xPixelsPerUnit/yPixelsPerUnit)); 1150 if (unitSpecifier == 1) { 1151 properties.put("pixel_units", "Meters"); 1152 } else if (unitSpecifier != 0) { 1153 String msg = PropertyUtil.getString("PNGImageDecoder12"); 1155 throw new RuntimeException (msg); 1156 } 1157 } 1158 } 1159 1160 private void parse_sBIT_chunk(PNGChunk chunk) { 1161 if (colorType == PNG_COLOR_PALETTE) { 1162 significantBits = new int[3]; 1163 } else { 1164 significantBits = new int[inputBands]; 1165 } 1166 for (int i = 0; i < significantBits.length; i++) { 1167 int bits = chunk.getByte(i); 1168 int depth = (colorType == PNG_COLOR_PALETTE) ? 8 : bitDepth; 1169 if (bits <= 0 || bits > depth) { 1170 String msg = PropertyUtil.getString("PNGImageDecoder13"); 1173 throw new RuntimeException (msg); 1174 } 1175 significantBits[i] = bits; 1176 } 1177 1178 if (encodeParam != null) { 1179 encodeParam.setSignificantBits(significantBits); 1180 } 1181 if (emitProperties) { 1182 properties.put("significant_bits", significantBits); 1183 } 1184 } 1185 1186 private void parse_sRGB_chunk(PNGChunk chunk) { 1187 sRGBRenderingIntent = chunk.getByte(0); 1188 1189 fileGamma = 45455/100000.0F; 1192 1193 chromaticity = new float[8]; 1194 chromaticity[0] = 31270/10000.0F; 1195 chromaticity[1] = 32900/10000.0F; 1196 chromaticity[2] = 64000/10000.0F; 1197 chromaticity[3] = 33000/10000.0F; 1198 chromaticity[4] = 30000/10000.0F; 1199 chromaticity[5] = 60000/10000.0F; 1200 chromaticity[6] = 15000/10000.0F; 1201 chromaticity[7] = 6000/10000.0F; 1202 1203 if (performGammaCorrection) { 1204 float gamma = fileGamma*(displayExponent/userExponent); 1206 if (encodeParam != null) { 1207 encodeParam.setGamma(gamma); 1208 encodeParam.setChromaticity(chromaticity); 1209 } 1210 if (emitProperties) { 1211 properties.put("gamma", new Float (gamma)); 1212 properties.put("white_point_x", new Float (chromaticity[0])); 1213 properties.put("white_point_y", new Float (chromaticity[1])); 1214 properties.put("red_x", new Float (chromaticity[2])); 1215 properties.put("red_y", new Float (chromaticity[3])); 1216 properties.put("green_x", new Float (chromaticity[4])); 1217 properties.put("green_y", new Float (chromaticity[5])); 1218 properties.put("blue_x", new Float (chromaticity[6])); 1219 properties.put("blue_y", new Float (chromaticity[7])); 1220 } 1221 } 1222 } 1223 1224 private void parse_tEXt_chunk(PNGChunk chunk) { 1225 String key = new String (); 1226 String value = new String (); 1227 byte b; 1228 1229 int textIndex = 0; 1230 while ((b = chunk.getByte(textIndex++)) != 0) { 1231 key += (char)b; 1232 } 1233 1234 for (int i = textIndex; i < chunk.getLength(); i++) { 1235 value += (char)chunk.getByte(i); 1236 } 1237 1238 textKeys.add(key); 1239 textStrings.add(value); 1240 } 1241 1242 private void parse_tIME_chunk(PNGChunk chunk) { 1243 int year = chunk.getInt2(0); 1244 int month = chunk.getInt1(2) - 1; 1245 int day = chunk.getInt1(3); 1246 int hour = chunk.getInt1(4); 1247 int minute = chunk.getInt1(5); 1248 int second = chunk.getInt1(6); 1249 1250 TimeZone gmt = TimeZone.getTimeZone("GMT"); 1251 1252 GregorianCalendar cal = new GregorianCalendar (gmt); 1253 cal.set(year, month, day, 1254 hour, minute, second); 1255 Date date = cal.getTime(); 1256 1257 if (encodeParam != null) { 1258 encodeParam.setModificationTime(date); 1259 } 1260 if (emitProperties) { 1261 properties.put("timestamp", date); 1262 } 1263 } 1264 1265 private void parse_tRNS_chunk(PNGChunk chunk) { 1266 if (colorType == PNG_COLOR_PALETTE) { 1267 int entries = chunk.getLength(); 1268 if (entries > paletteEntries) { 1269 String msg = PropertyUtil.getString("PNGImageDecoder14"); 1271 throw new RuntimeException (msg); 1272 } 1273 1274 alphaPalette = new byte[paletteEntries]; 1276 for (int i = 0; i < entries; i++) { 1277 alphaPalette[i] = chunk.getByte(i); 1278 } 1279 1280 for (int i = entries; i < paletteEntries; i++) { 1282 alphaPalette[i] = (byte)255; 1283 } 1284 1285 if (!suppressAlpha) { 1286 if (expandPalette) { 1287 postProcess = POST_PALETTE_TO_RGBA; 1288 outputBands = 4; 1289 } else { 1290 outputHasAlphaPalette = true; 1291 } 1292 } 1293 } else if (colorType == PNG_COLOR_GRAY) { 1294 grayTransparentAlpha = chunk.getInt2(0); 1295 1296 if (!suppressAlpha) { 1297 if (bitDepth < 8) { 1298 output8BitGray = true; 1299 maxOpacity = 255; 1300 postProcess = POST_GRAY_LUT_ADD_TRANS; 1301 } else { 1302 postProcess = POST_ADD_GRAY_TRANS; 1303 } 1304 1305 if (expandGrayAlpha) { 1306 outputBands = 4; 1307 postProcess |= POST_EXP_MASK; 1308 } else { 1309 outputBands = 2; 1310 } 1311 1312 if (encodeParam != null) { 1313 ((PNGEncodeParam.Gray)encodeParam). 1314 setTransparentGray(grayTransparentAlpha); 1315 } 1316 } 1317 } else if (colorType == PNG_COLOR_RGB) { 1318 redTransparentAlpha = chunk.getInt2(0); 1319 greenTransparentAlpha = chunk.getInt2(2); 1320 blueTransparentAlpha = chunk.getInt2(4); 1321 1322 if (!suppressAlpha) { 1323 outputBands = 4; 1324 postProcess = POST_ADD_RGB_TRANS; 1325 1326 if (encodeParam != null) { 1327 int[] rgbTrans = new int[3]; 1328 rgbTrans[0] = redTransparentAlpha; 1329 rgbTrans[1] = greenTransparentAlpha; 1330 rgbTrans[2] = blueTransparentAlpha; 1331 ((PNGEncodeParam.RGB)encodeParam). 1332 setTransparentRGB(rgbTrans); 1333 } 1334 } 1335 } else if (colorType == PNG_COLOR_GRAY_ALPHA || 1336 colorType == PNG_COLOR_RGB_ALPHA) { 1337 String msg = PropertyUtil.getString("PNGImageDecoder15"); 1339 throw new RuntimeException (msg); 1340 } 1341 } 1342 1343 private void parse_zTXt_chunk(PNGChunk chunk) { 1344 String key = new String (); 1345 String value = new String (); 1346 byte b; 1347 1348 int textIndex = 0; 1349 while ((b = chunk.getByte(textIndex++)) != 0) { 1350 key += (char)b; 1351 } 1352 chunk.getByte(textIndex++); 1353 1354 try { 1355 int length = chunk.getLength() - textIndex; 1356 byte[] data = chunk.getData(); 1357 InputStream cis = 1358 new ByteArrayInputStream (data, textIndex, length); 1359 InputStream iis = new InflaterInputStream (cis); 1360 1361 int c; 1362 while ((c = iis.read()) != -1) { 1363 value += (char)c; 1364 } 1365 1366 ztextKeys.add(key); 1367 ztextStrings.add(value); 1368 } catch (Exception e) { 1369 e.printStackTrace(); 1370 } 1371 } 1372 1373 private WritableRaster createRaster(int width, int height, int bands, 1374 int scanlineStride, 1375 int bitDepth) { 1376 1377 DataBuffer dataBuffer; 1378 WritableRaster ras = null; 1379 Point origin = new Point (0, 0); 1380 if ((bitDepth < 8) && (bands == 1)) { 1381 dataBuffer = new DataBufferByte (height*scanlineStride); 1382 ras = Raster.createPackedRaster(dataBuffer, 1383 width, height, 1384 bitDepth, 1385 origin); 1386 } else if (bitDepth <= 8) { 1387 dataBuffer = new DataBufferByte (height*scanlineStride); 1388 ras = Raster.createInterleavedRaster(dataBuffer, 1389 width, height, 1390 scanlineStride, 1391 bands, 1392 bandOffsets[bands], 1393 origin); 1394 } else { 1395 dataBuffer = new DataBufferUShort (height*scanlineStride); 1396 ras = Raster.createInterleavedRaster(dataBuffer, 1397 width, height, 1398 scanlineStride, 1399 bands, 1400 bandOffsets[bands], 1401 origin); 1402 } 1403 1404 return ras; 1405 } 1406 1407 1409 private static void decodeSubFilter(byte[] curr, int count, int bpp) { 1410 for (int i = bpp; i < count; i++) { 1411 int val; 1412 1413 val = curr[i] & 0xff; 1414 val += curr[i - bpp] & 0xff; 1415 1416 curr[i] = (byte)val; 1417 } 1418 } 1419 1420 private static void decodeUpFilter(byte[] curr, byte[] prev, 1421 int count) { 1422 for (int i = 0; i < count; i++) { 1423 int raw = curr[i] & 0xff; 1424 int prior = prev[i] & 0xff; 1425 1426 curr[i] = (byte)(raw + prior); 1427 } 1428 } 1429 1430 private static void decodeAverageFilter(byte[] curr, byte[] prev, 1431 int count, int bpp) { 1432 int raw, priorPixel, priorRow; 1433 1434 for (int i = 0; i < bpp; i++) { 1435 raw = curr[i] & 0xff; 1436 priorRow = prev[i] & 0xff; 1437 1438 curr[i] = (byte)(raw + priorRow/2); 1439 } 1440 1441 for (int i = bpp; i < count; i++) { 1442 raw = curr[i] & 0xff; 1443 priorPixel = curr[i - bpp] & 0xff; 1444 priorRow = prev[i] & 0xff; 1445 1446 curr[i] = (byte)(raw + (priorPixel + priorRow)/2); 1447 } 1448 } 1449 1450 private static int paethPredictor(int a, int b, int c) { 1451 int p = a + b - c; 1452 int pa = Math.abs(p - a); 1453 int pb = Math.abs(p - b); 1454 int pc = Math.abs(p - c); 1455 1456 if ((pa <= pb) && (pa <= pc)) { 1457 return a; 1458 } else if (pb <= pc) { 1459 return b; 1460 } else { 1461 return c; 1462 } 1463 } 1464 1465 private static void decodePaethFilter(byte[] curr, byte[] prev, 1466 int count, int bpp) { 1467 int raw, priorPixel, priorRow, priorRowPixel; 1468 1469 for (int i = 0; i < bpp; i++) { 1470 raw = curr[i] & 0xff; 1471 priorRow = prev[i] & 0xff; 1472 1473 curr[i] = (byte)(raw + priorRow); 1474 } 1475 1476 for (int i = bpp; i < count; i++) { 1477 raw = curr[i] & 0xff; 1478 priorPixel = curr[i - bpp] & 0xff; 1479 priorRow = prev[i] & 0xff; 1480 priorRowPixel = prev[i - bpp] & 0xff; 1481 1482 curr[i] = (byte)(raw + paethPredictor(priorPixel, 1483 priorRow, 1484 priorRowPixel)); 1485 } 1486 } 1487 1488 private void processPixels(int process, 1489 Raster src, WritableRaster dst, 1490 int xOffset, int step, int y, int width) { 1491 int srcX, dstX; 1492 1493 int[] ps = src.getPixel(0, 0, (int[])null); 1495 int[] pd = dst.getPixel(0, 0, (int[])null); 1496 1497 dstX = xOffset; 1498 switch (process) { 1499 case POST_NONE: 1500 for (srcX = 0; srcX < width; srcX++) { 1501 src.getPixel(srcX, 0, ps); 1502 dst.setPixel(dstX, y, ps); 1503 dstX += step; 1504 } 1505 break; 1506 1507 case POST_GAMMA: 1508 for (srcX = 0; srcX < width; srcX++) { 1509 src.getPixel(srcX, 0, ps); 1510 1511 for (int i = 0; i < inputBands; i++) { 1512 int x = ps[i]; 1513 ps[i] = gammaLut[x]; 1514 } 1515 1516 dst.setPixel(dstX, y, ps); 1517 dstX += step; 1518 } 1519 break; 1520 1521 case POST_GRAY_LUT: 1522 for (srcX = 0; srcX < width; srcX++) { 1523 src.getPixel(srcX, 0, ps); 1524 1525 pd[0] = grayLut[ps[0]]; 1526 1527 dst.setPixel(dstX, y, pd); 1528 dstX += step; 1529 } 1530 break; 1531 1532 case POST_GRAY_LUT_ADD_TRANS: 1533 for (srcX = 0; srcX < width; srcX++) { 1534 src.getPixel(srcX, 0, ps); 1535 1536 int val = ps[0]; 1537 pd[0] = grayLut[val]; 1538 if (val == grayTransparentAlpha) { 1539 pd[1] = 0; 1540 } else { 1541 pd[1] = maxOpacity; 1542 } 1543 1544 dst.setPixel(dstX, y, pd); 1545 dstX += step; 1546 } 1547 break; 1548 1549 case POST_PALETTE_TO_RGB: 1550 for (srcX = 0; srcX < width; srcX++) { 1551 src.getPixel(srcX, 0, ps); 1552 1553 int val = ps[0]; 1554 pd[0] = redPalette[val]; 1555 pd[1] = greenPalette[val]; 1556 pd[2] = bluePalette[val]; 1557 1558 dst.setPixel(dstX, y, pd); 1559 dstX += step; 1560 } 1561 break; 1562 1563 case POST_PALETTE_TO_RGBA: 1564 for (srcX = 0; srcX < width; srcX++) { 1565 src.getPixel(srcX, 0, ps); 1566 1567 int val = ps[0]; 1568 pd[0] = redPalette[val]; 1569 pd[1] = greenPalette[val]; 1570 pd[2] = bluePalette[val]; 1571 pd[3] = alphaPalette[val]; 1572 1573 dst.setPixel(dstX, y, pd); 1574 dstX += step; 1575 } 1576 break; 1577 1578 case POST_ADD_GRAY_TRANS: 1579 for (srcX = 0; srcX < width; srcX++) { 1580 src.getPixel(srcX, 0, ps); 1581 1582 int val = ps[0]; 1583 if (performGammaCorrection) { 1584 val = gammaLut[val]; 1585 } 1586 pd[0] = val; 1587 if (val == grayTransparentAlpha) { 1588 pd[1] = 0; 1589 } else { 1590 pd[1] = maxOpacity; 1591 } 1592 1593 dst.setPixel(dstX, y, pd); 1594 dstX += step; 1595 } 1596 break; 1597 1598 case POST_ADD_RGB_TRANS: 1599 for (srcX = 0; srcX < width; srcX++) { 1600 src.getPixel(srcX, 0, ps); 1601 1602 int r = ps[0]; 1603 int g = ps[1]; 1604 int b = ps[2]; 1605 if (performGammaCorrection) { 1606 pd[0] = gammaLut[r]; 1607 pd[1] = gammaLut[g]; 1608 pd[2] = gammaLut[b]; 1609 } else { 1610 pd[0] = r; 1611 pd[1] = g; 1612 pd[2] = b; 1613 } 1614 if ((r == redTransparentAlpha) && 1615 (g == greenTransparentAlpha) && 1616 (b == blueTransparentAlpha)) { 1617 pd[3] = 0; 1618 } else { 1619 pd[3] = maxOpacity; 1620 } 1621 1622 dst.setPixel(dstX, y, pd); 1623 dstX += step; 1624 } 1625 break; 1626 1627 case POST_REMOVE_GRAY_TRANS: 1628 for (srcX = 0; srcX < width; srcX++) { 1629 src.getPixel(srcX, 0, ps); 1630 1631 int g = ps[0]; 1632 if (performGammaCorrection) { 1633 pd[0] = gammaLut[g]; 1634 } else { 1635 pd[0] = g; 1636 } 1637 1638 dst.setPixel(dstX, y, pd); 1639 dstX += step; 1640 } 1641 break; 1642 1643 case POST_REMOVE_RGB_TRANS: 1644 for (srcX = 0; srcX < width; srcX++) { 1645 src.getPixel(srcX, 0, ps); 1646 1647 int r = ps[0]; 1648 int g = ps[1]; 1649 int b = ps[2]; 1650 if (performGammaCorrection) { 1651 pd[0] = gammaLut[r]; 1652 pd[1] = gammaLut[g]; 1653 pd[2] = gammaLut[b]; 1654 } else { 1655 pd[0] = r; 1656 pd[1] = g; 1657 pd[2] = b; 1658 } 1659 1660 dst.setPixel(dstX, y, pd); 1661 dstX += step; 1662 } 1663 break; 1664 1665 case POST_GAMMA_EXP: 1666 for (srcX = 0; srcX < width; srcX++) { 1667 src.getPixel(srcX, 0, ps); 1668 1669 int val = ps[0]; 1670 int alpha = ps[1]; 1671 int gamma = gammaLut[val]; 1672 pd[0] = gamma; 1673 pd[1] = gamma; 1674 pd[2] = gamma; 1675 pd[3] = alpha; 1676 1677 dst.setPixel(dstX, y, pd); 1678 dstX += step; 1679 } 1680 break; 1681 1682 case POST_GRAY_ALPHA_EXP: 1683 for (srcX = 0; srcX < width; srcX++) { 1684 src.getPixel(srcX, 0, ps); 1685 1686 int val = ps[0]; 1687 int alpha = ps[1]; 1688 pd[0] = val; 1689 pd[1] = val; 1690 pd[2] = val; 1691 pd[3] = alpha; 1692 1693 dst.setPixel(dstX, y, pd); 1694 dstX += step; 1695 } 1696 break; 1697 1698 case POST_ADD_GRAY_TRANS_EXP: 1699 for (srcX = 0; srcX < width; srcX++) { 1700 src.getPixel(srcX, 0, ps); 1701 1702 int val = ps[0]; 1703 if (performGammaCorrection) { 1704 val = gammaLut[val]; 1705 } 1706 pd[0] = val; 1707 pd[1] = val; 1708 pd[2] = val; 1709 if (val == grayTransparentAlpha) { 1710 pd[3] = 0; 1711 } else { 1712 pd[3] = maxOpacity; 1713 } 1714 1715 dst.setPixel(dstX, y, pd); 1716 dstX += step; 1717 } 1718 break; 1719 1720 case POST_GRAY_LUT_ADD_TRANS_EXP: 1721 for (srcX = 0; srcX < width; srcX++) { 1722 src.getPixel(srcX, 0, ps); 1723 1724 int val = ps[0]; 1725 int val2 = grayLut[val]; 1726 pd[0] = val2; 1727 pd[1] = val2; 1728 pd[2] = val2; 1729 if (val == grayTransparentAlpha) { 1730 pd[3] = 0; 1731 } else { 1732 pd[3] = maxOpacity; 1733 } 1734 1735 dst.setPixel(dstX, y, pd); 1736 dstX += step; 1737 } 1738 break; 1739 } 1740 } 1741 1742 1746 private void decodePass(WritableRaster imRas, 1747 int xOffset, int yOffset, 1748 int xStep, int yStep, 1749 int passWidth, int passHeight) { 1750 if ((passWidth == 0) || (passHeight == 0)) { 1751 return; 1752 } 1753 1754 int bytesPerRow = (inputBands*passWidth*bitDepth + 7)/8; 1755 int eltsPerRow = (bitDepth == 16) ? bytesPerRow/2 : bytesPerRow; 1756 byte[] curr = new byte[bytesPerRow]; 1757 byte[] prior = new byte[bytesPerRow]; 1758 1759 WritableRaster passRow = 1761 createRaster(passWidth, 1, inputBands, 1762 eltsPerRow, 1763 bitDepth); 1764 DataBuffer dataBuffer = passRow.getDataBuffer(); 1765 int type = dataBuffer.getDataType(); 1766 byte[] byteData = null; 1767 short[] shortData = null; 1768 if (type == DataBuffer.TYPE_BYTE) { 1769 byteData = ((DataBufferByte )dataBuffer).getData(); 1770 } else { 1771 shortData = ((DataBufferUShort )dataBuffer).getData(); 1772 } 1773 1774 int srcY, dstY; 1776 for (srcY = 0, dstY = yOffset; 1777 srcY < passHeight; 1778 srcY++, dstY += yStep) { 1779 int filter = 0; 1781 try { 1782 filter = dataStream.read(); 1783 dataStream.readFully(curr, 0, bytesPerRow); 1784 } catch (Exception e) { 1785 e.printStackTrace(); 1786 } 1787 1788 switch (filter) { 1789 case PNG_FILTER_NONE: 1790 break; 1791 case PNG_FILTER_SUB: 1792 decodeSubFilter(curr, bytesPerRow, bytesPerPixel); 1793 break; 1794 case PNG_FILTER_UP: 1795 decodeUpFilter(curr, prior, bytesPerRow); 1796 break; 1797 case PNG_FILTER_AVERAGE: 1798 decodeAverageFilter(curr, prior, bytesPerRow, bytesPerPixel); 1799 break; 1800 case PNG_FILTER_PAETH: 1801 decodePaethFilter(curr, prior, bytesPerRow, bytesPerPixel); 1802 break; 1803 default: 1804 String msg = PropertyUtil.getString("PNGImageDecoder16"); 1806 throw new RuntimeException (msg); 1807 } 1808 1809 if (bitDepth < 16) { 1811 System.arraycopy(curr, 0, byteData, 0, bytesPerRow); 1812 } else { 1813 int idx = 0; 1814 for (int j = 0; j < eltsPerRow; j++) { 1815 shortData[j] = 1816 (short)((curr[idx] << 8) | (curr[idx + 1] & 0xff)); 1817 idx += 2; 1818 } 1819 } 1820 1821 processPixels(postProcess, 1822 passRow, imRas, xOffset, xStep, dstY, passWidth); 1823 1824 byte[] tmp = prior; 1826 prior = curr; 1827 curr = tmp; 1828 } 1829 } 1830 1831 private void decodeImage(boolean useInterlacing) { 1832 if (!useInterlacing) { 1833 decodePass(theTile, 0, 0, 1, 1, width, height); 1834 } else { 1835 decodePass(theTile, 0, 0, 8, 8, (width + 7)/8, (height + 7)/8); 1836 decodePass(theTile, 4, 0, 8, 8, (width + 3)/8, (height + 7)/8); 1837 decodePass(theTile, 0, 4, 4, 8, (width + 3)/4, (height + 3)/8); 1838 decodePass(theTile, 2, 0, 4, 4, (width + 1)/4, (height + 3)/4); 1839 decodePass(theTile, 0, 2, 2, 4, (width + 1)/2, (height + 1)/4); 1840 decodePass(theTile, 1, 0, 2, 2, width/2, (height + 1)/2); 1841 decodePass(theTile, 0, 1, 1, 2, width, height/2); 1842 } 1843 } 1844 1845 1847 public Raster getTile(int tileX, int tileY) { 1848 if (tileX != 0 || tileY != 0) { 1849 String msg = PropertyUtil.getString("PNGImageDecoder17"); 1851 throw new IllegalArgumentException (msg); 1852 } 1853 return theTile; 1854 } 1855} 1856 | Popular Tags |