105 private static final int VERSION_3_EXT_32_BIT = 15;
106
107 private static final int VERSION_4_1_BIT = 16;
108 private static final int VERSION_4_4_BIT = 17;
109 private static final int VERSION_4_8_BIT = 18;
110 private static final int VERSION_4_16_BIT = 19;
111 private static final int VERSION_4_24_BIT = 20;
112 private static final int VERSION_4_32_BIT = 21;
113
114 private static final int VERSION_3_XP_EMBEDDED = 22;
115 private static final int VERSION_3_EXT_EMBEDDED = 23;
116 private static final int VERSION_4_XP_EMBEDDED = 24;
117 private static final int VERSION_5_XP_EMBEDDED = 25;
118
119 // BMP variables
120 private long bitmapFileSize;
121 private long bitmapOffset;
122 private long bitmapStart;
123 private long compression;
124 private long imageSize;
125 private byte palette[];
126 private int imageType;
127 private int numBands;
128 private boolean isBottomUp;
129 private int bitsPerPixel;
130 private int redMask, greenMask, blueMask, alphaMask;
131
132 private SampleModel sampleModel, originalSampleModel;
133 private ColorModel colorModel, originalColorModel;
134
135 /** The input stream where reads from */
136 private ImageInputStream iis = null;
137
138 /** Indicates whether the header is read. */
139 private boolean gotHeader = false;
140
141 /** The original image width. */
142 private int width;
143
144 /** The original image height. */
145 private int height;
638 if (bitsPerPixel == 8) {
639 int[] bandOffsets = new int[numBands];
640 for (int i = 0; i < numBands; i++) {
641 bandOffsets[i] = numBands -1 -i;
642 }
643 sampleModel =
644 new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
645 width, height,
646 numBands,
647 numBands * width,
648 bandOffsets);
649 } else {
650 // 1 and 4 bit pixels can be stored in a packed format.
651 sampleModel =
652 new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
653 width, height,
654 bitsPerPixel);
655 }
656
657 // Create IndexColorModel from the palette.
658 byte r[], g[], b[];
659 if (imageType == VERSION_2_1_BIT ||
660 imageType == VERSION_2_4_BIT ||
661 imageType == VERSION_2_8_BIT) {
662
663
664 size = palette.length/3;
665
666 if (size > 256) {
667 size = 256;
668 }
669
670 int off;
671 r = new byte[(int)size];
672 g = new byte[(int)size];
673 b = new byte[(int)size];
674 for (int i=0; i<(int)size; i++) {
675 off = 3 * i;
676 b[i] = palette[off];
677 g[i] = palette[off+1];
678 r[i] = palette[off+2];
868 if (bi == null) {
869 if (sampleModel != null && colorModel != null) {
870 sampleModel =
871 sampleModel.createCompatibleSampleModel(destinationRegion.x +
872 destinationRegion.width,
873 destinationRegion.y +
874 destinationRegion.height);
875 if (seleBand)
876 sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
877 raster = Raster.createWritableRaster(sampleModel, new Point());
878 bi = new BufferedImage(colorModel, raster, false, null);
879 }
880 } else {
881 raster = bi.getWritableTile(0, 0);
882 sampleModel = bi.getSampleModel();
883 colorModel = bi.getColorModel();
884
885 noTransform &= destinationRegion.equals(raster.getBounds());
886 }
887
888 byte bdata[] = null; // buffer for byte data
889 short sdata[] = null; // buffer for short data
890 int idata[] = null; // buffer for int data
891
892 // the sampleModel can be null in case of embedded image
893 if (sampleModel != null) {
894 if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
895 bdata = ((DataBufferByte)raster.getDataBuffer()).getData();
896 else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
897 sdata = ((DataBufferUShort)raster.getDataBuffer()).getData();
898 else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
899 idata = ((DataBufferInt)raster.getDataBuffer()).getData();
900 }
901
902 iis.seek(bitmapStart);
903
904 // There should only be one tile.
905 switch(imageType) {
906
907 case VERSION_2_1_BIT:
908 // no compression
909 read1Bit(bdata);
910 break;
1351 i < destinationRegion.width; i++, m += 3 * scaleX) {
1352 //get the bit and assign to the data buffer of the raster
1353 int n = 3 * i + k;
1354 for (int b = 0; b < destBands.length; b++)
1355 bdata[n + destBands[b]] = buf[m + sourceBands[b]];
1356 }
1357
1358 k += isBottomUp ? -lineStride : lineStride;
1359 iis.skipBytes(skipLength);
1360 processImageUpdate(bi, 0, j,
1361 destinationRegion.width, 1, 1, 1,
1362 new int[]{0});
1363 processImageProgress(100.0F*j/destinationRegion.height);
1364 if (abortRequested()) {
1365 break;
1366 }
1367 }
1368 }
1369 }
1370
1371 private void read16Bit(short sdata[]) throws IOException {
1372 // Padding bytes at the end of each scanline
1373 // width * bitsPerPixel should be divisible by 32
1374 int padding = width * 2 % 4;
1375
1376 if ( padding != 0)
1377 padding = 4 - padding;
1378
1379 int lineLength = width + padding / 2;
1380
1381 if (noTransform) {
1382 int j = isBottomUp ? (height -1) * width : 0;
1383 for (int i=0; i<height; i++) {
1384 iis.readFully(sdata, j, width);
1385 iis.skipBytes(padding);
1386
1387 j += isBottomUp ? -width : width;
1388 processImageUpdate(bi, 0, i,
1389 destinationRegion.width, 1, 1, 1,
1390 new int[]{0});
1391 processImageProgress(100.0F * i/destinationRegion.height);
1417 iis.readFully(buf, 0, lineLength);
1418 for (int i = 0, m = sourceRegion.x;
1419 i < destinationRegion.width; i++, m += scaleX) {
1420 //get the bit and assign to the data buffer of the raster
1421 sdata[k + i] = buf[m];
1422 }
1423
1424 k += isBottomUp ? -lineStride : lineStride;
1425 iis.skipBytes(skipLength);
1426 processImageUpdate(bi, 0, j,
1427 destinationRegion.width, 1, 1, 1,
1428 new int[]{0});
1429 processImageProgress(100.0F*j/destinationRegion.height);
1430 if (abortRequested()) {
1431 break;
1432 }
1433 }
1434 }
1435 }
1436
1437 private void read32Bit(int idata[]) throws IOException {
1438 if (noTransform) {
1439 int j = isBottomUp ? (height -1) * width : 0;
1440
1441 for (int i=0; i<height; i++) {
1442 iis.readFully(idata, j, width);
1443 j += isBottomUp ? -width : width;
1444 processImageUpdate(bi, 0, i,
1445 destinationRegion.width, 1, 1, 1,
1446 new int[]{0});
1447 processImageProgress(100.0F * i/destinationRegion.height);
1448 if (abortRequested()) {
1449 break;
1450 }
1451 }
1452 } else {
1453 int[] buf = new int[width];
1454 int lineStride =
1455 ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1456
1457 if (isBottomUp) {
1473 iis.readFully(buf, 0, width);
1474 for (int i = 0, m = sourceRegion.x;
1475 i < destinationRegion.width; i++, m += scaleX) {
1476 //get the bit and assign to the data buffer of the raster
1477 idata[k + i] = buf[m];
1478 }
1479
1480 k += isBottomUp ? -lineStride : lineStride;
1481 iis.skipBytes(skipLength);
1482 processImageUpdate(bi, 0, j,
1483 destinationRegion.width, 1, 1, 1,
1484 new int[]{0});
1485 processImageProgress(100.0F*j/destinationRegion.height);
1486 if (abortRequested()) {
1487 break;
1488 }
1489 }
1490 }
1491 }
1492
1493 private void readRLE8(byte bdata[]) throws IOException {
1494 // If imageSize field is not provided, calculate it.
1495 int imSize = (int)imageSize;
1496 if (imSize == 0) {
1497 imSize = (int)(bitmapFileSize - bitmapOffset);
1498 }
1499
1500 int padding = 0;
1501 // If width is not 32 bit aligned, then while uncompressing each
1502 // scanline will have padding bytes, calculate the amount of padding
1503 int remainder = width % 4;
1504 if (remainder != 0) {
1505 padding = 4 - remainder;
1506 }
1507
1508 // Read till we have the whole image
1509 byte values[] = new byte[imSize];
1510 int bytesRead = 0;
1511 iis.readFully(values, 0, imSize);
1512
1513 // Since data is compressed, decompress it
1514 decodeRLE8(imSize, padding, values, bdata);
1515 }
1516
1517 private boolean copyRLE8ScanlineToDst(int lineNo,
1518 byte[] val,
1519 byte[] bdata) {
1520 // Return value
1521 boolean isSuccess = false;
1522
1523 // Reusing the code to copy 1 row of pixels or scanline to required
1524 // destination buffer.
1525 if (lineNo >= sourceRegion.y &&
1526 lineNo < sourceRegion.y + sourceRegion.height) {
1527 if (noTransform) {
1528 int pos = lineNo * width;
1529 for(int i = 0; i < width; i++)
1545 bdata[pos++] = val[i];
1546 processImageUpdate(bi, 0, currentLine,
1547 destinationRegion.width, 1, 1, 1,
1548 new int[]{0});
1549 isSuccess = true;
1550 }
1551 // Ensure to reset the scanline buffer once the copy is complete.
1552 for(int scIndex = 0; scIndex < width; scIndex++) {
1553 val[scIndex] = 0;
1554 }
1555 }
1556
1557 return isSuccess;
1558 }
1559
1560 private void decodeRLE8(int imSize,
1561 int padding,
1562 byte[] values,
1563 byte[] bdata) throws IOException {
1564
1565 byte val[] = new byte[width];
1566 int count = 0, l = 0;
1567 int value;
1568 boolean flag = false;
1569 int lineNo = isBottomUp ? height - 1 : 0;
1570 int finished = 0;
1571
1572 // Ensure image source has sufficient data to decode
1573 while ((count + 1) < imSize) {
1574 value = values[count++] & 0xff;
1575 if (value == 0) {
1576 switch(values[count++] & 0xff) {
1577
1578 case 0:
1579 // End-of-scanline marker
1580 // Copy the decoded scanline to destination
1581 if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
1582 finished++;
1583 }
1584 processImageProgress(100.0F * finished / destinationRegion.height);
1585 lineNo += isBottomUp ? -1 : 1;
1847 }
1848
1849 // When end is odd, the above for loop does not
1850 // increment count, so do it now.
1851 if ((end & 1) == 1) {
1852 count++;
1853 }
1854
1855 // Whenever end pixels can fit into odd number of bytes,
1856 // an extra padding byte will be present, so skip that.
1857 if ((((end + 1) / 2) & 1) == 1) {
1858 count++;
1859 }
1860 break;
1861 }
1862 } else {
1863 // Encoded mode
1864 // Ensure to check if the source index-count, does not
1865 // exceed the source image size
1866 if (count < imSize) {
1867 int alternate[] = { (values[count] & 0xf0) >> 4,
1868 values[count] & 0x0f };
1869 for (int i=0; (i < value) && (l < width); i++) {
1870 val[l++] = (byte)alternate[i & 1];
1871 }
1872 }
1873
1874 count++;
1875 }
1876
1877 // If End-of-RLE data, then exit the while loop
1878 if (flag) {
1879 break;
1880 }
1881 }
1882 }
1883
1884 /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
1885 * ImageIO-style plugin.
1886 *
1887 * @param bi The destination {@code BufferedImage}.
|
105 private static final int VERSION_3_EXT_32_BIT = 15;
106
107 private static final int VERSION_4_1_BIT = 16;
108 private static final int VERSION_4_4_BIT = 17;
109 private static final int VERSION_4_8_BIT = 18;
110 private static final int VERSION_4_16_BIT = 19;
111 private static final int VERSION_4_24_BIT = 20;
112 private static final int VERSION_4_32_BIT = 21;
113
114 private static final int VERSION_3_XP_EMBEDDED = 22;
115 private static final int VERSION_3_EXT_EMBEDDED = 23;
116 private static final int VERSION_4_XP_EMBEDDED = 24;
117 private static final int VERSION_5_XP_EMBEDDED = 25;
118
119 // BMP variables
120 private long bitmapFileSize;
121 private long bitmapOffset;
122 private long bitmapStart;
123 private long compression;
124 private long imageSize;
125 private byte[] palette;
126 private int imageType;
127 private int numBands;
128 private boolean isBottomUp;
129 private int bitsPerPixel;
130 private int redMask, greenMask, blueMask, alphaMask;
131
132 private SampleModel sampleModel, originalSampleModel;
133 private ColorModel colorModel, originalColorModel;
134
135 /** The input stream where reads from */
136 private ImageInputStream iis = null;
137
138 /** Indicates whether the header is read. */
139 private boolean gotHeader = false;
140
141 /** The original image width. */
142 private int width;
143
144 /** The original image height. */
145 private int height;
638 if (bitsPerPixel == 8) {
639 int[] bandOffsets = new int[numBands];
640 for (int i = 0; i < numBands; i++) {
641 bandOffsets[i] = numBands -1 -i;
642 }
643 sampleModel =
644 new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
645 width, height,
646 numBands,
647 numBands * width,
648 bandOffsets);
649 } else {
650 // 1 and 4 bit pixels can be stored in a packed format.
651 sampleModel =
652 new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
653 width, height,
654 bitsPerPixel);
655 }
656
657 // Create IndexColorModel from the palette.
658 byte[] r, g, b;
659 if (imageType == VERSION_2_1_BIT ||
660 imageType == VERSION_2_4_BIT ||
661 imageType == VERSION_2_8_BIT) {
662
663
664 size = palette.length/3;
665
666 if (size > 256) {
667 size = 256;
668 }
669
670 int off;
671 r = new byte[(int)size];
672 g = new byte[(int)size];
673 b = new byte[(int)size];
674 for (int i=0; i<(int)size; i++) {
675 off = 3 * i;
676 b[i] = palette[off];
677 g[i] = palette[off+1];
678 r[i] = palette[off+2];
868 if (bi == null) {
869 if (sampleModel != null && colorModel != null) {
870 sampleModel =
871 sampleModel.createCompatibleSampleModel(destinationRegion.x +
872 destinationRegion.width,
873 destinationRegion.y +
874 destinationRegion.height);
875 if (seleBand)
876 sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
877 raster = Raster.createWritableRaster(sampleModel, new Point());
878 bi = new BufferedImage(colorModel, raster, false, null);
879 }
880 } else {
881 raster = bi.getWritableTile(0, 0);
882 sampleModel = bi.getSampleModel();
883 colorModel = bi.getColorModel();
884
885 noTransform &= destinationRegion.equals(raster.getBounds());
886 }
887
888 byte[] bdata = null; // buffer for byte data
889 short[] sdata = null; // buffer for short data
890 int[] idata = null; // buffer for int data
891
892 // the sampleModel can be null in case of embedded image
893 if (sampleModel != null) {
894 if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
895 bdata = ((DataBufferByte)raster.getDataBuffer()).getData();
896 else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
897 sdata = ((DataBufferUShort)raster.getDataBuffer()).getData();
898 else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
899 idata = ((DataBufferInt)raster.getDataBuffer()).getData();
900 }
901
902 iis.seek(bitmapStart);
903
904 // There should only be one tile.
905 switch(imageType) {
906
907 case VERSION_2_1_BIT:
908 // no compression
909 read1Bit(bdata);
910 break;
1351 i < destinationRegion.width; i++, m += 3 * scaleX) {
1352 //get the bit and assign to the data buffer of the raster
1353 int n = 3 * i + k;
1354 for (int b = 0; b < destBands.length; b++)
1355 bdata[n + destBands[b]] = buf[m + sourceBands[b]];
1356 }
1357
1358 k += isBottomUp ? -lineStride : lineStride;
1359 iis.skipBytes(skipLength);
1360 processImageUpdate(bi, 0, j,
1361 destinationRegion.width, 1, 1, 1,
1362 new int[]{0});
1363 processImageProgress(100.0F*j/destinationRegion.height);
1364 if (abortRequested()) {
1365 break;
1366 }
1367 }
1368 }
1369 }
1370
1371 private void read16Bit(short[] sdata) throws IOException {
1372 // Padding bytes at the end of each scanline
1373 // width * bitsPerPixel should be divisible by 32
1374 int padding = width * 2 % 4;
1375
1376 if ( padding != 0)
1377 padding = 4 - padding;
1378
1379 int lineLength = width + padding / 2;
1380
1381 if (noTransform) {
1382 int j = isBottomUp ? (height -1) * width : 0;
1383 for (int i=0; i<height; i++) {
1384 iis.readFully(sdata, j, width);
1385 iis.skipBytes(padding);
1386
1387 j += isBottomUp ? -width : width;
1388 processImageUpdate(bi, 0, i,
1389 destinationRegion.width, 1, 1, 1,
1390 new int[]{0});
1391 processImageProgress(100.0F * i/destinationRegion.height);
1417 iis.readFully(buf, 0, lineLength);
1418 for (int i = 0, m = sourceRegion.x;
1419 i < destinationRegion.width; i++, m += scaleX) {
1420 //get the bit and assign to the data buffer of the raster
1421 sdata[k + i] = buf[m];
1422 }
1423
1424 k += isBottomUp ? -lineStride : lineStride;
1425 iis.skipBytes(skipLength);
1426 processImageUpdate(bi, 0, j,
1427 destinationRegion.width, 1, 1, 1,
1428 new int[]{0});
1429 processImageProgress(100.0F*j/destinationRegion.height);
1430 if (abortRequested()) {
1431 break;
1432 }
1433 }
1434 }
1435 }
1436
1437 private void read32Bit(int[] idata) throws IOException {
1438 if (noTransform) {
1439 int j = isBottomUp ? (height -1) * width : 0;
1440
1441 for (int i=0; i<height; i++) {
1442 iis.readFully(idata, j, width);
1443 j += isBottomUp ? -width : width;
1444 processImageUpdate(bi, 0, i,
1445 destinationRegion.width, 1, 1, 1,
1446 new int[]{0});
1447 processImageProgress(100.0F * i/destinationRegion.height);
1448 if (abortRequested()) {
1449 break;
1450 }
1451 }
1452 } else {
1453 int[] buf = new int[width];
1454 int lineStride =
1455 ((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
1456
1457 if (isBottomUp) {
1473 iis.readFully(buf, 0, width);
1474 for (int i = 0, m = sourceRegion.x;
1475 i < destinationRegion.width; i++, m += scaleX) {
1476 //get the bit and assign to the data buffer of the raster
1477 idata[k + i] = buf[m];
1478 }
1479
1480 k += isBottomUp ? -lineStride : lineStride;
1481 iis.skipBytes(skipLength);
1482 processImageUpdate(bi, 0, j,
1483 destinationRegion.width, 1, 1, 1,
1484 new int[]{0});
1485 processImageProgress(100.0F*j/destinationRegion.height);
1486 if (abortRequested()) {
1487 break;
1488 }
1489 }
1490 }
1491 }
1492
1493 private void readRLE8(byte[] bdata) throws IOException {
1494 // If imageSize field is not provided, calculate it.
1495 int imSize = (int)imageSize;
1496 if (imSize == 0) {
1497 imSize = (int)(bitmapFileSize - bitmapOffset);
1498 }
1499
1500 int padding = 0;
1501 // If width is not 32 bit aligned, then while uncompressing each
1502 // scanline will have padding bytes, calculate the amount of padding
1503 int remainder = width % 4;
1504 if (remainder != 0) {
1505 padding = 4 - remainder;
1506 }
1507
1508 // Read till we have the whole image
1509 byte[] values = new byte[imSize];
1510 int bytesRead = 0;
1511 iis.readFully(values, 0, imSize);
1512
1513 // Since data is compressed, decompress it
1514 decodeRLE8(imSize, padding, values, bdata);
1515 }
1516
1517 private boolean copyRLE8ScanlineToDst(int lineNo,
1518 byte[] val,
1519 byte[] bdata) {
1520 // Return value
1521 boolean isSuccess = false;
1522
1523 // Reusing the code to copy 1 row of pixels or scanline to required
1524 // destination buffer.
1525 if (lineNo >= sourceRegion.y &&
1526 lineNo < sourceRegion.y + sourceRegion.height) {
1527 if (noTransform) {
1528 int pos = lineNo * width;
1529 for(int i = 0; i < width; i++)
1545 bdata[pos++] = val[i];
1546 processImageUpdate(bi, 0, currentLine,
1547 destinationRegion.width, 1, 1, 1,
1548 new int[]{0});
1549 isSuccess = true;
1550 }
1551 // Ensure to reset the scanline buffer once the copy is complete.
1552 for(int scIndex = 0; scIndex < width; scIndex++) {
1553 val[scIndex] = 0;
1554 }
1555 }
1556
1557 return isSuccess;
1558 }
1559
1560 private void decodeRLE8(int imSize,
1561 int padding,
1562 byte[] values,
1563 byte[] bdata) throws IOException {
1564
1565 byte[] val = new byte[width];
1566 int count = 0, l = 0;
1567 int value;
1568 boolean flag = false;
1569 int lineNo = isBottomUp ? height - 1 : 0;
1570 int finished = 0;
1571
1572 // Ensure image source has sufficient data to decode
1573 while ((count + 1) < imSize) {
1574 value = values[count++] & 0xff;
1575 if (value == 0) {
1576 switch(values[count++] & 0xff) {
1577
1578 case 0:
1579 // End-of-scanline marker
1580 // Copy the decoded scanline to destination
1581 if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
1582 finished++;
1583 }
1584 processImageProgress(100.0F * finished / destinationRegion.height);
1585 lineNo += isBottomUp ? -1 : 1;
1847 }
1848
1849 // When end is odd, the above for loop does not
1850 // increment count, so do it now.
1851 if ((end & 1) == 1) {
1852 count++;
1853 }
1854
1855 // Whenever end pixels can fit into odd number of bytes,
1856 // an extra padding byte will be present, so skip that.
1857 if ((((end + 1) / 2) & 1) == 1) {
1858 count++;
1859 }
1860 break;
1861 }
1862 } else {
1863 // Encoded mode
1864 // Ensure to check if the source index-count, does not
1865 // exceed the source image size
1866 if (count < imSize) {
1867 int[] alternate = { (values[count] & 0xf0) >> 4,
1868 values[count] & 0x0f };
1869 for (int i=0; (i < value) && (l < width); i++) {
1870 val[l++] = (byte)alternate[i & 1];
1871 }
1872 }
1873
1874 count++;
1875 }
1876
1877 // If End-of-RLE data, then exit the while loop
1878 if (flag) {
1879 break;
1880 }
1881 }
1882 }
1883
1884 /** Decodes the jpeg/png image embedded in the bitmap using any jpeg
1885 * ImageIO-style plugin.
1886 *
1887 * @param bi The destination {@code BufferedImage}.
|