127
128
private int maxOpacity;
129
private int[] significantBits = null;
130
private int[] significantBits;
131
132
// Parameter information
133
134
// If true, the user wants destination alpha where applicable.
134
private boolean suppressAlpha = false;
135
private boolean suppressAlpha;
136
137
// If true, perform palette lookup internally
137
private boolean expandPalette = false;
138
private boolean expandPalette;
139
140
// If true, output < 8 bit gray images in 8 bit components format
140
private boolean output8BitGray = false;
141
private boolean output8BitGray;
142
143
// Create an alpha channel in the destination color model.
143
private boolean outputHasAlphaPalette = false;
144
private boolean outputHasAlphaPalette;
145
146
// Perform gamma correction on the image
146
private boolean performGammaCorrection = false;
147
private boolean performGammaCorrection;
148
149
// Expand GA to GGGA for compatbility with Java2D
149
private boolean expandGrayAlpha = false;
150
private boolean expandGrayAlpha;
151
152
// Produce an instance of PNGEncodeParam
152
private boolean generateEncodeParam = false;
153
private boolean generateEncodeParam;
154
155
// PNGDecodeParam controlling decode process
155
private PNGDecodeParam decodeParam = null;
156
private PNGDecodeParam decodeParam;
157
158
// PNGEncodeParam to store file details in
158
private PNGEncodeParam encodeParam = null;
159
private PNGEncodeParam encodeParam;
160
161
private boolean emitProperties = true;
162
private float fileGamma = 45455/100000.0F;
163
private float fileGamma = 45455 / 100000.0F;
164
165
private float userExponent = 1.0F;
166
167
private float displayExponent = 2.2F;
168
private float[] chromaticity = null;
169
private float[] chromaticity;
170
171
private int sRGBRenderingIntent = -1;
242
243
private WritableRaster theTile;
244
private int[] gammaLut = null;
245
private int[] gammaLut;
246
247
private void initGammaLut(int bits) {
247
double exp = (double)userExponent/(fileGamma*displayExponent);
248
double exp = (double)userExponent / (fileGamma * displayExponent);
248
249
int numSamples = 1 << bits;
249
250
int maxOutSample = (bits == 16) ? 65535 : 255;
251
252
gammaLut = new int[numSamples];
252
253
for (int i = 0; i < numSamples; i++) {
253
double gbright = (double)i/(numSamples - 1);
254
double gbright = (double)i / (numSamples - 1);
254
255
double gamma = Math.pow(gbright, exp);
255
int igamma = (int)(gamma*maxOutSample + 0.5);
256
int igamma = (int)(gamma * maxOutSample + 0.5);
256
257
if (igamma > maxOutSample) {
257
258
igamma = maxOutSample;
344
345
streamVec.add(new ByteArrayInputStream(chunk.getData()));
345
346
} else if (chunkType.equals(PNGChunk.ChunkType.IEND.name())) {
346
347
chunk = PNGChunk.readChunk(distream);
347
parse_IEND_chunk(chunk);
349
parse_IEND_chunk(chunk);
350
} catch (Exception e) {
352
String msg = PropertyUtil.getString("PNGImageDecoder2");
353
throw new RuntimeException(msg);
348
355
break; // fall through to the bottom
349
356
} else if (chunkType.equals(PNGChunk.ChunkType.bKGD.name())) {
350
357
chunk = PNGChunk.readChunk(distream);
394
401
if (emitProperties) {
395
402
String key = "chunk_" + chunkIndex++ + ':' + type;
396
properties.put(key.toLowerCase(), data);
403
properties.put(key.toLowerCase(Locale.getDefault()), data);
399
} catch (Exception e) {
401
String msg = PropertyUtil.getString("PNGImageDecoder2");
402
throw new RuntimeException(msg);
406
// } catch (Exception e) {
407
// e.printStackTrace();
408
// String msg = PropertyUtil.getString("PNGImageDecoder2");
409
// throw new RuntimeException(msg);
406
413
// Final post-processing
424
431
bitDepth = chunk.getInt1(8);
426
if ((bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) &&
427
(bitDepth != 8) && (bitDepth != 16)) {
433
if ((bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4)
434
&& (bitDepth != 8) && (bitDepth != 16)) {
428
435
// Error -- bad bit depth
429
436
String msg = PropertyUtil.getString("PNGImageDecoder3");
430
437
throw new RuntimeException(msg);
432
439
maxOpacity = (1 << bitDepth) - 1;
434
441
colorType = chunk.getInt1(9);
435
if ((colorType != PNG_COLOR_GRAY) &&
436
(colorType != PNG_COLOR_RGB) &&
437
(colorType != PNG_COLOR_PALETTE) &&
438
(colorType != PNG_COLOR_GRAY_ALPHA) &&
439
(colorType != PNG_COLOR_RGB_ALPHA)) {
442
if ((colorType != PNG_COLOR_GRAY)
443
&& (colorType != PNG_COLOR_RGB)
444
&& (colorType != PNG_COLOR_PALETTE)
445
&& (colorType != PNG_COLOR_GRAY_ALPHA)
446
&& (colorType != PNG_COLOR_RGB_ALPHA)) {
440
447
System.out.println(PropertyUtil.getString("PNGImageDecoder4"));
471
478
if (generateEncodeParam) {
472
479
if (colorType == PNG_COLOR_PALETTE) {
473
480
encodeParam = new PNGEncodeParam.Palette();
474
} else if (colorType == PNG_COLOR_GRAY ||
475
colorType == PNG_COLOR_GRAY_ALPHA) {
481
} else if (colorType == PNG_COLOR_GRAY
482
|| colorType == PNG_COLOR_GRAY_ALPHA) {
476
483
encodeParam = new PNGEncodeParam.Gray();
478
485
encodeParam = new PNGEncodeParam.RGB();
484
491
encodeParam.setBitDepth(bitDepth);
486
493
if (emitProperties) {
487
properties.put("bit_depth", new Integer(bitDepth));
494
properties.put("bit_depth", bitDepth);
490
497
if (performGammaCorrection) {
491
498
// Assume file gamma is 1/2.2 unless we get a gAMA chunk
492
float gamma = (1.0F/2.2F)*(displayExponent/userExponent);
499
float gamma = (1.0F / 2.2F) * (displayExponent / userExponent);
493
500
if (encodeParam != null) {
494
501
encodeParam.setGamma(gamma);
496
503
if (emitProperties) {
497
properties.put("gamma", new Float(gamma));
504
properties.put("gamma", gamma);
614
621
private void parse_IEND_chunk(PNGChunk chunk) throws Exception {
615
622
// Store text strings
616
623
int textLen = textKeys.size();
617
String[] textArray = new String[2*textLen];
624
String[] textArray = new String[2 * textLen];
618
625
for (int i = 0; i < textLen; i++) {
619
626
String key = (String)textKeys.get(i);
620
627
String val = (String)textStrings.get(i);
621
textArray[2*i] = key;
622
textArray[2*i + 1] = val;
628
textArray[2 * i] = key;
629
textArray[2 * i + 1] = val;
623
630
if (emitProperties) {
624
631
String uniqueKey = "text_" + i + ':' + key;
625
properties.put(uniqueKey.toLowerCase(), val);
632
properties.put(uniqueKey.toLowerCase(Locale.getDefault()), val);
628
635
if (encodeParam != null) {
632
639
// Store compressed text strings
633
640
int ztextLen = ztextKeys.size();
634
String[] ztextArray = new String[2*ztextLen];
641
String[] ztextArray = new String[2 * ztextLen];
635
642
for (int i = 0; i < ztextLen; i++) {
636
643
String key = (String)ztextKeys.get(i);
637
644
String val = (String)ztextStrings.get(i);
638
ztextArray[2*i] = key;
639
ztextArray[2*i + 1] = val;
645
ztextArray[2 * i] = key;
646
ztextArray[2 * i + 1] = val;
640
647
if (emitProperties) {
641
648
String uniqueKey = "ztext_" + i + ':' + key;
642
properties.put(uniqueKey.toLowerCase(), val);
649
properties.put(uniqueKey.toLowerCase(Locale.getDefault()), val);
645
652
if (encodeParam != null) {
656
663
// Create an empty WritableRaster
657
664
int depth = bitDepth;
658
if ((colorType == PNG_COLOR_GRAY) &&
659
(bitDepth < 8) && output8BitGray) {
665
if ((colorType == PNG_COLOR_GRAY)
666
&& (bitDepth < 8) && output8BitGray) {
662
669
if ((colorType == PNG_COLOR_PALETTE) && expandPalette) {
665
int bytesPerRow = (outputBands*width*depth + 7)/8;
672
int bytesPerRow = (outputBands * width * depth + 7) / 8;
666
673
int scanlineStride =
667
(depth == 16) ? (bytesPerRow/2) : bytesPerRow;
674
(depth == 16) ? (bytesPerRow / 2) : bytesPerRow;
669
676
theTile = createRaster(width, height, outputBands,
958
964
chromaticity = new float[8];
959
chromaticity[0] = chunk.getInt4(0)/100000.0F;
960
chromaticity[1] = chunk.getInt4(4)/100000.0F;
961
chromaticity[2] = chunk.getInt4(8)/100000.0F;
962
chromaticity[3] = chunk.getInt4(12)/100000.0F;
963
chromaticity[4] = chunk.getInt4(16)/100000.0F;
964
chromaticity[5] = chunk.getInt4(20)/100000.0F;
965
chromaticity[6] = chunk.getInt4(24)/100000.0F;
966
chromaticity[7] = chunk.getInt4(28)/100000.0F;
965
chromaticity[0] = chunk.getInt4(0) / 100000.0F;
966
chromaticity[1] = chunk.getInt4(4) / 100000.0F;
967
chromaticity[2] = chunk.getInt4(8) / 100000.0F;
968
chromaticity[3] = chunk.getInt4(12) / 100000.0F;
969
chromaticity[4] = chunk.getInt4(16) / 100000.0F;
970
chromaticity[5] = chunk.getInt4(20) / 100000.0F;
971
chromaticity[6] = chunk.getInt4(24) / 100000.0F;
972
chromaticity[7] = chunk.getInt4(28) / 100000.0F;
968
974
if (encodeParam != null) {
969
975
encodeParam.setChromaticity(chromaticity);
971
977
if (emitProperties) {
972
properties.put("white_point_x", new Float(chromaticity[0]));
973
properties.put("white_point_y", new Float(chromaticity[1]));
974
properties.put("red_x", new Float(chromaticity[2]));
975
properties.put("red_y", new Float(chromaticity[3]));
976
properties.put("green_x", new Float(chromaticity[4]));
977
properties.put("green_y", new Float(chromaticity[5]));
978
properties.put("blue_x", new Float(chromaticity[6]));
979
properties.put("blue_y", new Float(chromaticity[7]));
978
properties.put("white_point_x", chromaticity[0]);
979
properties.put("white_point_y", chromaticity[1]);
980
properties.put("red_x", chromaticity[2]);
981
properties.put("red_y", chromaticity[3]);
982
properties.put("green_x", chromaticity[4]);
983
properties.put("green_y", chromaticity[5]);
984
properties.put("blue_x", chromaticity[6]);
985
properties.put("blue_y", chromaticity[7]);
989
fileGamma = chunk.getInt4(0)/100000.0F;
995
fileGamma = chunk.getInt4(0) / 100000.0F;
992
performGammaCorrection ? displayExponent/userExponent : 1.0F;
998
performGammaCorrection ? displayExponent / userExponent : 1.0F;
993
999
if (encodeParam != null) {
994
encodeParam.setGamma(fileGamma*exp);
1000
encodeParam.setGamma(fileGamma * exp);
996
1002
if (emitProperties) {
997
properties.put("gamma", new Float(fileGamma*exp));
1003
properties.put("gamma", fileGamma * exp);
1036
1042
unitSpecifier);
1038
1044
if (emitProperties) {
1039
properties.put("x_pixels_per_unit", new Integer(xPixelsPerUnit));
1040
properties.put("y_pixels_per_unit", new Integer(yPixelsPerUnit));
1045
properties.put("x_pixels_per_unit", xPixelsPerUnit);
1046
properties.put("y_pixels_per_unit", yPixelsPerUnit);
1041
1047
properties.put("pixel_aspect_ratio",
1042
new Float((float)xPixelsPerUnit/yPixelsPerUnit));
1048
(float) xPixelsPerUnit / yPixelsPerUnit);
1043
1049
if (unitSpecifier == 1) {
1044
1050
properties.put("pixel_units", "Meters");
1045
1051
} else if (unitSpecifier != 0) {
1082
1088
// The presence of an sRGB chunk implies particular
1083
1089
// settings for gamma and chroma.
1084
fileGamma = 45455/100000.0F;
1090
fileGamma = 45455 / 100000.0F;
1086
1092
chromaticity = new float[8];
1087
chromaticity[0] = 31270/10000.0F;
1088
chromaticity[1] = 32900/10000.0F;
1089
chromaticity[2] = 64000/10000.0F;
1090
chromaticity[3] = 33000/10000.0F;
1091
chromaticity[4] = 30000/10000.0F;
1092
chromaticity[5] = 60000/10000.0F;
1093
chromaticity[6] = 15000/10000.0F;
1094
chromaticity[7] = 6000/10000.0F;
1093
chromaticity[0] = 31270 / 10000.0F;
1094
chromaticity[1] = 32900 / 10000.0F;
1095
chromaticity[2] = 64000 / 10000.0F;
1096
chromaticity[3] = 33000 / 10000.0F;
1097
chromaticity[4] = 30000 / 10000.0F;
1098
chromaticity[5] = 60000 / 10000.0F;
1099
chromaticity[6] = 15000 / 10000.0F;
1100
chromaticity[7] = 6000 / 10000.0F;
1096
1102
if (performGammaCorrection) {
1097
1103
// File gamma is 1/2.2
1098
float gamma = fileGamma*(displayExponent/userExponent);
1104
float gamma = fileGamma * (displayExponent / userExponent);
1099
1105
if (encodeParam != null) {
1100
1106
encodeParam.setGamma(gamma);
1101
1107
encodeParam.setChromaticity(chromaticity);
1103
1109
if (emitProperties) {
1104
properties.put("gamma", new Float(gamma));
1105
properties.put("white_point_x", new Float(chromaticity[0]));
1106
properties.put("white_point_y", new Float(chromaticity[1]));
1107
properties.put("red_x", new Float(chromaticity[2]));
1108
properties.put("red_y", new Float(chromaticity[3]));
1109
properties.put("green_x", new Float(chromaticity[4]));
1110
properties.put("green_y", new Float(chromaticity[5]));
1111
properties.put("blue_x", new Float(chromaticity[6]));
1112
properties.put("blue_y", new Float(chromaticity[7]));
1110
properties.put("gamma", gamma);
1111
properties.put("white_point_x", chromaticity[0]);
1112
properties.put("white_point_y", chromaticity[1]);
1113
properties.put("red_x", chromaticity[2]);
1114
properties.put("red_y", chromaticity[3]);
1115
properties.put("green_x", chromaticity[4]);
1116
properties.put("green_y", chromaticity[5]);
1117
properties.put("blue_x", chromaticity[6]);
1118
properties.put("blue_y", chromaticity[7]);
1221
1226
rgbTrans[0] = redTransparentAlpha;
1222
1227
rgbTrans[1] = greenTransparentAlpha;
1223
1228
rgbTrans[2] = blueTransparentAlpha;
1224
((PNGEncodeParam.RGB)encodeParam).
1225
setTransparentRGB(rgbTrans);
1229
((PNGEncodeParam.RGB)encodeParam).setTransparentRGB(rgbTrans);
1228
} else if (colorType == PNG_COLOR_GRAY_ALPHA ||
1229
colorType == PNG_COLOR_RGB_ALPHA) {
1232
} else if (colorType == PNG_COLOR_GRAY_ALPHA
1233
|| colorType == PNG_COLOR_RGB_ALPHA) {
1230
1234
// Error -- GA or RGBA image can't have a tRNS chunk.
1231
1235
String msg = PropertyUtil.getString("PNGImageDecoder15");
1232
1236
throw new RuntimeException(msg);
1271
1275
WritableRaster ras = null;
1272
1276
Point origin = new Point(0, 0);
1273
1277
if ((bitDepth < 8) && (bands == 1)) {
1274
dataBuffer = new DataBufferByte(height*scanlineStride);
1278
dataBuffer = new DataBufferByte(height * scanlineStride);
1275
1279
ras = Raster.createPackedRaster(dataBuffer,
1279
1283
} else if (bitDepth <= 8) {
1280
dataBuffer = new DataBufferByte(height*scanlineStride);
1284
dataBuffer = new DataBufferByte(height * scanlineStride);
1281
1285
ras = Raster.createInterleavedRaster(dataBuffer,
1283
1287
scanlineStride,
1323
1327
private static void decodeAverageFilter(byte[] curr, byte[] prev,
1324
1328
int count, int bpp) {
1325
int raw, priorPixel, priorRow;
1327
1333
for (int i = 0; i < bpp; i++) {
1328
1334
raw = curr[i] & 0xff;
1329
1335
priorRow = prev[i] & 0xff;
1331
curr[i] = (byte)(raw + priorRow/2);
1337
curr[i] = (byte)(raw + priorRow / 2);
1334
1340
for (int i = bpp; i < count; i++) {
1336
1342
priorPixel = curr[i - bpp] & 0xff;
1337
1343
priorRow = prev[i] & 0xff;
1339
curr[i] = (byte)(raw + (priorPixel + priorRow)/2);
1345
curr[i] = (byte)(raw + (priorPixel + priorRow) / 2);
1343
1349
private static void decodePaethFilter(byte[] curr, byte[] prev,
1344
1350
int count, int bpp) {
1345
int raw, priorPixel, priorRow, priorRowPixel;
1347
1356
for (int i = 0; i < bpp; i++) {
1348
1357
raw = curr[i] & 0xff;
1366
1375
private void processPixels(int process,
1367
1376
Raster src, WritableRaster dst,
1368
1377
int xOffset, int step, int y, int width) {
1371
1381
// Create an array suitable for holding one pixel
1372
1382
int[] ps = src.getPixel(0, 0, (int[])null);
1710
1721
if (!useInterlacing) {
1711
1722
decodePass(theTile, 0, 0, 1, 1, width, height);
1713
decodePass(theTile, 0, 0, 8, 8, (width + 7)/8, (height + 7)/8);
1714
decodePass(theTile, 4, 0, 8, 8, (width + 3)/8, (height + 7)/8);
1715
decodePass(theTile, 0, 4, 4, 8, (width + 3)/4, (height + 3)/8);
1716
decodePass(theTile, 2, 0, 4, 4, (width + 1)/4, (height + 3)/4);
1717
decodePass(theTile, 0, 2, 2, 4, (width + 1)/2, (height + 1)/4);
1718
decodePass(theTile, 1, 0, 2, 2, width/2, (height + 1)/2);
1719
decodePass(theTile, 0, 1, 1, 2, width, height/2);
1724
decodePass(theTile, 0, 0, 8, 8, (width + 7) / 8, (height + 7) / 8);
1725
decodePass(theTile, 4, 0, 8, 8, (width + 3) / 8, (height + 7) / 8);
1726
decodePass(theTile, 0, 4, 4, 8, (width + 3) / 4, (height + 3) / 8);
1727
decodePass(theTile, 2, 0, 4, 4, (width + 1) / 4, (height + 3) / 4);
1728
decodePass(theTile, 0, 2, 2, 4, (width + 1) / 2, (height + 1) / 4);
1729
decodePass(theTile, 1, 0, 2, 2, width / 2, (height + 1) / 2);
1730
decodePass(theTile, 0, 1, 1, 2, width, height / 2);