3 * $Date: 2007-03-30 12:26:16 -0500 (Fri, 30 Mar 2007) $
\r
6 * Copyright (C) 2002-2005 The Jmol Development Team
\r
8 * Contact: jmol-developers@lists.sf.net
\r
10 * This library is free software; you can redistribute it and/or
\r
11 * modify it under the terms of the GNU Lesser General Public
\r
12 * License as published by the Free Software Foundation; either
\r
13 * version 2.1 of the License, or (at your option) any later version.
\r
15 * This library is distributed in the hope that it will be useful,
\r
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
18 * Lesser General Public License for more details.
\r
20 * You should have received a copy of the GNU Lesser General Public
\r
21 * License along with this library; if not, write to the Free Software
\r
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
\r
26 import java.io.BufferedInputStream;
\r
27 import java.io.IOException;
\r
29 import javajs.util.Rdr;
\r
32 * src: http://www.javaworld.com/article/2077542/learn-java/java-tip-43--how-to-
\r
33 * read-8--and-24-bit-microsoft-windows-bitmaps-in-java-applications.html
\r
35 * see also: http://en.wikipedia.org/wiki/BMP_file_format
\r
37 * Modified by Bob Hanson hansonr@stolaf.edu
\r
39 * @author Bob Hanson (hansonr@stolaf.edu)
\r
42 public class BMPDecoder {
\r
44 public BMPDecoder() {
\r
48 private BufferedInputStream bis;
\r
53 * loadbitmap() method converted from Windows C code. Reads only uncompressed
\r
54 * 24- and 8-bit images. Tested with images saved using Microsoft Paint in
\r
55 * Windows 95. If the image is not a 24- or 8-bit image, the program refuses
\r
56 * to even try. I guess one could include 4-bit images by masking the byte by
\r
57 * first 1100 and then 0011. I am not really interested in such images. If a
\r
58 * compressed image is attempted, the routine will probably fail by generating
\r
59 * an IOException. Look for variable ncompression to be different from 0 to
\r
60 * indicate compression is present.
\r
63 * @return [image byte array, width, height]
\r
65 public Object[] decodeWindowsBMP(byte[] bytes) {
\r
67 bis = Rdr.getBIS(bytes);
\r
69 // read BITMAPFILEHEADER
\r
70 if (readByte() != 'B' || readByte() != 'M')
\r
72 readInt(); // file size; ignored
\r
73 readShort(); // reserved
\r
74 readShort(); // reserved
\r
75 readInt(); // ptr to pixel array; ignored
\r
76 int imageWidth, imageHeight, bitsPerPixel, nColors = 0, imageSize = 0;
\r
77 // read BITMAP header
\r
78 int headerSize = readInt();
\r
79 switch (headerSize) {
\r
82 imageWidth = readShort();
\r
83 imageHeight = readShort();
\r
84 readShort(); // planes
\r
85 bitsPerPixel = readShort();
\r
89 imageWidth = readInt();
\r
90 imageHeight = readInt();
\r
91 readShort(); // planes
\r
92 bitsPerPixel = readShort();
\r
93 int ncompression = readInt();
\r
94 if (ncompression != 0) {
\r
95 System.out.println("BMP Compression is :" + ncompression
\r
99 imageSize = readInt();
\r
102 nColors = readInt();
\r
103 readInt(); // colors used
\r
106 System.out.println("BMP Header unrecognized, length=" + headerSize
\r
110 boolean isYReversed = (imageHeight < 0);
\r
112 imageHeight = -imageHeight;
\r
113 int nPixels = imageHeight * imageWidth;
\r
114 int bytesPerPixel = bitsPerPixel / 8;
\r
115 nColors = (nColors > 0 ? nColors : 1 << bitsPerPixel);
\r
116 int npad = (bytesPerPixel == 4 ? 0
\r
117 : imageSize == 0 ? 4 - (imageWidth % 4) : (imageSize / imageHeight)
\r
118 - imageWidth * bytesPerPixel) % 4;
\r
120 int[] buf = new int[nPixels];
\r
121 int dpt = (isYReversed ? imageWidth : -imageWidth);
\r
122 int pt0 = (isYReversed ? 0 : nPixels + dpt);
\r
123 int pt1 = (isYReversed ? nPixels : dpt);
\r
124 switch (bitsPerPixel) {
\r
127 for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
\r
128 for (int i = 0; i < imageWidth; i++)
\r
129 buf[pt + i] = readColor(bytesPerPixel);
\r
132 palette = new int[nColors];
\r
133 for (int i = 0; i < nColors; i++)
\r
134 palette[i] = readColor(4);
\r
135 for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
\r
136 for (int i = 0; i < imageWidth; i++)
\r
137 buf[pt + i] = palette[readByte()];
\r
140 npad = (4 - (((imageWidth + 1) / 2) % 4)) % 4;
\r
141 palette = new int[nColors];
\r
142 for (int i = 0; i < nColors; i++)
\r
143 palette[i] = readColor(4);
\r
145 for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
\r
146 for (int i = 0, shift = 4; i < imageWidth; i++, shift = 4 - shift)
\r
147 buf[pt + i] = palette[((shift == 4 ? (b4 = readByte()) : b4) >> shift) & 0xF];
\r
150 int color1 = readColor(3);
\r
151 int color2 = readColor(3);
\r
152 npad = (4 - (((imageWidth + 7) / 8) % 4)) % 4;
\r
154 for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
\r
155 for (int i = 0, bpt = -1; i < imageWidth; i++, bpt--) {
\r
160 buf[pt + i] = ((b & (1 << bpt)) == 0 ? color1 : color2);
\r
167 .println("Not a 32-, 24-, 8-, 4-, or 1-bit Windows Bitmap, aborting...");
\r
170 return new Object[] { buf, Integer.valueOf(imageWidth),
\r
171 Integer.valueOf(imageHeight) };
\r
172 } catch (Exception e) {
\r
173 System.out.println("Caught exception in loadbitmap!");
\r
178 private boolean pad(int npad) throws IOException {
\r
179 for (int i = 0; i < npad; i++)
\r
184 private byte[] temp;
\r
186 private int readColor(int n) throws IOException {
\r
187 bis.read(temp, 0, n);
\r
188 return 0xff << 24 | ((temp[2] & 0xff) << 16)
\r
189 | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
\r
192 private int readInt() throws IOException {
\r
193 bis.read(temp, 0, 4);
\r
194 return ((temp[3] & 0xff) << 24) | ((temp[2] & 0xff) << 16)
\r
195 | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
\r
198 private int readShort() throws IOException {
\r
199 bis.read(temp, 0, 2);
\r
200 return ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
\r
203 private int readByte() throws IOException {
\r
204 bis.read(temp, 0, 1);
\r
205 return temp[0] & 0xff;
\r