Merge branch 'Jalview-JS/jim/JAL-3253-JAL-3418' into Jalview-JS/JAL-3253-applet
[jalview.git] / unused / javajs / img / BMPDecoder.java
1 /* $RCSfile$
2  * $Author: nicove $
3  * $Date: 2007-03-30 12:26:16 -0500 (Fri, 30 Mar 2007) $
4  * $Revision: 7275 $
5  *
6  * Some portions of this file have been modified by Robert Hanson hansonr.at.stolaf.edu 2012-2017
7  * for use in SwingJS via transpilation into JavaScript using Java2Script.
8  *
9  * Copyright (C) 2002-2005  The Jmol Development Team
10  *
11  * Contact: jmol-developers@lists.sf.net
12  *
13  *  This library is free software; you can redistribute it and/or
14  *  modify it under the terms of the GNU Lesser General Public
15  *  License as published by the Free Software Foundation; either
16  *  version 2.1 of the License, or (at your option) any later version.
17  *
18  *  This library is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *  Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public
24  *  License along with this library; if not, write to the Free Software
25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27 package javajs.img;
28
29 import java.io.BufferedInputStream;
30 import java.io.IOException;
31
32 import javajs.util.Rdr;
33
34 /**
35  * src: http://www.javaworld.com/article/2077542/learn-java/java-tip-43--how-to-
36  * read-8--and-24-bit-microsoft-windows-bitmaps-in-java-applications.html
37  *
38  * see also: http://en.wikipedia.org/wiki/BMP_file_format
39  * 
40  * Modified by Bob Hanson hansonr@stolaf.edu
41  * 
42  * @author Bob Hanson (hansonr@stolaf.edu)
43  * 
44  */
45 public class BMPDecoder {
46
47   public BMPDecoder() {
48     // for reflection
49   }
50   
51   private BufferedInputStream bis;
52
53   /**
54    * original comment:
55    * 
56    * loadbitmap() method converted from Windows C code. Reads only uncompressed
57    * 24- and 8-bit images. Tested with images saved using Microsoft Paint in
58    * Windows 95. If the image is not a 24- or 8-bit image, the program refuses
59    * to even try. I guess one could include 4-bit images by masking the byte by
60    * first 1100 and then 0011. I am not really interested in such images. If a
61    * compressed image is attempted, the routine will probably fail by generating
62    * an IOException. Look for variable ncompression to be different from 0 to
63    * indicate compression is present.
64    * 
65    * @param bytes
66    * @return [image byte array, width, height]
67    */
68   public Object[] decodeWindowsBMP(byte[] bytes) {
69     try {
70       bis = Rdr.getBIS(bytes);
71       temp = new byte[4];
72       // read BITMAPFILEHEADER
73       if (readByte() != 'B' || readByte() != 'M')
74         return null;
75       readInt(); // file size; ignored
76       readShort(); // reserved
77       readShort(); // reserved
78       readInt(); // ptr to pixel array; ignored
79       int imageWidth, imageHeight, bitsPerPixel, nColors = 0, imageSize = 0;
80       // read BITMAP header
81       int headerSize = readInt();
82       switch (headerSize) {
83       case 12:
84         // BITMAPCOREHEADER
85         imageWidth = readShort();
86         imageHeight = readShort();
87         readShort(); // planes
88         bitsPerPixel = readShort();
89         break;
90       case 40:
91         // BITMAPINFOHEADER
92         imageWidth = readInt();
93         imageHeight = readInt();
94         readShort(); // planes
95         bitsPerPixel = readShort();
96         int ncompression = readInt();
97         if (ncompression != 0) {
98           System.out.println("BMP Compression is :" + ncompression
99               + " -- aborting");
100           return null;
101         }
102         imageSize = readInt();
103         readInt(); // hres
104         readInt(); // vres
105         nColors = readInt();
106         readInt(); // colors used
107         break;
108       default:
109         System.out.println("BMP Header unrecognized, length=" + headerSize
110             + " -- aborting");
111         return null;
112       }
113       boolean isYReversed = (imageHeight < 0);
114       if (isYReversed)
115         imageHeight = -imageHeight;
116       int nPixels = imageHeight * imageWidth;
117       int bytesPerPixel = bitsPerPixel / 8;
118       nColors = (nColors > 0 ? nColors : 1 << bitsPerPixel);
119       int npad = (bytesPerPixel == 4 ? 0
120           : imageSize == 0 ? 4 - (imageWidth % 4) : (imageSize / imageHeight)
121               - imageWidth * bytesPerPixel) % 4;
122       int[] palette;
123       int[] buf = new int[nPixels];
124       int dpt = (isYReversed ? imageWidth : -imageWidth);
125       int pt0 = (isYReversed ? 0 : nPixels + dpt);
126       int pt1 = (isYReversed ? nPixels : dpt);
127       switch (bitsPerPixel) {
128       case 32:
129       case 24:
130         for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
131           for (int i = 0; i < imageWidth; i++)
132             buf[pt + i] = readColor(bytesPerPixel);
133         break;
134       case 8:
135         palette = new int[nColors];
136         for (int i = 0; i < nColors; i++)
137           palette[i] = readColor(4);
138         for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
139           for (int i = 0; i < imageWidth; i++)
140             buf[pt + i] = palette[readByte()];
141         break;
142       case 4:
143         npad = (4 - (((imageWidth + 1) / 2) % 4)) % 4;
144         palette = new int[nColors];
145         for (int i = 0; i < nColors; i++)
146           palette[i] = readColor(4);
147         int b4 = 0;
148         for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
149           for (int i = 0, shift = 4; i < imageWidth; i++, shift = 4 - shift)
150             buf[pt + i] = palette[((shift == 4 ? (b4 = readByte()) : b4) >> shift) & 0xF];
151         break;
152       case 1:
153         int color1 = readColor(3);
154         int color2 = readColor(3);
155         npad = (4 - (((imageWidth + 7) / 8) % 4)) % 4;
156         int b = 0;
157         for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
158           for (int i = 0, bpt = -1; i < imageWidth; i++, bpt--) {
159             if (bpt < 0) {
160               b = readByte();
161               bpt = 7;
162             }
163             buf[pt + i] = ((b & (1 << bpt)) == 0 ? color1 : color2);
164           }
165         break;
166       case 64:
167       case 2:
168       default:
169         System.out
170             .println("Not a 32-, 24-, 8-, 4-, or 1-bit Windows Bitmap, aborting...");
171         return null;
172       }
173       return new Object[] { buf, Integer.valueOf(imageWidth),
174           Integer.valueOf(imageHeight) };
175     } catch (Exception e) {
176       System.out.println("Caught exception in loadbitmap!");
177     }
178     return null;
179   }
180
181   private boolean pad(int npad) throws IOException {
182     for (int i = 0; i < npad; i++)
183       readByte();
184     return true;
185   }
186
187   private byte[] temp;
188   
189   private int readColor(int n) throws IOException {
190     bis.read(temp, 0, n);
191     return 0xff << 24 | ((temp[2] & 0xff) << 16)
192         | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
193   }
194
195   private int readInt() throws IOException {
196     bis.read(temp, 0, 4);
197     return ((temp[3] & 0xff) << 24) | ((temp[2] & 0xff) << 16)
198         | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
199   }
200
201   private int readShort() throws IOException {
202     bis.read(temp, 0, 2);
203     return ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
204   }
205
206   private int readByte() throws IOException {
207     bis.read(temp, 0, 1);
208     return temp[0] & 0xff;
209   }
210
211 }