1 18 package org.apache.batik.ext.awt.image.codec; 19 20 import java.awt.Rectangle ; 21 import java.awt.image.ColorModel ; 22 import java.awt.image.IndexColorModel ; 23 import java.awt.image.Raster ; 24 import java.awt.image.RenderedImage ; 25 import java.awt.image.SampleModel ; 26 import java.io.ByteArrayOutputStream ; 27 import java.io.DataOutput ; 28 import java.io.DataOutputStream ; 29 import java.io.FilterOutputStream ; 30 import java.io.IOException ; 31 import java.io.OutputStream ; 32 import java.util.Calendar ; 33 import java.util.Date ; 34 import java.util.GregorianCalendar ; 35 import java.util.TimeZone ; 36 import java.util.zip.Deflater ; 37 import java.util.zip.DeflaterOutputStream ; 38 39 class CRC { 40 41 private static int[] crcTable = new int[256]; 42 43 static { 44 for (int n = 0; n < 256; n++) { 46 int c = n; 47 for (int k = 0; k < 8; k++) { 48 if ((c & 1) == 1) { 49 c = 0xedb88320 ^ (c >>> 1); 50 } else { 51 c >>>= 1; 52 } 53 54 crcTable[n] = c; 55 } 56 } 57 } 58 59 public static int updateCRC(int crc, byte[] data, int off, int len) { 60 int c = crc; 61 62 for (int n = 0; n < len; n++) { 63 c = crcTable[(c ^ data[off + n]) & 0xff] ^ (c >>> 8); 64 } 65 66 return c; 67 } 68 } 69 70 71 class ChunkStream extends OutputStream implements DataOutput { 72 73 private String type; 74 private ByteArrayOutputStream baos; 75 private DataOutputStream dos; 76 77 public ChunkStream(String type) throws IOException { 78 this.type = type; 79 80 this.baos = new ByteArrayOutputStream (); 81 this.dos = new DataOutputStream (baos); 82 } 83 84 public void write(byte[] b) throws IOException { 85 dos.write(b); 86 } 87 88 public void write(byte[] b, int off, int len) throws IOException { 89 dos.write(b, off, len); 90 } 91 92 public void write(int b) throws IOException { 93 dos.write(b); 94 } 95 96 public void writeBoolean(boolean v) throws IOException { 97 dos.writeBoolean(v); 98 } 99 100 public void writeByte(int v) throws IOException { 101 dos.writeByte(v); 102 } 103 104 public void writeBytes(String s) throws IOException { 105 dos.writeBytes(s); 106 } 107 108 public void writeChar(int v) throws IOException { 109 dos.writeChar(v); 110 } 111 112 public void writeChars(String s) throws IOException { 113 dos.writeChars(s); 114 } 115 116 public void writeDouble(double v) throws IOException { 117 dos.writeDouble(v); 118 } 119 120 public void writeFloat(float v) throws IOException { 121 dos.writeFloat(v); 122 } 123 124 public void writeInt(int v) throws IOException { 125 dos.writeInt(v); 126 } 127 128 public void writeLong(long v) throws IOException { 129 dos.writeLong(v); 130 } 131 132 public void writeShort(int v) throws IOException { 133 dos.writeShort(v); 134 } 135 136 public void writeUTF(String str) throws IOException { 137 dos.writeUTF(str); 138 } 139 140 public void writeToStream(DataOutputStream output) throws IOException { 141 byte[] typeSignature = new byte[4]; 142 typeSignature[0] = (byte)type.charAt(0); 143 typeSignature[1] = (byte)type.charAt(1); 144 typeSignature[2] = (byte)type.charAt(2); 145 typeSignature[3] = (byte)type.charAt(3); 146 147 dos.flush(); 148 baos.flush(); 149 150 byte[] data = baos.toByteArray(); 151 int len = data.length; 152 153 output.writeInt(len); 154 output.write(typeSignature); 155 output.write(data, 0, len); 156 157 int crc = 0xffffffff; 158 crc = CRC.updateCRC(crc, typeSignature, 0, 4); 159 crc = CRC.updateCRC(crc, data, 0, len); 160 output.writeInt(crc ^ 0xffffffff); 161 } 162 } 163 164 165 class IDATOutputStream extends FilterOutputStream { 166 167 private static final byte[] typeSignature = 168 {(byte)'I', (byte)'D', (byte)'A', (byte)'T'}; 169 170 private int bytesWritten = 0; 171 private int segmentLength; 172 byte[] buffer; 173 174 public IDATOutputStream(OutputStream output, 175 int segmentLength) { 176 super(output); 177 this.segmentLength = segmentLength; 178 this.buffer = new byte[segmentLength]; 179 } 180 181 public void close() throws IOException { 182 flush(); 183 } 184 185 private void writeInt(int x) throws IOException { 186 out.write(x >> 24); 187 out.write((x >> 16) & 0xff); 188 out.write((x >> 8) & 0xff); 189 out.write(x & 0xff); 190 } 191 192 public void flush() throws IOException { 193 writeInt(bytesWritten); 195 out.write(typeSignature); 197 out.write(buffer, 0, bytesWritten); 199 200 int crc = 0xffffffff; 201 crc = CRC.updateCRC(crc, typeSignature, 0, 4); 202 crc = CRC.updateCRC(crc, buffer, 0, bytesWritten); 203 204 writeInt(crc ^ 0xffffffff); 206 207 bytesWritten = 0; 209 } 210 211 public void write(byte[] b) throws IOException { 212 this.write(b, 0, b.length); 213 } 214 215 public void write(byte[] b, int off, int len) throws IOException { 216 while (len > 0) { 217 int bytes = Math.min(segmentLength - bytesWritten, len); 218 System.arraycopy(b, off, buffer, bytesWritten, bytes); 219 off += bytes; 220 len -= bytes; 221 bytesWritten += bytes; 222 223 if (bytesWritten == segmentLength) { 224 flush(); 225 } 226 } 227 } 228 229 public void write(int b) throws IOException { 230 buffer[bytesWritten++] = (byte)b; 231 if (bytesWritten == segmentLength) { 232 flush(); 233 } 234 } 235 } 236 237 242 public class PNGImageEncoder extends ImageEncoderImpl { 243 244 private static final int PNG_COLOR_GRAY = 0; 245 private static final int PNG_COLOR_RGB = 2; 246 private static final int PNG_COLOR_PALETTE = 3; 247 private static final int PNG_COLOR_GRAY_ALPHA = 4; 248 private static final int PNG_COLOR_RGB_ALPHA = 6; 249 250 private static final byte[] magic = { 251 (byte)137, (byte) 80, (byte) 78, (byte) 71, 252 (byte) 13, (byte) 10, (byte) 26, (byte) 10 253 }; 254 255 private PNGEncodeParam param; 256 257 private RenderedImage image; 258 private int width; 259 private int height; 260 private int bitDepth; 261 private int bitShift; 262 private int numBands; 263 private int colorType; 264 265 private int bpp; 267 private boolean skipAlpha = false; 268 private boolean compressGray = false; 269 270 private boolean interlace; 271 272 private byte[] redPalette = null; 273 private byte[] greenPalette = null; 274 private byte[] bluePalette = null; 275 private byte[] alphaPalette = null; 276 277 private DataOutputStream dataOutput; 278 279 public PNGImageEncoder(OutputStream output, 280 PNGEncodeParam param) { 281 super(output, param); 282 283 if (param != null) { 284 this.param = param; 285 } 286 this.dataOutput = new DataOutputStream (output); 287 } 288 289 private void writeMagic() throws IOException { 290 dataOutput.write(magic); 291 } 292 293 private void writeIHDR() throws IOException { 294 ChunkStream cs = new ChunkStream("IHDR"); 295 cs.writeInt(width); 296 cs.writeInt(height); 297 cs.writeByte((byte)bitDepth); 298 cs.writeByte((byte)colorType); 299 cs.writeByte((byte)0); 300 cs.writeByte((byte)0); 301 cs.writeByte(interlace ? (byte)1 : (byte)0); 302 303 cs.writeToStream(dataOutput); 304 } 305 306 private byte[] prevRow = null; 307 private byte[] currRow = null; 308 309 private byte[][] filteredRows = null; 310 311 private static int clamp(int val, int maxValue) { 312 return (val > maxValue) ? maxValue : val; 313 } 314 315 private void encodePass(OutputStream os, Raster ras, 316 int xOffset, int yOffset, 317 int xSkip, int ySkip) 318 throws IOException { 319 int minX = ras.getMinX(); 320 int minY = ras.getMinY(); 321 int width = ras.getWidth(); 322 int height = ras.getHeight(); 323 324 xOffset *= numBands; 325 xSkip *= numBands; 326 327 int samplesPerByte = 8/bitDepth; 328 329 int numSamples = width*numBands; 330 int[] samples = new int[numSamples]; 331 332 int pixels = (numSamples - xOffset + xSkip - 1)/xSkip; 333 int bytesPerRow = pixels*numBands; 334 if (bitDepth < 8) { 335 bytesPerRow = (bytesPerRow + samplesPerByte - 1)/samplesPerByte; 336 } else if (bitDepth == 16) { 337 bytesPerRow *= 2; 338 } 339 340 if (bytesPerRow == 0) { 341 return; 342 } 343 344 currRow = new byte[bytesPerRow + bpp]; 345 prevRow = new byte[bytesPerRow + bpp]; 346 347 filteredRows = new byte[5][bytesPerRow + bpp]; 348 349 int maxValue = (1 << bitDepth) - 1; 350 351 for (int row = minY + yOffset; row < minY + height; row += ySkip) { 352 ras.getPixels(minX, row, width, 1, samples); 353 354 if (compressGray) { 355 int shift = 8 - bitDepth; 356 for (int i = 0; i < width; i++) { 357 samples[i] >>= shift; 358 } 359 } 360 361 int count = bpp; int pos = 0; 363 int tmp = 0; 364 365 switch (bitDepth) { 366 case 1: case 2: case 4: 367 369 int mask = samplesPerByte - 1; 370 for (int s = xOffset; s < numSamples; s += xSkip) { 371 int val = clamp(samples[s] >> bitShift, maxValue); 372 tmp = (tmp << bitDepth) | val; 373 374 if (pos++ == mask) { 375 currRow[count++] = (byte)tmp; 376 tmp = 0; 377 pos = 0; 378 } 379 } 380 381 if (pos != 0) { 383 tmp <<= (samplesPerByte - pos)*bitDepth; 384 currRow[count++] = (byte)tmp; 385 } 386 break; 387 388 case 8: 389 for (int s = xOffset; s < numSamples; s += xSkip) { 390 for (int b = 0; b < numBands; b++) { 391 currRow[count++] = 392 (byte)clamp(samples[s + b] >> bitShift, maxValue); 393 } 394 } 395 break; 396 397 case 16: 398 for (int s = xOffset; s < numSamples; s += xSkip) { 399 for (int b = 0; b < numBands; b++) { 400 int val = clamp(samples[s + b] >> bitShift, maxValue); 401 currRow[count++] = (byte)(val >> 8); 402 currRow[count++] = (byte)(val & 0xff); 403 } 404 } 405 break; 406 } 407 408 int filterType = param.filterRow(currRow, prevRow, 410 filteredRows, 411 bytesPerRow, bpp); 412 413 os.write(filterType); 414 os.write(filteredRows[filterType], bpp, bytesPerRow); 415 416 byte[] swap = currRow; 418 currRow = prevRow; 419 prevRow = swap; 420 } 421 } 422 423 private void writeIDAT() throws IOException { 424 IDATOutputStream ios = new IDATOutputStream(dataOutput, 8192); 425 DeflaterOutputStream dos = 426 new DeflaterOutputStream (ios, new Deflater (9)); 427 428 Raster ras = image.getData(new Rectangle (image.getMinX(), 436 image.getMinY(), 437 image.getWidth(), 438 image.getHeight())); 439 450 if (skipAlpha) { 451 int numBands = ras.getNumBands() - 1; 452 int[] bandList = new int[numBands]; 453 for (int i = 0; i < numBands; i++) { 454 bandList[i] = i; 455 } 456 ras = ras.createChild(0, 0, 457 ras.getWidth(), ras.getHeight(), 458 0, 0, 459 bandList); 460 } 461 462 if (interlace) { 463 encodePass(dos, ras, 0, 0, 8, 8); 465 encodePass(dos, ras, 4, 0, 8, 8); 467 encodePass(dos, ras, 0, 4, 4, 8); 469 encodePass(dos, ras, 2, 0, 4, 4); 471 encodePass(dos, ras, 0, 2, 2, 4); 473 encodePass(dos, ras, 1, 0, 2, 2); 475 encodePass(dos, ras, 0, 1, 1, 2); 477 } else { 478 encodePass(dos, ras, 0, 0, 1, 1); 479 } 480 481 dos.finish(); 482 ios.flush(); 483 } 484 485 private void writeIEND() throws IOException { 486 ChunkStream cs = new ChunkStream("IEND"); 487 cs.writeToStream(dataOutput); 488 } 489 490 private static final float[] srgbChroma = { 491 0.31270F, 0.329F, 0.64F, 0.33F, 0.3F, 0.6F, 0.15F, 0.06F 492 }; 493 494 private void writeCHRM() throws IOException { 495 if (param.isChromaticitySet() || param.isSRGBIntentSet()) { 496 ChunkStream cs = new ChunkStream("cHRM"); 497 498 float[] chroma; 499 if (!param.isSRGBIntentSet()) { 500 chroma = param.getChromaticity(); 501 } else { 502 chroma = srgbChroma; } 504 505 for (int i = 0; i < 8; i++) { 506 cs.writeInt((int)(chroma[i]*100000)); 507 } 508 cs.writeToStream(dataOutput); 509 } 510 } 511 512 private void writeGAMA() throws IOException { 513 if (param.isGammaSet() || param.isSRGBIntentSet()) { 514 ChunkStream cs = new ChunkStream("gAMA"); 515 516 float gamma; 517 if (!param.isSRGBIntentSet()) { 518 gamma = param.getGamma(); 519 } else { 520 gamma = 1.0F/2.2F; } 522 cs.writeInt((int)(gamma*100000)); 525 cs.writeToStream(dataOutput); 526 } 527 } 528 529 private void writeICCP() throws IOException { 530 if (param.isICCProfileDataSet()) { 531 ChunkStream cs = new ChunkStream("iCCP"); 532 byte[] ICCProfileData = param.getICCProfileData(); 533 cs.write(ICCProfileData); 534 cs.writeToStream(dataOutput); 535 } 536 } 537 538 private void writeSBIT() throws IOException { 539 if (param.isSignificantBitsSet()) { 540 ChunkStream cs = new ChunkStream("sBIT"); 541 int[] significantBits = param.getSignificantBits(); 542 int len = significantBits.length; 543 for (int i = 0; i < len; i++) { 544 cs.writeByte(significantBits[i]); 545 } 546 cs.writeToStream(dataOutput); 547 } 548 } 549 550 private void writeSRGB() throws IOException { 551 if (param.isSRGBIntentSet()) { 552 ChunkStream cs = new ChunkStream("sRGB"); 553 554 int intent = param.getSRGBIntent(); 555 cs.write(intent); 556 cs.writeToStream(dataOutput); 557 } 558 } 559 560 private void writePLTE() throws IOException { 561 if (redPalette == null) { 562 return; 563 } 564 565 ChunkStream cs = new ChunkStream("PLTE"); 566 for (int i = 0; i < redPalette.length; i++) { 567 cs.writeByte(redPalette[i]); 568 cs.writeByte(greenPalette[i]); 569 cs.writeByte(bluePalette[i]); 570 } 571 572 cs.writeToStream(dataOutput); 573 } 574 575 private void writeBKGD() throws IOException { 576 if (param.isBackgroundSet()) { 577 ChunkStream cs = new ChunkStream("bKGD"); 578 579 switch (colorType) { 580 case PNG_COLOR_GRAY: 581 case PNG_COLOR_GRAY_ALPHA: 582 int gray = ((PNGEncodeParam.Gray)param).getBackgroundGray(); 583 cs.writeShort(gray); 584 break; 585 586 case PNG_COLOR_PALETTE: 587 int index = 588 ((PNGEncodeParam.Palette)param).getBackgroundPaletteIndex(); 589 cs.writeByte(index); 590 break; 591 592 case PNG_COLOR_RGB: 593 case PNG_COLOR_RGB_ALPHA: 594 int[] rgb = ((PNGEncodeParam.RGB)param).getBackgroundRGB(); 595 cs.writeShort(rgb[0]); 596 cs.writeShort(rgb[1]); 597 cs.writeShort(rgb[2]); 598 break; 599 } 600 601 cs.writeToStream(dataOutput); 602 } 603 } 604 605 private void writeHIST() throws IOException { 606 if (param.isPaletteHistogramSet()) { 607 ChunkStream cs = new ChunkStream("hIST"); 608 609 int[] hist = param.getPaletteHistogram(); 610 for (int i = 0; i < hist.length; i++) { 611 cs.writeShort(hist[i]); 612 } 613 614 cs.writeToStream(dataOutput); 615 } 616 } 617 618 private void writeTRNS() throws IOException { 619 if (param.isTransparencySet() && 620 (colorType != PNG_COLOR_GRAY_ALPHA) && 621 (colorType != PNG_COLOR_RGB_ALPHA)) { 622 ChunkStream cs = new ChunkStream("tRNS"); 623 624 if (param instanceof PNGEncodeParam.Palette) { 625 byte[] t = 626 ((PNGEncodeParam.Palette)param).getPaletteTransparency(); 627 for (int i = 0; i < t.length; i++) { 628 cs.writeByte(t[i]); 629 } 630 } else if (param instanceof PNGEncodeParam.Gray) { 631 int t = ((PNGEncodeParam.Gray)param).getTransparentGray(); 632 cs.writeShort(t); 633 } else if (param instanceof PNGEncodeParam.RGB) { 634 int[] t = ((PNGEncodeParam.RGB)param).getTransparentRGB(); 635 cs.writeShort(t[0]); 636 cs.writeShort(t[1]); 637 cs.writeShort(t[2]); 638 } 639 640 cs.writeToStream(dataOutput); 641 } else if (colorType == PNG_COLOR_PALETTE) { 642 int lastEntry = Math.min(255, alphaPalette.length - 1); 643 int nonOpaque; 644 for (nonOpaque = lastEntry; nonOpaque >= 0; nonOpaque--) { 645 if (alphaPalette[nonOpaque] != (byte)255) { 646 break; 647 } 648 } 649 650 if (nonOpaque >= 0) { 651 ChunkStream cs = new ChunkStream("tRNS"); 652 for (int i = 0; i <= nonOpaque; i++) { 653 cs.writeByte(alphaPalette[i]); 654 } 655 cs.writeToStream(dataOutput); 656 } 657 } 658 } 659 660 private void writePHYS() throws IOException { 661 if (param.isPhysicalDimensionSet()) { 662 ChunkStream cs = new ChunkStream("pHYs"); 663 664 int[] dims = param.getPhysicalDimension(); 665 cs.writeInt(dims[0]); 666 cs.writeInt(dims[1]); 667 cs.writeByte((byte)dims[2]); 668 669 cs.writeToStream(dataOutput); 670 } 671 } 672 673 private void writeSPLT() throws IOException { 674 if (param.isSuggestedPaletteSet()) { 675 ChunkStream cs = new ChunkStream("sPLT"); 676 677 System.out.println("sPLT not supported yet."); 678 679 cs.writeToStream(dataOutput); 680 } 681 } 682 683 private void writeTIME() throws IOException { 684 if (param.isModificationTimeSet()) { 685 ChunkStream cs = new ChunkStream("tIME"); 686 687 Date date = param.getModificationTime(); 688 TimeZone gmt = TimeZone.getTimeZone("GMT"); 689 690 GregorianCalendar cal = new GregorianCalendar (gmt); 691 cal.setTime(date); 692 693 int year = cal.get(Calendar.YEAR); 694 int month = cal.get(Calendar.MONTH); 695 int day = cal.get(Calendar.DAY_OF_MONTH); 696 int hour = cal.get(Calendar.HOUR_OF_DAY); 697 int minute = cal.get(Calendar.MINUTE); 698 int second = cal.get(Calendar.SECOND); 699 700 cs.writeShort(year); 701 cs.writeByte(month + 1); 702 cs.writeByte(day); 703 cs.writeByte(hour); 704 cs.writeByte(minute); 705 cs.writeByte(second); 706 707 cs.writeToStream(dataOutput); 708 } 709 } 710 711 private void writeTEXT() throws IOException { 712 if (param.isTextSet()) { 713 String [] text = param.getText(); 714 715 for (int i = 0; i < text.length/2; i++) { 716 byte[] keyword = text[2*i].getBytes(); 717 byte[] value = text[2*i + 1].getBytes(); 718 719 ChunkStream cs = new ChunkStream("tEXt"); 720 721 cs.write(keyword, 0, Math.min(keyword.length, 79)); 722 cs.write(0); 723 cs.write(value); 724 725 cs.writeToStream(dataOutput); 726 } 727 } 728 } 729 730 private void writeZTXT() throws IOException { 731 if (param.isCompressedTextSet()) { 732 String [] text = param.getCompressedText(); 733 734 for (int i = 0; i < text.length/2; i++) { 735 byte[] keyword = text[2*i].getBytes(); 736 byte[] value = text[2*i + 1].getBytes(); 737 738 ChunkStream cs = new ChunkStream("zTXt"); 739 740 cs.write(keyword, 0, Math.min(keyword.length, 79)); 741 cs.write(0); 742 cs.write(0); 743 744 DeflaterOutputStream dos = new DeflaterOutputStream (cs); 745 dos.write(value); 746 dos.finish(); 747 748 cs.writeToStream(dataOutput); 749 } 750 } 751 } 752 753 private void writePrivateChunks() throws IOException { 754 int numChunks = param.getNumPrivateChunks(); 755 for (int i = 0; i < numChunks; i++) { 756 String type = param.getPrivateChunkType(i); 757 byte[] data = param.getPrivateChunkData(i); 758 759 ChunkStream cs = new ChunkStream(type); 760 cs.write(data); 761 cs.writeToStream(dataOutput); 762 } 763 } 764 765 773 private PNGEncodeParam.Gray createGrayParam(byte[] redPalette, 774 byte[] greenPalette, 775 byte[] bluePalette, 776 byte[] alphaPalette) { 777 PNGEncodeParam.Gray param = new PNGEncodeParam.Gray(); 778 int numTransparent = 0; 779 780 int grayFactor = 255/((1 << bitDepth) - 1); 781 int entries = 1 << bitDepth; 782 for (int i = 0; i < entries; i++) { 783 byte red = redPalette[i]; 784 if ((red != i*grayFactor) || 785 (red != greenPalette[i]) || 786 (red != bluePalette[i])) { 787 return null; 788 } 789 790 byte alpha = alphaPalette[i]; 792 if (alpha == (byte)0) { 793 param.setTransparentGray(i); 794 795 ++numTransparent; 796 if (numTransparent > 1) { 797 return null; 798 } 799 } else if (alpha != (byte)255) { 800 return null; 801 } 802 } 803 804 return param; 805 } 806 807 813 public void encode(RenderedImage im) throws IOException { 814 this.image = im; 815 this.width = image.getWidth(); 816 this.height = image.getHeight(); 817 818 SampleModel sampleModel = image.getSampleModel(); 819 820 int[] sampleSize = sampleModel.getSampleSize(); 821 822 this.bitDepth = -1; 824 this.bitShift = 0; 825 826 if (param instanceof PNGEncodeParam.Gray) { 828 PNGEncodeParam.Gray paramg = (PNGEncodeParam.Gray)param; 829 if (paramg.isBitDepthSet()) { 830 this.bitDepth = paramg.getBitDepth(); 831 } 832 833 if (paramg.isBitShiftSet()) { 834 this.bitShift = paramg.getBitShift(); 835 } 836 } 837 838 if (this.bitDepth == -1) { 840 842 this.bitDepth = sampleSize[0]; 843 for (int i = 1; i < sampleSize.length; i++) { 845 if (sampleSize[i] != bitDepth) { 846 throw new RuntimeException (); 847 } 848 } 849 850 if (bitDepth > 2 && bitDepth < 4) { 852 bitDepth = 4; 853 } else if (bitDepth > 4 && bitDepth < 8) { 854 bitDepth = 8; 855 } else if (bitDepth > 8 && bitDepth < 16) { 856 bitDepth = 16; 857 } else if (bitDepth > 16) { 858 throw new RuntimeException (); 859 } 860 } 861 862 this.numBands = sampleModel.getNumBands(); 863 this.bpp = numBands*((bitDepth == 16) ? 2 : 1); 864 865 ColorModel colorModel = image.getColorModel(); 866 if (colorModel instanceof IndexColorModel ) { 867 if (bitDepth < 1 || bitDepth > 8) { 868 throw new RuntimeException (); 869 } 870 if (sampleModel.getNumBands() != 1) { 871 throw new RuntimeException (); 872 } 873 874 IndexColorModel icm = (IndexColorModel )colorModel; 875 int size = icm.getMapSize(); 876 877 redPalette = new byte[size]; 878 greenPalette = new byte[size]; 879 bluePalette = new byte[size]; 880 alphaPalette = new byte[size]; 881 882 icm.getReds(redPalette); 883 icm.getGreens(greenPalette); 884 icm.getBlues(bluePalette); 885 icm.getAlphas(alphaPalette); 886 887 this.bpp = 1; 888 889 if (param == null) { 890 param = createGrayParam(redPalette, 891 greenPalette, 892 bluePalette, 893 alphaPalette); 894 } 895 896 if (param == null) { 898 param = new PNGEncodeParam.Palette(); 899 } 900 901 if (param instanceof PNGEncodeParam.Palette) { 902 PNGEncodeParam.Palette parami = (PNGEncodeParam.Palette)param; 904 if (parami.isPaletteSet()) { 905 int[] palette = parami.getPalette(); 906 size = palette.length/3; 907 908 int index = 0; 909 for (int i = 0; i < size; i++) { 910 redPalette[i] = (byte)palette[index++]; 911 greenPalette[i] = (byte)palette[index++]; 912 bluePalette[i] = (byte)palette[index++]; 913 alphaPalette[i] = (byte)255; 914 } 915 } 916 this.colorType = PNG_COLOR_PALETTE; 917 } else if (param instanceof PNGEncodeParam.Gray) { 918 redPalette = greenPalette = bluePalette = alphaPalette = null; 919 this.colorType = PNG_COLOR_GRAY; 920 } else { 921 throw new RuntimeException (); 922 } 923 } else if (numBands == 1) { 924 if (param == null) { 925 param = new PNGEncodeParam.Gray(); 926 } 927 this.colorType = PNG_COLOR_GRAY; 928 } else if (numBands == 2) { 929 if (param == null) { 930 param = new PNGEncodeParam.Gray(); 931 } 932 933 if (param.isTransparencySet()) { 934 skipAlpha = true; 935 numBands = 1; 936 if ((sampleSize[0] == 8) && (bitDepth < 8)) { 937 compressGray = true; 938 } 939 bpp = (bitDepth == 16) ? 2 : 1; 940 this.colorType = PNG_COLOR_GRAY; 941 } else { 942 if (this.bitDepth < 8) { 943 this.bitDepth = 8; 944 } 945 this.colorType = PNG_COLOR_GRAY_ALPHA; 946 } 947 } else if (numBands == 3) { 948 if (param == null) { 949 param = new PNGEncodeParam.RGB(); 950 } 951 this.colorType = PNG_COLOR_RGB; 952 } else if (numBands == 4) { 953 if (param == null) { 954 param = new PNGEncodeParam.RGB(); 955 } 956 if (param.isTransparencySet()) { 957 skipAlpha = true; 958 numBands = 3; 959 bpp = (bitDepth == 16) ? 6 : 3; 960 this.colorType = PNG_COLOR_RGB; 961 } else { 962 this.colorType = PNG_COLOR_RGB_ALPHA; 963 } 964 } 965 966 interlace = param.getInterlacing(); 967 968 writeMagic(); 969 970 writeIHDR(); 971 972 writeCHRM(); 973 writeGAMA(); 974 writeICCP(); 975 writeSBIT(); 976 writeSRGB(); 977 978 writePLTE(); 979 980 writeHIST(); 981 writeTRNS(); 982 writeBKGD(); 983 984 writePHYS(); 985 writeSPLT(); 986 writeTIME(); 987 writeTEXT(); 988 writeZTXT(); 989 990 writePrivateChunks(); 991 992 writeIDAT(); 993 994 writeIEND(); 995 996 dataOutput.flush(); 997 } 998 } 999 | Popular Tags |