BMPImageDecoder.java
上传用户:btjssb159
上传日期:2018-01-04
资源大小:241k
文件大小:33k
源码类别:

DNA

开发平台:

Java

  1. /*
  2.  * Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without 
  5.  * modification, are permitted provided that the following conditions are met:
  6.  * 
  7.  * -Redistributions of source code must retain the above copyright notice, this 
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * -Redistribution in binary form must reproduct the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  * 
  14.  * Neither the name of Sun Microsystems, Inc. or the names of contributors may
  15.  * be used to endorse or promote products derived from this software without
  16.  * specific prior written permission.
  17.  * 
  18.  * This software is provided "AS IS," without a warranty of any kind. ALL
  19.  * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
  20.  * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
  21.  * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
  22.  * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
  23.  * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
  24.  * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
  25.  * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
  26.  * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
  27.  * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGES.
  29.  * 
  30.  * You acknowledge that Software is not designed,licensed or intended for use in 
  31.  * the design, construction, operation or maintenance of any nuclear facility.
  32.  */
  33. import java.awt.Point;
  34. import java.awt.Transparency;
  35. import java.awt.color.ColorSpace;
  36. import java.awt.image.DataBuffer;
  37. import java.awt.image.DataBufferByte;
  38. import java.awt.image.Raster;
  39. import java.awt.image.RenderedImage;
  40. import java.awt.image.WritableRaster;
  41. import java.awt.image.IndexColorModel;
  42. import java.awt.image.MultiPixelPackedSampleModel;
  43. import java.io.IOException;
  44. import java.io.BufferedInputStream;
  45. import java.io.InputStream;
  46. import java.util.Hashtable;
  47. import java.util.Enumeration;
  48. /**
  49.  */
  50. public class BMPImageDecoder extends ImageDecoderImpl {
  51.     public BMPImageDecoder(InputStream input, ImageDecodeParam param) {
  52.         super(input, param);
  53.     }
  54.     public RenderedImage decodeAsRenderedImage(int page) throws IOException {
  55.         if (page != 0) {
  56.             throw new IOException(JaiI18N.getString("BMPImageDecoder8"));
  57.         }
  58.         return new BMPImage(input);
  59.     }
  60. }
  61. class BMPImage extends SimpleRenderedImage {
  62.     
  63.     // BMP variables
  64.     private BufferedInputStream inputStream;
  65.     private long bitmapFileSize;
  66.     private long bitmapOffset;
  67.     private long compression;
  68.     private long imageSize;
  69.     private byte palette[];
  70.     private int imageType;
  71.     private int numBands;
  72.     private boolean isBottomUp;
  73.     private int bitsPerPixel;
  74.     private int redMask, greenMask, blueMask;    
  75.     
  76.     // BMP Image types
  77.     private static final int VERSION_2_1_BIT = 0;
  78.     private static final int VERSION_2_4_BIT = 1;
  79.     private static final int VERSION_2_8_BIT = 2;
  80.     private static final int VERSION_2_24_BIT = 3;
  81.     private static final int VERSION_3_1_BIT = 4;
  82.     private static final int VERSION_3_4_BIT = 5;
  83.     private static final int VERSION_3_8_BIT = 6;
  84.     private static final int VERSION_3_24_BIT = 7;
  85.     private static final int VERSION_3_NT_16_BIT = 8;
  86.     private static final int VERSION_3_NT_32_BIT = 9;
  87.     private static final int VERSION_4_1_BIT = 10;
  88.     private static final int VERSION_4_4_BIT = 11;
  89.     private static final int VERSION_4_8_BIT = 12;
  90.     private static final int VERSION_4_16_BIT = 13;
  91.     private static final int VERSION_4_24_BIT = 14;
  92.     private static final int VERSION_4_32_BIT = 15;
  93.     // Color space types
  94.     private static final int LCS_CALIBRATED_RGB = 0;
  95.     private static final int LCS_sRGB = 1;
  96.     private static final int LCS_CMYK = 2;
  97.     // Compression Types
  98.     private static final int BI_RGB = 0;
  99.     private static final int BI_RLE8 = 1;
  100.     private static final int BI_RLE4 = 2;
  101.     private static final int BI_BITFIELDS = 3;
  102.     // Shifts for each color component
  103.     private int blueBits, greenBits, redBits;
  104.     private WritableRaster theTile = null;
  105.     /**
  106.      * Constructor for BMPImage
  107.      *
  108.      * @param stream 
  109.      */
  110.     public BMPImage(InputStream stream) {
  111. if (stream instanceof BufferedInputStream) {
  112.     inputStream = (BufferedInputStream)stream;
  113. } else {
  114.     inputStream = new BufferedInputStream(stream);
  115. }
  116. try {
  117.     // Start File Header
  118.     if (!(readUnsignedByte(inputStream) == 'B' &&
  119.     readUnsignedByte(inputStream) == 'M')) {
  120. throw new
  121.     RuntimeException(JaiI18N.getString("BMPImageDecoder0"));
  122.     }
  123.     
  124.     // Read file size
  125.     bitmapFileSize = readDWord(inputStream);
  126.     // Read the two reserved fields
  127.     readWord(inputStream);
  128.     readWord(inputStream);
  129.     
  130.     // Offset to the bitmap from the beginning
  131.     bitmapOffset = readDWord(inputStream);
  132.     
  133.     // End File Header
  134.     
  135.     // Start BitmapCoreHeader
  136.     long size = readDWord(inputStream);
  137.     if (size == 12) {
  138. width = readWord(inputStream);
  139. height = readWord(inputStream);
  140.     } else {
  141. width = readLong(inputStream);
  142. height = readLong(inputStream);
  143.     }
  144.     int planes = readWord(inputStream);
  145.     bitsPerPixel = readWord(inputStream);
  146.     properties.put("color_planes", new Integer(planes));
  147.     properties.put("bits_per_pixel", new Integer(bitsPerPixel));
  148.     
  149.     // As BMP always has 3 rgb bands, except for Version 5,
  150.     // which is bgra
  151.     numBands = 3;
  152.     
  153.     if (size == 12) {
  154. // Windows 2.x and OS/2 1.x
  155. properties.put("bmp_version", "BMP v. 2.x");
  156. // Classify the image type
  157. if (bitsPerPixel == 1) {
  158.     imageType = VERSION_2_1_BIT;
  159. } else if (bitsPerPixel == 4) {
  160.     imageType = VERSION_2_4_BIT;
  161. } else if (bitsPerPixel == 8) {
  162.     imageType = VERSION_2_8_BIT;
  163. } else if (bitsPerPixel == 24) {
  164.     imageType = VERSION_2_24_BIT;
  165. }
  166. // Read in the palette
  167. int numberOfEntries = (int)((bitmapOffset-14-size) / 3);
  168. int sizeOfPalette = numberOfEntries*3;
  169. palette = new byte[sizeOfPalette];
  170. inputStream.read(palette, 0, sizeOfPalette);
  171. properties.put("palette", palette);
  172.     } else {
  173. compression = readDWord(inputStream);
  174. imageSize = readDWord(inputStream);
  175. long xPelsPerMeter = readLong(inputStream);
  176. long yPelsPerMeter = readLong(inputStream);
  177. long colorsUsed = readDWord(inputStream);
  178. long colorsImportant = readDWord(inputStream);
  179. switch((int)compression) {
  180. case BI_RGB:
  181.     properties.put("compression", "BI_RGB");
  182.     break;
  183. case BI_RLE8:
  184.     properties.put("compression", "BI_RLE8");
  185.     break;
  186.     
  187. case BI_RLE4:
  188.     properties.put("compression", "BI_RLE4");
  189.     break;
  190.     
  191. case BI_BITFIELDS:
  192.     properties.put("compression", "BI_BITFIELDS");
  193.     break;
  194. }
  195. properties.put("x_pixels_per_meter", new Long(xPelsPerMeter));
  196. properties.put("y_pixels_per_meter", new Long(yPelsPerMeter));
  197. properties.put("colors_used", new Long(colorsUsed));
  198. properties.put("colors_important", new Long(colorsImportant));
  199. if (size == 40) {
  200.     // Windows 3.x and Windows NT     
  201.     switch((int)compression) {
  202.     
  203.     case BI_RGB:  // No compression
  204.     case BI_RLE8:  // 8-bit RLE compression
  205.     case BI_RLE4:  // 4-bit RLE compression
  206. // Read in the palette
  207. int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  208. int sizeOfPalette = numberOfEntries*4;
  209. palette = new byte[sizeOfPalette];
  210. inputStream.read(palette, 0, sizeOfPalette);
  211. properties.put("palette", palette);
  212. if (bitsPerPixel == 1) {
  213.     imageType = VERSION_3_1_BIT;
  214. } else if (bitsPerPixel == 4) {
  215.     imageType = VERSION_3_4_BIT;
  216. } else if (bitsPerPixel == 8) {
  217.     imageType = VERSION_3_8_BIT;
  218. } else if (bitsPerPixel == 24) {
  219.     imageType = VERSION_3_24_BIT;
  220. } else if (bitsPerPixel == 16) {
  221.     imageType = VERSION_3_NT_16_BIT;
  222.     redMask = 0x7C00;
  223.     greenMask = 0x3E0;
  224.     blueMask = 0x1F;
  225.     properties.put("red_mask", new Integer(redMask));
  226.     properties.put("green_mask", new Integer(greenMask));
  227.     properties.put("blue_mask", new Integer(blueMask));
  228.     computeShifts();
  229. } else if (bitsPerPixel == 32) {
  230.     imageType = VERSION_3_NT_32_BIT;
  231.     redMask   = 0x00FF0000;
  232.     greenMask = 0x0000FF00;
  233.     blueMask  = 0x000000FF;
  234.     properties.put("red_mask", new Integer(redMask));
  235.     properties.put("green_mask", new Integer(greenMask));
  236.     properties.put("blue_mask", new Integer(blueMask));
  237.     computeShifts();
  238. }
  239. properties.put("bmp_version", "BMP v. 3.x");
  240. break;
  241.     
  242.     case BI_BITFIELDS:
  243. if (bitsPerPixel == 16) {
  244.     imageType = VERSION_3_NT_16_BIT;
  245. } else if (bitsPerPixel == 32) {
  246.     imageType = VERSION_3_NT_32_BIT;
  247. }
  248. // BitsField encoding
  249. redMask = (int)readDWord(inputStream);
  250. greenMask = (int)readDWord(inputStream);
  251. blueMask = (int)readDWord(inputStream);
  252. properties.put("red_mask", new Integer(redMask));
  253. properties.put("green_mask", new Integer(greenMask));
  254. properties.put("blue_mask", new Integer(blueMask));
  255. computeShifts();
  256. if (colorsUsed != 0) {
  257.     // there is a palette
  258.     sizeOfPalette = (int)colorsUsed*4;
  259.     palette = new byte[sizeOfPalette];
  260.     inputStream.read(palette, 0, sizeOfPalette);
  261.     properties.put("palette", palette);
  262. }
  263. properties.put("bmp_version", "BMP v. 3.x NT");
  264. break;
  265.     
  266.     default:
  267. throw new 
  268.  RuntimeException(JaiI18N.getString("BMPImageDecoder1"));
  269.     }
  270. } else if (size == 108) {
  271.     // Windows 4.x BMP
  272.     
  273.     properties.put("bmp_version", "BMP v. 4.x");
  274.          
  275.     // rgb masks, valid only if comp is BI_BITFIELDS
  276.     redMask = (int)readDWord(inputStream);
  277.     greenMask = (int)readDWord(inputStream);
  278.     blueMask = (int)readDWord(inputStream);
  279.     // Only supported for 32bpp BI_RGB argb
  280.     int alphaMask = (int)readDWord(inputStream);
  281.     long csType = readDWord(inputStream);
  282.     int redX = readLong(inputStream);
  283.     int redY = readLong(inputStream);
  284.     int redZ = readLong(inputStream);
  285.     int greenX = readLong(inputStream);
  286.     int greenY = readLong(inputStream);
  287.     int greenZ = readLong(inputStream);
  288.     int blueX = readLong(inputStream);
  289.     int blueY = readLong(inputStream);
  290.     int blueZ = readLong(inputStream);
  291.     long gammaRed = readDWord(inputStream);
  292.     long gammaGreen = readDWord(inputStream);
  293.     long gammaBlue = readDWord(inputStream);
  294.     // Read in the palette
  295.     int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
  296.     int sizeOfPalette = numberOfEntries*4;
  297.     palette = new byte[sizeOfPalette];
  298.     inputStream.read(palette, 0, sizeOfPalette);
  299.     if (palette != null || palette.length != 0) {
  300. properties.put("palette", palette);
  301.     }
  302.     
  303.     switch((int)csType) {
  304.     case LCS_CALIBRATED_RGB:
  305. // All the new fields are valid only for this case
  306. properties.put("color_space", "LCS_CALIBRATED_RGB");
  307. properties.put("redX", new Integer(redX));
  308. properties.put("redY", new Integer(redY));
  309. properties.put("redZ", new Integer(redZ));
  310. properties.put("greenX", new Integer(greenX));
  311. properties.put("greenY", new Integer(greenY));
  312. properties.put("greenZ", new Integer(greenZ));
  313. properties.put("blueX", new Integer(blueX));
  314. properties.put("blueY", new Integer(blueY));
  315. properties.put("blueZ", new Integer(blueZ));
  316. properties.put("gamma_red", new Long(gammaRed));
  317. properties.put("gamma_green", new Long(gammaGreen));
  318. properties.put("gamma_blue", new Long(gammaBlue));
  319. // break;
  320. throw new 
  321.  RuntimeException(JaiI18N.getString("BMPImageDecoder2"));
  322.     case LCS_sRGB:
  323. // Default Windows color space
  324. properties.put("color_space", "LCS_sRGB");
  325. break;
  326.     case LCS_CMYK:
  327. properties.put("color_space", "LCS_CMYK");
  328. //     break;
  329. throw new 
  330.  RuntimeException(JaiI18N.getString("BMPImageDecoder2"));
  331.     }
  332.     
  333.     if (bitsPerPixel == 1) {
  334. imageType = VERSION_4_1_BIT;
  335.     } else if (bitsPerPixel == 4) {
  336. imageType = VERSION_4_4_BIT;
  337.     } else if (bitsPerPixel == 8) {
  338. imageType = VERSION_4_8_BIT;
  339.     } else if (bitsPerPixel == 16) {
  340. imageType = VERSION_4_16_BIT;
  341. if ((int)compression == BI_RGB) {
  342.     redMask = 0x7C00;
  343.     greenMask = 0x3E0;
  344.     blueMask = 0x1F;
  345. }
  346.     } else if (bitsPerPixel == 24) {
  347. imageType = VERSION_4_24_BIT;
  348.     } else if (bitsPerPixel == 32) {
  349. imageType = VERSION_4_32_BIT;
  350. if ((int)compression == BI_RGB) {
  351.     redMask   = 0x00FF0000;
  352.     greenMask = 0x0000FF00;
  353.     blueMask  = 0x000000FF;
  354. }
  355.     }
  356.     
  357.     properties.put("red_mask", new Integer(redMask));
  358.     properties.put("green_mask", new Integer(greenMask));
  359.     properties.put("blue_mask", new Integer(blueMask));
  360.     properties.put("alpha_mask", new Integer(alphaMask));
  361.     
  362.     computeShifts();
  363. } else {
  364.     properties.put("bmp_version", "BMP v. 5.x");
  365.     throw new 
  366. RuntimeException(JaiI18N.getString("BMPImageDecoder4"));
  367. }
  368.     }
  369. } catch (IOException ioe) {
  370.     throw new RuntimeException(JaiI18N.getString("BMPImageDecoder5"));
  371. }
  372.     
  373. if (height > 0) {
  374.     // bottom up image
  375.     isBottomUp = true;
  376. } else {
  377.     // top down image
  378.     isBottomUp = false;
  379.     height = Math.abs(height);
  380. }
  381. // Reset Image Layout so there's only one tile.
  382. tileWidth = width;
  383. tileHeight = height;
  384. // When number of bitsPerPixel is <= 8, we use IndexColorModel.
  385.   if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
  386.     numBands = 1;
  387.     if (bitsPerPixel == 8) {
  388. sampleModel = 
  389.     RasterFactory.createPixelInterleavedSampleModel(
  390.    DataBuffer.TYPE_BYTE,
  391.    width, height, 
  392.    numBands);
  393.     } else {
  394. // 1 and 4 bit pixels can be stored in a packed format.
  395. sampleModel = 
  396.     new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, 
  397.     width, height,
  398.     bitsPerPixel);
  399.     }
  400.     // Create IndexColorModel from the palette.
  401.     byte r[], g[], b[];
  402.     int size;
  403.     if (imageType == VERSION_2_1_BIT || 
  404. imageType == VERSION_2_4_BIT ||
  405. imageType == VERSION_2_8_BIT) {
  406. size = palette.length/3;
  407. if (size > 256) {
  408.     size = 256;
  409. }
  410. int off;
  411. r = new byte[size];
  412. g = new byte[size];
  413. b = new byte[size];
  414. for (int i=0; i<size; i++) {
  415.     off = 3 * i;
  416.     b[i] = palette[off];
  417.     g[i] = palette[off+1];
  418.     r[i] = palette[off+2];
  419. }
  420.     } else {
  421. size = palette.length/4;
  422. if (size > 256) {
  423.     size = 256;
  424. }
  425. int off;
  426. r = new byte[size];
  427. g = new byte[size];
  428. b = new byte[size];
  429. for (int i=0; i<size; i++) {
  430.     off = 4 * i;
  431.     b[i] = palette[off];
  432.     g[i] = palette[off+1];
  433.     r[i] = palette[off+2];
  434. }
  435.     }
  436.     colorModel = new IndexColorModel(bitsPerPixel, size, r, g, b);
  437. } else {
  438.     numBands = 3;
  439.     // Create SampleModel
  440.     sampleModel =
  441. RasterFactory.createPixelInterleavedSampleModel(
  442.                     DataBuffer.TYPE_BYTE, width, height, numBands);
  443.             colorModel =
  444.                 ImageCodec.createComponentColorModel(sampleModel);
  445.      }
  446.     }
  447.     // Deal with 1 Bit images using IndexColorModels
  448.     private void read1Bit(byte[] bdata, int paletteEntries) {
  449. int padding = 0;
  450. int bytesPerScanline = (int)Math.ceil((double)width/8.0);
  451. int remainder = bytesPerScanline % 4;
  452. if (remainder != 0) {
  453.     padding = 4 - remainder;
  454. }
  455. int imSize = (bytesPerScanline + padding) * height;
  456. // Read till we have the whole image
  457. byte values[] = new byte[imSize];
  458. try {
  459.     int bytesRead = 0;
  460.     while (bytesRead < imSize) {
  461. bytesRead += inputStream.read(values, bytesRead,
  462.       imSize - bytesRead);
  463.     }
  464. } catch (IOException ioe) {
  465.     throw new 
  466. RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  467. }
  468. if (isBottomUp) {
  469.     // Convert the bottom up image to a top down format by copying
  470.     // one scanline from the bottom to the top at a time.
  471.     for (int i=0; i<height; i++) {
  472.   System.arraycopy(values, 
  473.  imSize - (i+1)*(bytesPerScanline + padding),
  474.  bdata, 
  475.  i*bytesPerScanline, bytesPerScanline);
  476.     }
  477. } else {
  478.     
  479.    for (int i=0; i<height; i++) {
  480.   System.arraycopy(values, 
  481.  i * (bytesPerScanline + padding), 
  482.  bdata, 
  483.  i * bytesPerScanline, 
  484.  bytesPerScanline);
  485.     } 
  486. }
  487.     }
  488.     
  489.     // Method to read a 4 bit BMP image data
  490.     private void read4Bit(byte[] bdata, int paletteEntries) {
  491. // Padding bytes at the end of each scanline
  492. int padding = 0;
  493. int bytesPerScanline = (int)Math.ceil((double)width/2.0);
  494. int remainder = bytesPerScanline % 4;
  495. if (remainder != 0) {
  496.     padding = 4 - remainder;
  497. }
  498. int imSize = (bytesPerScanline + padding) * height;
  499. // Read till we have the whole image
  500. byte values[] = new byte[imSize];
  501. try {
  502.     int bytesRead = 0;
  503.     while (bytesRead < imSize) {
  504. bytesRead += inputStream.read(values, bytesRead,
  505.       imSize - bytesRead);
  506.     }
  507. } catch (IOException ioe) {
  508.     throw new 
  509. RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  510. }
  511. if (isBottomUp) {
  512.     
  513.     // Convert the bottom up image to a top down format by copying
  514.     // one scanline from the bottom to the top at a time.
  515.     for (int i=0; i<height; i++) {
  516.   System.arraycopy(values, 
  517.  imSize - (i+1)*(bytesPerScanline + padding), 
  518.  bdata, 
  519.  i*bytesPerScanline, 
  520.  bytesPerScanline);
  521.     }
  522. } else {
  523.     for (int i=0; i<height; i++) {
  524.   System.arraycopy(values, 
  525.  i * (bytesPerScanline + padding), 
  526.  bdata, 
  527.  i * bytesPerScanline, 
  528.  bytesPerScanline);
  529.     }
  530. }
  531.     }
  532.     
  533.     // Method to read 8 bit BMP image data
  534.     private void read8Bit(byte[] bdata, int paletteEntries) {
  535. // Padding bytes at the end of each scanline
  536. int padding = 0;
  537. // width * bitsPerPixel should be divisible by 32
  538. int bitsPerScanline = width * 8;
  539. if ( bitsPerScanline%32 != 0) {
  540.     padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
  541.     padding = (int)Math.ceil(padding/8.0);
  542. }
  543. int imSize = (width + padding) * height;
  544. // Read till we have the whole image
  545. byte values[] = new byte[imSize];
  546. try {
  547.     int bytesRead = 0;
  548.     while (bytesRead < imSize) {
  549. bytesRead += inputStream.read(values, bytesRead,
  550.       imSize - bytesRead);
  551.     }
  552. } catch (IOException ioe) {
  553.     throw new 
  554. RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  555. }
  556. if (isBottomUp) {
  557.     // Convert the bottom up image to a top down format by copying
  558.     // one scanline from the bottom to the top at a time.
  559.     for (int i=0; i<height; i++) {
  560.   System.arraycopy(values, 
  561.  imSize - (i+1) * (width + padding), 
  562.  bdata, 
  563.  i * width, 
  564.  width);
  565.     }
  566. } else {
  567.     for (int i=0; i<height; i++) {
  568.   System.arraycopy(values, 
  569.  i * (width + padding), 
  570.  bdata, 
  571.  i * width, 
  572.  width);
  573.     }
  574. }
  575.     }
  576.     // Method to read 24 bit BMP image data
  577.     private void read24Bit(byte[] bdata) {
  578. // Padding bytes at the end of each scanline
  579. int padding = 0;
  580. // width * bitsPerPixel should be divisible by 32
  581. int bitsPerScanline = width * 24;
  582. if ( bitsPerScanline%32 != 0) {
  583.     padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
  584.     padding = (int)Math.ceil(padding/8.0);
  585. }
  586. int imSize = (int)imageSize;
  587. if (imSize == 0) {
  588.     imSize = (int)(bitmapFileSize - bitmapOffset);
  589. }
  590. // Read till we have the whole image
  591. byte values[] = new byte[imSize];
  592. try {
  593.     int bytesRead = 0;
  594.     while (bytesRead < imSize) {
  595. bytesRead += inputStream.read(values, bytesRead,
  596.       imSize - bytesRead);
  597.     }
  598. } catch (IOException ioe) {
  599.     // throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  600.     throw new RuntimeException(ioe.getMessage());
  601. }
  602. int l=0, count;
  603. if (isBottomUp) {
  604.     int max = width*height*3-1;
  605.     
  606.     count = -padding;
  607.     for (int i=0; i<height; i++) {
  608. l = max - (i+1)*width*3 + 1;
  609. count += padding;
  610. for (int j=0; j<width; j++) {
  611.     bdata[l++] = values[count++];
  612.     bdata[l++] = values[count++];
  613.     bdata[l++] = values[count++];
  614. }
  615.     }
  616. } else {
  617.     count = -padding;
  618.     for (int i=0; i<height; i++) {
  619. count += padding;
  620. for (int j=0; j<width; j++) {
  621.     bdata[l++] = values[count++];
  622.     bdata[l++] = values[count++];
  623.     bdata[l++] = values[count++];
  624. }
  625.     }
  626. }
  627.     }
  628.     private void read16Bit(byte bdata[]) {
  629. // Padding bytes at the end of each scanline
  630. int padding = 0;
  631. // width * bitsPerPixel should be divisible by 32
  632. int bitsPerScanline = width * 16;
  633. if ( bitsPerScanline%32 != 0) {
  634.     padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
  635.     padding = (int)Math.ceil(padding/8.0);
  636. }
  637. int imSize = (int)imageSize;
  638. if (imSize == 0) {
  639.     imSize = (int)(bitmapFileSize - bitmapOffset);
  640. }
  641. int l=0;
  642. try {
  643.     if (isBottomUp) {
  644. int max = width*height*3-1;
  645. for (int i=0; i<height; i++) {
  646.     l = max - (i+1)*width*3 + 1;
  647.     for (int j=0; j<width; j++) {
  648. int value = readWord(inputStream);
  649. bdata[l++] = (byte)((value & blueMask) >> blueBits);
  650. bdata[l++] = (byte)((value & greenMask) >> greenBits);
  651. bdata[l++] = (byte)((value & redMask) >> redBits);
  652.     }
  653.     for (int m=0; m<padding; m++) {
  654. inputStream.read();
  655.     }
  656. }
  657.     } else {
  658. for (int i=0; i<height; i++) {
  659.     for (int j=0; j<width; j++) {
  660. int value = readWord(inputStream);
  661. bdata[l++] = (byte)((value & blueMask) >> blueBits);
  662. bdata[l++] = (byte)((value & greenMask) >> greenBits);
  663. bdata[l++] = (byte)((value & redMask) >> redBits);
  664.     }
  665.     for (int m=0; m<padding; m++) {
  666. inputStream.read();
  667.     }
  668. }
  669.     }
  670. } catch (IOException ioe) {
  671.     throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  672. }
  673.     }
  674.     private void read32Bit(byte bdata[]) {
  675. int imSize = (int)imageSize;
  676. if (imSize == 0) {
  677.     imSize = (int)(bitmapFileSize - bitmapOffset);
  678. }
  679. int l=0;
  680. try {
  681.     if (isBottomUp) {
  682. int max = width*height*3-1;
  683. for (int i=0; i<height; i++) {
  684.     l = max - (i+1)*width*3 + 1;
  685.     for (int j=0; j<width; j++) {
  686. int value = (int)readDWord(inputStream);
  687. bdata[l++] = (byte)((value & blueMask) >> blueBits);
  688. bdata[l++] = (byte)((value & greenMask) >> greenBits);
  689. bdata[l++] = (byte)((value & redMask) >> redBits);
  690.     }
  691. }
  692.     } else {
  693. for (int i=0; i<height; i++) {
  694.     for (int j=0; j<width; j++) {
  695. int value = (int)readDWord(inputStream);
  696. bdata[l++] = (byte)((value & blueMask) >> blueBits);
  697. bdata[l++] = (byte)((value & greenMask) >> greenBits);
  698. bdata[l++] = (byte)((value & redMask) >> redBits);
  699.     }
  700. }
  701.     }
  702. } catch (IOException ioe) {
  703.     throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  704. }
  705.     }
  706.     
  707.     private void readRLE8(byte bdata[]) {
  708. // If imageSize field is not provided, calculate it.
  709. int imSize = (int)imageSize;
  710. if (imSize == 0) {
  711.     imSize = (int)(bitmapFileSize - bitmapOffset);
  712. }
  713. int padding = 0;
  714. // If width is not 32 bit aligned, then while uncompressing each 
  715. // scanline will have padding bytes, calculate the amount of padding
  716. int remainder = width % 4;
  717. if (remainder != 0) {
  718.     padding = 4 - remainder;
  719. }
  720. // Read till we have the whole image
  721. byte values[] = new byte[imSize];
  722. try {
  723.     int bytesRead = 0;
  724.     while (bytesRead < imSize) {
  725. bytesRead += inputStream.read(values, bytesRead,
  726.       imSize - bytesRead);
  727.     }
  728. } catch (IOException ioe) {
  729.     throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  730. }
  731. // Since data is compressed, decompress it
  732. byte val[] = decodeRLE8(imSize, padding, values);
  733. // Uncompressed data does not have any padding
  734.         imSize = width * height;
  735. if (isBottomUp) {
  736.     // Convert the bottom up image to a top down format by copying
  737.     // one scanline from the bottom to the top at a time.
  738.     // int bytesPerScanline = (int)Math.ceil((double)width/8.0);
  739.     int bytesPerScanline = width;
  740.     for (int i=0; i<height; i++) {
  741. System.arraycopy(val, 
  742.  imSize - (i+1)*(bytesPerScanline), 
  743.  bdata, 
  744.  i*bytesPerScanline, bytesPerScanline);
  745.     }
  746.     
  747. } else {
  748.     
  749.     bdata = val;
  750. }
  751.     }
  752.     
  753.     private byte[] decodeRLE8(int imSize, int padding, byte values[]) {
  754. byte val[] = new byte[width * height];
  755. int count = 0, l = 0;
  756. int value;
  757. boolean flag = false;
  758. while (count != imSize) {
  759.     value = values[count++] & 0xff;
  760.     if (value == 0) {
  761. switch(values[count++] & 0xff) {
  762. case 0:
  763.     // End-of-scanline marker
  764.     break;
  765. case 1:
  766.     // End-of-RLE marker
  767.     flag = true;
  768.     break;
  769. case 2:
  770.     // delta or vector marker
  771.     int xoff = values[count++] & 0xff;
  772.     int yoff = values[count] & 0xff;
  773.     // Move to the position xoff, yoff down
  774.     l += xoff + yoff*width;
  775.     break;
  776.       
  777. default:
  778.     int end = values[count-1] & 0xff;
  779.     for (int i=0; i<end; i++) {
  780. val[l++] = (byte)(values[count++] & 0xff);
  781.     }
  782.     // Whenever end pixels can fit into odd number of bytes,
  783.     // an extra padding byte will be present, so skip that.
  784.     if (!isEven(end)) {
  785. count++;
  786.     }
  787. }
  788.     } else {
  789. for (int i=0; i<value; i++) {
  790.     val[l++] = (byte)(values[count] & 0xff);
  791. }
  792. count++;
  793.     }
  794.     // If End-of-RLE data, then exit the while loop
  795.     if (flag) {
  796. break;
  797.     }
  798. }
  799. return val;
  800.     }
  801.     private int[] readRLE4() {
  802. // If imageSize field is not specified, calculate it.
  803. int imSize = (int)imageSize;
  804. if (imSize == 0) {
  805.     imSize = (int)(bitmapFileSize - bitmapOffset);
  806. }
  807. int padding = 0;
  808. // If width is not 32 byte aligned, then while uncompressing each 
  809. // scanline will have padding bytes, calculate the amount of padding
  810. int remainder = width % 4;
  811. if (remainder != 0) {
  812.     padding = 4 - remainder;
  813. }
  814. // Read till we have the whole image
  815. int values[] = new int[imSize];
  816. try {
  817.     for (int i=0; i<imSize; i++) {
  818. values[i] = inputStream.read();
  819.     }
  820. } catch(IOException ioe) {
  821.     throw new RuntimeException(JaiI18N.getString("BMPImageDecoder6"));
  822. }
  823. // Decompress the RLE4 compressed data.
  824. int val[] = decodeRLE4(imSize, padding, values);
  825. // Invert it as it is bottom up format.
  826. if (isBottomUp) {
  827.     int inverted[] = val;
  828.     val = new int[width * height];
  829.     int l = 0, index, lineEnd;
  830.     for (int i = height-1; i >= 0; i--) {
  831. index = i * width;
  832. lineEnd = l + width;
  833. while(l != lineEnd) {
  834.     val[l++] = inverted[index++];
  835. }
  836.     }
  837. }
  838. // This array will be used to call setPixels as the decompression
  839. // had unpacked the 4bit pixels each into an int.
  840. return val;
  841.     }
  842.     private int[] decodeRLE4(int imSize, int padding, int values[]) {
  843. int val[] = new int[width * height];
  844.   int count = 0, l = 0;
  845. int value;
  846. boolean flag = false;
  847. while (count != imSize) {
  848.     value = values[count++];
  849.     if (value == 0) {
  850. // Absolute mode
  851. switch(values[count++]) {
  852. case 0:
  853.     // End-of-scanline marker
  854.     break;
  855. case 1:
  856.     // End-of-RLE marker
  857.     flag = true;
  858.     break;
  859. case 2:
  860.     // delta or vector marker
  861.     int xoff = values[count++];
  862.     int yoff = values[count];
  863.     // Move to the position xoff, yoff down
  864.     l += xoff + yoff*width;
  865.     break;
  866.       
  867. default:
  868.     int end = values[count-1];
  869.     for (int i=0; i<end; i++) {
  870. val[l++] = isEven(i) ? (values[count] & 0xf0) >> 4 
  871.                      : (values[count++] & 0x0f);
  872.     }
  873.     // When end is odd, the above for loop does not
  874.     // increment count, so do it now.
  875.     if (!isEven(end)) {
  876. count++;
  877.     } 
  878.     
  879.     // Whenever end pixels can fit into odd number of bytes,
  880.     // an extra padding byte will be present, so skip that.
  881.     if ( !isEven((int)Math.ceil(end/2)) ) {
  882. count++;
  883.     }
  884.     break;
  885. }
  886.     } else {
  887. // Encoded mode
  888. int alternate[] = { (values[count] & 0xf0) >> 4, 
  889.     values[count] & 0x0f };
  890. for (int i=0; i<value; i++) {
  891.     val[l++] = alternate[i%2];
  892. }
  893. count++;
  894.     }
  895.     // If End-of-RLE data, then exit the while loop
  896.     if (flag) {
  897. break;
  898.     }
  899.     
  900. }
  901. return val;
  902.     }
  903.     private boolean isEven(int number) {
  904. return (number%2 == 0 ? true : false);
  905.     }
  906.     
  907.     private void computeShifts() {
  908. redBits = computeShift(redMask);
  909. greenBits = computeShift(greenMask);
  910. blueBits = computeShift(blueMask);
  911.     }
  912.     private int computeShift(int hexNumber) {
  913. int factor = 0x1;
  914. int result = 0, count=0;
  915. while (result == 0) {
  916.     result = hexNumber & factor;
  917.     count++;
  918.     factor = factor << 1;
  919. }
  920. return (count-1);
  921.     }
  922.     
  923.     // Windows defined data type reading methods - everything is little endian
  924.     // Unsigned 8 bits
  925.     private int readUnsignedByte(InputStream stream) throws IOException {
  926. return (stream.read() & 0xff);
  927.     }
  928.     // Unsigned 2 bytes
  929.     private int readUnsignedShort(InputStream stream) throws IOException {
  930. int b1 = readUnsignedByte(stream);
  931. int b2 = readUnsignedByte(stream);
  932. return ((b2 << 8) | b1) & 0xffff;
  933.     }
  934.     // Signed 16 bits
  935.     private int readShort(InputStream stream) throws IOException {
  936. int b1 = readUnsignedByte(stream);
  937. int b2 = readUnsignedByte(stream);
  938. return (b2 << 8) | b1;
  939.     }
  940.     // Unsigned 16 bits
  941.     private int readWord(InputStream stream) throws IOException {
  942. return readUnsignedShort(stream);
  943.     }
  944.     // Unsigned 4 bytes
  945.     private long readUnsignedInt(InputStream stream) throws IOException {
  946. int b1 = readUnsignedByte(stream);
  947.         int b2 = readUnsignedByte(stream);
  948.         int b3 = readUnsignedByte(stream);
  949.         int b4 = readUnsignedByte(stream);
  950. long l = (long)((b4 << 24) | (b3 << 16) | (b2 << 8) | b1);
  951. return l & 0xffffffff;
  952.     }
  953.     // Signed 4 bytes
  954.     private int readInt(InputStream stream) throws IOException {
  955. int b1 = readUnsignedByte(stream);
  956.         int b2 = readUnsignedByte(stream);
  957.         int b3 = readUnsignedByte(stream);
  958.         int b4 = readUnsignedByte(stream);
  959. return (b4 << 24) | (b3 << 16) | (b2 << 8) | b1;
  960.     }
  961.     
  962.     // Unsigned 4 bytes 
  963.     private long readDWord(InputStream stream) throws IOException {
  964. return readUnsignedInt(stream);
  965.     }
  966.     // 32 bit signed value
  967.     private int readLong(InputStream stream) throws IOException {
  968. return readInt(stream);
  969.     }
  970.     private synchronized Raster computeTile(int tileX, int tileY) {
  971.         if (theTile != null) {
  972.             return theTile;
  973.         }
  974. // Create a new tile
  975. Point org = new Point(tileXToX(tileX), tileYToY(tileY));
  976. WritableRaster tile = 
  977.     RasterFactory.createWritableRaster(sampleModel, org);
  978. DataBufferByte buffer = (DataBufferByte)tile.getDataBuffer();
  979. byte bdata[] = buffer.getData();
  980. // There should only be one tile.
  981. switch(imageType) {
  982.     
  983. case VERSION_2_1_BIT:
  984.     // no compression
  985.     read1Bit(bdata, 3);
  986.     break;
  987.     
  988. case VERSION_2_4_BIT:
  989.     // no compression
  990.     read4Bit(bdata, 3);
  991.     break;
  992.     
  993. case VERSION_2_8_BIT:
  994.     // no compression
  995.     read8Bit(bdata, 3);
  996.     break;
  997.     
  998. case VERSION_2_24_BIT:
  999.     // no compression
  1000.     read24Bit(bdata);
  1001.     break;
  1002.     
  1003. case VERSION_3_1_BIT:
  1004.     // 1-bit images cannot be compressed.
  1005.     read1Bit(bdata, 4);
  1006.     break;
  1007.     
  1008. case VERSION_3_4_BIT:
  1009.     switch((int)compression) {
  1010.     case BI_RGB:
  1011. read4Bit(bdata, 4);
  1012. break;
  1013.     case BI_RLE4:
  1014. int pixels[] = readRLE4();
  1015. tile.setPixels(0, 0, width, height, pixels);
  1016. break;
  1017.     default:
  1018. throw new 
  1019.     RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
  1020.     }
  1021.     break;
  1022. case VERSION_3_8_BIT:
  1023.     switch((int)compression) {
  1024.     case BI_RGB:
  1025. read8Bit(bdata, 4);
  1026.     break;
  1027.     
  1028.     case BI_RLE8:
  1029. readRLE8(bdata);
  1030. break;
  1031.     
  1032.     default:
  1033. throw new 
  1034.     RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
  1035.     }
  1036.     break;
  1037.     
  1038. case VERSION_3_24_BIT:
  1039.     // 24-bit images are not compressed
  1040.     read24Bit(bdata);
  1041.     break;
  1042.     
  1043. case VERSION_3_NT_16_BIT:
  1044.     read16Bit(bdata);
  1045.     break;
  1046.     
  1047. case VERSION_3_NT_32_BIT:
  1048.     read32Bit(bdata);
  1049.     break;
  1050.     
  1051. case VERSION_4_1_BIT:
  1052.     read1Bit(bdata, 4);
  1053.     break;
  1054. case VERSION_4_4_BIT:
  1055.     switch((int)compression) {
  1056.     case BI_RGB:
  1057. read4Bit(bdata, 4);
  1058. break;
  1059.     case BI_RLE4:
  1060. int pixels[] = readRLE4();
  1061. tile.setPixels(0, 0, width, height, pixels);
  1062. break;
  1063.     default:
  1064. throw new 
  1065.     RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
  1066.     }
  1067. case VERSION_4_8_BIT:
  1068.     switch((int)compression) {
  1069.     case BI_RGB:
  1070. read8Bit(bdata, 4);
  1071. break;
  1072.     case BI_RLE8:
  1073. readRLE8(bdata);
  1074. break;
  1075.     default:
  1076. throw new 
  1077.     RuntimeException(JaiI18N.getString("BMPImageDecoder3"));
  1078.     }
  1079.     break;
  1080.     
  1081. case VERSION_4_16_BIT:
  1082.     read16Bit(bdata);
  1083.     break;
  1084.     
  1085. case VERSION_4_24_BIT:
  1086.     read24Bit(bdata);
  1087.     break;
  1088.     
  1089. case VERSION_4_32_BIT:
  1090.     read32Bit(bdata);
  1091.     break;
  1092. }
  1093.         theTile = tile;
  1094. return tile;
  1095.     }
  1096.     public synchronized Raster getTile(int tileX, int tileY) {
  1097.         if ((tileX != 0) || (tileY != 0)) {
  1098.             throw new
  1099. IllegalArgumentException(JaiI18N.getString("BMPImageDecoder7"));
  1100.         }
  1101.         return computeTile(tileX, tileY);
  1102.     }
  1103. }