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