1 18 package org.apache.batik.ext.awt.image.codec; 19 20 import java.awt.image.ColorModel ; 21 import java.awt.image.IndexColorModel ; 22 import java.awt.image.RenderedImage ; 23 import java.awt.image.SampleModel ; 24 import java.util.Date ; 25 import java.util.Vector ; 26 27 34 public abstract class PNGEncodeParam implements ImageEncodeParam { 35 36 37 public static final int INTENT_PERCEPTUAL = 0; 38 39 40 public static final int INTENT_RELATIVE = 1; 41 42 43 public static final int INTENT_SATURATION = 2; 44 45 46 public static final int INTENT_ABSOLUTE = 3; 47 48 49 public static final int PNG_FILTER_NONE = 0; 50 51 52 public static final int PNG_FILTER_SUB = 1; 53 54 55 public static final int PNG_FILTER_UP = 2; 56 57 58 public static final int PNG_FILTER_AVERAGE = 3; 59 60 61 public static final int PNG_FILTER_PAETH = 4; 62 63 64 82 public static PNGEncodeParam getDefaultEncodeParam(RenderedImage im) { 83 ColorModel colorModel = im.getColorModel(); 84 if (colorModel instanceof IndexColorModel ) { 85 return new PNGEncodeParam.Palette(); 86 } 87 88 SampleModel sampleModel = im.getSampleModel(); 89 int numBands = sampleModel.getNumBands(); 90 91 if (numBands == 1 || numBands == 2) { 92 return new PNGEncodeParam.Gray(); 93 } else { 94 return new PNGEncodeParam.RGB(); 95 } 96 } 97 98 public static class Palette extends PNGEncodeParam { 99 100 101 public Palette() {} 102 103 105 private boolean backgroundSet = false; 106 107 110 public void unsetBackground() { 111 backgroundSet = false; 112 } 113 114 117 public boolean isBackgroundSet() { 118 return backgroundSet; 119 } 120 121 126 public void setBitDepth(int bitDepth) { 127 if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && 128 bitDepth != 8) { 129 throw new IllegalArgumentException (PropertyUtil.getString("PNGEncodeParam2")); 130 } 131 this.bitDepth = bitDepth; 132 bitDepthSet = true; 133 } 134 135 137 private int[] palette = null; 138 private boolean paletteSet = false; 139 140 151 public void setPalette(int[] rgb) { 152 if (rgb.length < 1*3 || rgb.length > 256*3) { 153 throw new 154 IllegalArgumentException (PropertyUtil.getString("PNGEncodeParam0")); 155 } 156 if ((rgb.length % 3) != 0) { 157 throw new 158 IllegalArgumentException (PropertyUtil.getString("PNGEncodeParam1")); 159 } 160 161 palette = (int[])(rgb.clone()); 162 paletteSet = true; 163 } 164 165 175 public int[] getPalette() { 176 if (!paletteSet) { 177 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam3")); 178 } 179 return (int[])(palette.clone()); 180 } 181 182 185 public void unsetPalette() { 186 palette = null; 187 paletteSet = false; 188 } 189 190 193 public boolean isPaletteSet() { 194 return paletteSet; 195 } 196 197 199 private int backgroundPaletteIndex; 200 201 206 public void setBackgroundPaletteIndex(int index) { 207 backgroundPaletteIndex = index; 208 backgroundSet = true; 209 } 210 211 220 public int getBackgroundPaletteIndex() { 221 if (!backgroundSet) { 222 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam4")); 223 } 224 return backgroundPaletteIndex; 225 } 226 227 229 private int[] transparency; 230 231 238 public void setPaletteTransparency(byte[] alpha) { 239 transparency = new int[alpha.length]; 240 for (int i = 0; i < alpha.length; i++) { 241 transparency[i] = alpha[i] & 0xff; 242 } 243 transparencySet = true; 244 } 245 246 256 public byte[] getPaletteTransparency() { 257 if (!transparencySet) { 258 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam5")); 259 } 260 byte[] alpha = new byte[transparency.length]; 261 for (int i = 0; i < alpha.length; i++) { 262 alpha[i] = (byte)transparency[i]; 263 } 264 return alpha; 265 } 266 } 267 268 public static class Gray extends PNGEncodeParam { 269 270 271 public Gray() {} 272 273 275 private boolean backgroundSet = false; 276 277 280 public void unsetBackground() { 281 backgroundSet = false; 282 } 283 284 287 public boolean isBackgroundSet() { 288 return backgroundSet; 289 } 290 291 301 public void setBitDepth(int bitDepth) { 302 if (bitDepth != 1 && bitDepth != 2 && bitDepth != 4 && 303 bitDepth != 8 && bitDepth != 16) { 304 throw new IllegalArgumentException (); 305 } 306 this.bitDepth = bitDepth; 307 bitDepthSet = true; 308 } 309 310 312 private int backgroundPaletteGray; 313 314 319 public void setBackgroundGray(int gray) { 320 backgroundPaletteGray = gray; 321 backgroundSet = true; 322 } 323 324 334 public int getBackgroundGray() { 335 if (!backgroundSet) { 336 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam6")); 337 } 338 return backgroundPaletteGray; 339 } 340 341 343 private int[] transparency; 344 345 353 public void setTransparentGray(int transparentGray) { 354 transparency = new int[1]; 355 transparency[0] = transparentGray; 356 transparencySet = true; 357 } 358 359 369 public int getTransparentGray() { 370 if (!transparencySet) { 371 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam7")); 372 } 373 int gray = transparency[0]; 374 return gray; 375 } 376 377 private int bitShift; 378 private boolean bitShiftSet = false; 379 380 386 public void setBitShift(int bitShift) { 387 if (bitShift < 0) { 388 throw new RuntimeException (); 389 } 390 this.bitShift = bitShift; 391 bitShiftSet = true; 392 } 393 394 402 public int getBitShift() { 403 if (!bitShiftSet) { 404 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam8")); 405 } 406 return bitShift; 407 } 408 409 413 public void unsetBitShift() { 414 bitShiftSet = false; 415 } 416 417 420 public boolean isBitShiftSet() { 421 return bitShiftSet; 422 } 423 424 427 public boolean isBitDepthSet() { 428 return bitDepthSet; 429 } 430 } 431 432 public static class RGB extends PNGEncodeParam { 433 434 435 public RGB() {} 436 437 439 private boolean backgroundSet = false; 440 441 444 public void unsetBackground() { 445 backgroundSet = false; 446 } 447 448 451 public boolean isBackgroundSet() { 452 return backgroundSet; 453 } 454 455 459 public void setBitDepth(int bitDepth) { 460 if (bitDepth != 8 && bitDepth != 16) { 461 throw new RuntimeException (); 462 } 463 this.bitDepth = bitDepth; 464 bitDepthSet = true; 465 } 466 467 469 private int[] backgroundRGB; 470 471 477 public void setBackgroundRGB(int[] rgb) { 478 if (rgb.length != 3) { 479 throw new RuntimeException (); 480 } 481 backgroundRGB = rgb; 482 backgroundSet = true; 483 } 484 485 493 public int[] getBackgroundRGB() { 494 if (!backgroundSet) { 495 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam9")); 496 } 497 return backgroundRGB; 498 } 499 500 502 private int[] transparency; 503 504 512 public void setTransparentRGB(int[] transparentRGB) { 513 transparency = (int[])(transparentRGB.clone()); 514 transparencySet = true; 515 } 516 517 526 public int[] getTransparentRGB() { 527 if (!transparencySet) { 528 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam10")); 529 } 530 return (int[])(transparency.clone()); 531 } 532 } 533 534 protected int bitDepth; 535 protected boolean bitDepthSet = false; 536 537 540 public abstract void setBitDepth(int bitDepth); 541 542 550 public int getBitDepth() { 551 if (!bitDepthSet) { 552 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam11")); 553 } 554 return bitDepth; 555 } 556 557 563 public void unsetBitDepth() { 564 bitDepthSet = false; 565 } 566 567 private boolean useInterlacing = false; 568 569 572 public void setInterlacing(boolean useInterlacing) { 573 this.useInterlacing = useInterlacing; 574 } 575 576 579 public boolean getInterlacing() { 580 return useInterlacing; 581 } 582 583 585 596 602 public void unsetBackground() { 603 throw new RuntimeException (PropertyUtil.getString("PNGEncodeParam23")); 604 } 605 606 612 public boolean isBackgroundSet() { 613 throw new RuntimeException (PropertyUtil.getString("PNGEncodeParam24")); 614 } 615 616 618 private float[] chromaticity = null; 619 private boolean chromaticitySet = false; 620 621 632 public void setChromaticity(float[] chromaticity) { 633 if (chromaticity.length != 8) { 634 throw new IllegalArgumentException (); 635 } 636 this.chromaticity = (float[])(chromaticity.clone()); 637 chromaticitySet = true; 638 } 639 640 643 public void setChromaticity(float whitePointX, float whitePointY, 644 float redX, float redY, 645 float greenX, float greenY, 646 float blueX, float blueY) { 647 float[] chroma = new float[8]; 648 chroma[0] = whitePointX; 649 chroma[1] = whitePointY; 650 chroma[2] = redX; 651 chroma[3] = redY; 652 chroma[4] = greenX; 653 chroma[5] = greenY; 654 chroma[6] = blueX; 655 chroma[7] = blueY; 656 setChromaticity(chroma); 657 } 658 659 671 public float[] getChromaticity() { 672 if (!chromaticitySet) { 673 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam12")); 674 } 675 return (float[])(chromaticity.clone()); 676 } 677 678 681 public void unsetChromaticity() { 682 chromaticity = null; 683 chromaticitySet = false; 684 } 685 686 689 public boolean isChromaticitySet() { 690 return chromaticitySet; 691 } 692 693 695 private float gamma; 696 private boolean gammaSet = false; 697 698 703 public void setGamma(float gamma) { 704 this.gamma = gamma; 705 gammaSet = true; 706 } 707 708 716 public float getGamma() { 717 if (!gammaSet) { 718 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam13")); 719 } 720 return gamma; 721 } 722 723 726 public void unsetGamma() { 727 gammaSet = false; 728 } 729 730 733 public boolean isGammaSet() { 734 return gammaSet; 735 } 736 737 739 private int[] paletteHistogram = null; 740 private boolean paletteHistogramSet = false; 741 742 749 public void setPaletteHistogram(int[] paletteHistogram) { 750 this.paletteHistogram = (int[])(paletteHistogram.clone()); 751 paletteHistogramSet = true; 752 } 753 754 762 public int[] getPaletteHistogram() { 763 if (!paletteHistogramSet) { 764 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam14")); 765 } 766 return paletteHistogram; 767 } 768 769 772 public void unsetPaletteHistogram() { 773 paletteHistogram = null; 774 paletteHistogramSet = false; 775 } 776 777 780 public boolean isPaletteHistogramSet() { 781 return paletteHistogramSet; 782 } 783 784 786 private byte[] ICCProfileData = null; 787 private boolean ICCProfileDataSet = false; 788 789 795 public void setICCProfileData(byte[] ICCProfileData) { 796 this.ICCProfileData = (byte[])(ICCProfileData.clone()); 797 ICCProfileDataSet = true; 798 } 799 800 808 public byte[] getICCProfileData() { 809 if (!ICCProfileDataSet) { 810 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam15")); 811 } 812 return (byte[])(ICCProfileData.clone()); 813 } 814 815 818 public void unsetICCProfileData() { 819 ICCProfileData = null; 820 ICCProfileDataSet = false; 821 } 822 823 826 public boolean isICCProfileDataSet() { 827 return ICCProfileDataSet; 828 } 829 830 832 private int[] physicalDimension = null; 833 private boolean physicalDimensionSet = false; 834 835 844 public void setPhysicalDimension(int[] physicalDimension) { 845 this.physicalDimension = (int[])(physicalDimension.clone()); 846 physicalDimensionSet = true; 847 } 848 849 852 public void setPhysicalDimension(int xPixelsPerUnit, 853 int yPixelsPerUnit, 854 int unitSpecifier) { 855 int[] pd = new int[3]; 856 pd[0] = xPixelsPerUnit; 857 pd[1] = yPixelsPerUnit; 858 pd[2] = unitSpecifier; 859 860 setPhysicalDimension(pd); 861 } 862 863 874 public int[] getPhysicalDimension() { 875 if (!physicalDimensionSet) { 876 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam16")); 877 } 878 return (int[])(physicalDimension.clone()); 879 } 880 881 884 public void unsetPhysicalDimension() { 885 physicalDimension = null; 886 physicalDimensionSet = false; 887 } 888 889 892 public boolean isPhysicalDimensionSet() { 893 return physicalDimensionSet; 894 } 895 896 898 private PNGSuggestedPaletteEntry[] suggestedPalette = null; 899 private boolean suggestedPaletteSet = false; 900 901 908 public void setSuggestedPalette(PNGSuggestedPaletteEntry[] palette) { 909 suggestedPalette = (PNGSuggestedPaletteEntry[])(palette.clone()); 910 suggestedPaletteSet = true; 911 } 912 913 924 public PNGSuggestedPaletteEntry[] getSuggestedPalette() { 925 if (!suggestedPaletteSet) { 926 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam17")); 927 } 928 return (PNGSuggestedPaletteEntry[])(suggestedPalette.clone()); 929 } 930 931 934 public void unsetSuggestedPalette() { 935 suggestedPalette = null; 936 suggestedPaletteSet = false; 937 } 938 939 942 public boolean isSuggestedPaletteSet() { 943 return suggestedPaletteSet; 944 } 945 946 948 private int[] significantBits = null; 949 private boolean significantBitsSet = false; 950 951 961 public void setSignificantBits(int[] significantBits) { 962 this.significantBits = (int[])(significantBits.clone()); 963 significantBitsSet = true; 964 } 965 966 976 public int[] getSignificantBits() { 977 if (!significantBitsSet) { 978 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam18")); 979 } 980 return (int[])significantBits.clone(); 981 } 982 983 986 public void unsetSignificantBits() { 987 significantBits = null; 988 significantBitsSet = false; 989 } 990 991 994 public boolean isSignificantBitsSet() { 995 return significantBitsSet; 996 } 997 998 1000 private int SRGBIntent; 1001 private boolean SRGBIntentSet = false; 1002 1003 1011 public void setSRGBIntent(int SRGBIntent) { 1012 this.SRGBIntent = SRGBIntent; 1013 SRGBIntentSet = true; 1014 } 1015 1016 1024 public int getSRGBIntent() { 1025 if (!SRGBIntentSet) { 1026 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam19")); 1027 } 1028 return SRGBIntent; 1029 } 1030 1031 1034 public void unsetSRGBIntent() { 1035 SRGBIntentSet = false; 1036 } 1037 1038 1041 public boolean isSRGBIntentSet() { 1042 return SRGBIntentSet; 1043 } 1044 1045 1047 private String [] text = null; 1048 private boolean textSet = false; 1049 1050 1057 public void setText(String [] text) { 1058 this.text = text; 1059 textSet = true; 1060 } 1061 1062 1071 public String [] getText() { 1072 if (!textSet) { 1073 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam20")); 1074 } 1075 return text; 1076 } 1077 1078 1081 public void unsetText() { 1082 text = null; 1083 textSet = false; 1084 } 1085 1086 1089 public boolean isTextSet() { 1090 return textSet; 1091 } 1092 1093 1095 private Date modificationTime; 1096 private boolean modificationTimeSet = false; 1097 1098 1106 public void setModificationTime(Date modificationTime) { 1107 this.modificationTime = modificationTime; 1108 modificationTimeSet = true; 1109 } 1110 1111 1119 public Date getModificationTime() { 1120 if (!modificationTimeSet) { 1121 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam21")); 1122 } 1123 return modificationTime; 1124 } 1125 1126 1129 public void unsetModificationTime() { 1130 modificationTime = null; 1131 modificationTimeSet = false; 1132 } 1133 1134 1137 public boolean isModificationTimeSet() { 1138 return modificationTimeSet; 1139 } 1140 1141 1143 boolean transparencySet = false; 1144 1145 1148 public void unsetTransparency() { 1149 transparencySet = false; 1150 } 1151 1152 1155 public boolean isTransparencySet() { 1156 return transparencySet; 1157 } 1158 1159 1161 private String [] zText = null; 1162 private boolean zTextSet = false; 1163 1164 1171 public void setCompressedText(String [] text) { 1172 this.zText = text; 1173 zTextSet = true; 1174 } 1175 1176 1187 public String [] getCompressedText() { 1188 if (!zTextSet) { 1189 throw new IllegalStateException (PropertyUtil.getString("PNGEncodeParam22")); 1190 } 1191 return zText; 1192 } 1193 1194 1197 public void unsetCompressedText() { 1198 zText = null; 1199 zTextSet = false; 1200 } 1201 1202 1205 public boolean isCompressedTextSet() { 1206 return zTextSet; 1207 } 1208 1209 1211 Vector chunkType = new Vector (); 1212 Vector chunkData = new Vector (); 1213 1214 1222 public synchronized void addPrivateChunk(String type, byte[] data) { 1223 chunkType.add(type); 1224 chunkData.add(data.clone()); 1225 } 1226 1227 1231 public synchronized int getNumPrivateChunks() { 1232 return chunkType.size(); 1233 } 1234 1235 1240 public synchronized String getPrivateChunkType(int index) { 1241 return (String )chunkType.elementAt(index); 1242 } 1243 1244 1250 public synchronized byte[] getPrivateChunkData(int index) { 1251 return (byte[])chunkData.elementAt(index); 1252 } 1253 1254 1259 public synchronized void removeUnsafeToCopyPrivateChunks() { 1260 Vector newChunkType = new Vector (); 1261 Vector newChunkData = new Vector (); 1262 1263 int len = getNumPrivateChunks(); 1264 for (int i = 0; i < len; i++) { 1265 String type = getPrivateChunkType(i); 1266 char lastChar = type.charAt(3); 1267 if (lastChar >= 'a' && lastChar <= 'z') { 1268 newChunkType.add(type); 1269 newChunkData.add(getPrivateChunkData(i)); 1270 } 1271 } 1272 1273 chunkType = newChunkType; 1274 chunkData = newChunkData; 1275 } 1276 1277 1280 public synchronized void removeAllPrivateChunks() { 1281 chunkType = new Vector (); 1282 chunkData = new Vector (); 1283 } 1284 1285 1288 private static final int abs(int x) { 1289 return (x < 0) ? -x : x; 1290 } 1291 1292 1297 public static final int paethPredictor(int a, int b, int c) { 1298 int p = a + b - c; 1299 int pa = abs(p - a); 1300 int pb = abs(p - b); 1301 int pc = abs(p - c); 1302 1303 if ((pa <= pb) && (pa <= pc)) { 1304 return a; 1305 } else if (pb <= pc) { 1306 return b; 1307 } else { 1308 return c; 1309 } 1310 } 1311 1312 1369 public int filterRow(byte[] currRow, 1370 byte[] prevRow, 1371 byte[][] scratchRows, 1372 int bytesPerRow, 1373 int bytesPerPixel) { 1374 1375 int [] badness = {0, 0, 0, 0, 0}; 1376 int curr, left, up, upleft, diff; 1377 int pa, pb, pc; 1378 for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { 1379 curr = currRow[i] & 0xff; 1380 left = currRow[i - bytesPerPixel] & 0xff; 1381 up = prevRow[i] & 0xff; 1382 upleft = prevRow[i - bytesPerPixel] & 0xff; 1383 1384 badness[0] += curr; 1386 1387 diff = curr - left; 1389 scratchRows[1][i] = (byte)diff; 1390 badness [1] += (diff>0)?diff:-diff; 1391 1392 diff = curr - up; 1394 scratchRows[2][i] = (byte)diff; 1395 badness [2] += (diff>=0)?diff:-diff; 1396 1397 diff = curr - ((left+up)>>1); 1399 scratchRows[3][i] = (byte)diff; 1400 badness [3] += (diff>=0)?diff:-diff; 1401 1402 1404 1420 pa = up -upleft; 1421 pb = left-upleft; 1422 if (pa<0) { 1423 if (pb<0) { 1424 if (pa >= pb) diff = curr-left; 1428 else 1429 diff = curr-up; 1430 } else { 1431 pc = pa+pb; 1433 pa=-pa; 1434 if (pa <= pb) if (pa <= pc) 1436 diff = curr-left; 1437 else 1438 diff = curr-upleft; 1439 else 1440 if (pb <= -pc) 1443 diff = curr-up; 1444 else 1445 diff = curr-upleft; 1446 } 1447 } else { 1448 if (pb<0) { 1449 pb =-pb; if (pa <= pb) { 1451 pc = pb-pa; 1453 if (pa <= pc) 1454 diff = curr-left; 1455 else if (pb == pc) 1456 diff = curr-up; 1459 else 1460 diff = curr-upleft; 1461 } else { 1462 pc = pa-pb; 1464 if (pb <= pc) 1465 diff = curr-up; 1466 else 1467 diff = curr-upleft; 1468 } 1469 } else { 1470 if (pa <= pb) 1472 diff = curr-left; 1473 else 1474 diff = curr-up; 1475 } 1476 } 1477 scratchRows[4][i] = (byte)diff; 1478 badness [4] += (diff>=0)?diff:-diff; 1479 } 1480 int filterType = 0; 1481 int minBadness = badness[0]; 1482 1483 for (int i = 1; i < 5; i++) { 1484 if (badness[i] < minBadness) { 1485 minBadness = badness[i]; 1486 filterType = i; 1487 } 1488 } 1489 1490 if (filterType == 0) { 1491 System.arraycopy(currRow, bytesPerPixel, 1492 scratchRows[0], bytesPerPixel, 1493 bytesPerRow); 1494 } 1495 1496 return filterType; 1497 } 1498} 1499 | Popular Tags |