javajs.img.BMPDecoder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmol Show documentation
Show all versions of jmol Show documentation
Jmol: an open-source Java viewer for chemical structures in 3D
/* $RCSfile$
* $Author: nicove $
* $Date: 2007-03-30 12:26:16 -0500 (Fri, 30 Mar 2007) $
* $Revision: 7275 $
*
* Copyright (C) 2002-2005 The Jmol Development Team
*
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package javajs.img;
import java.io.BufferedInputStream;
import java.io.IOException;
import javajs.util.Rdr;
/**
* src: http://www.javaworld.com/article/2077542/learn-java/java-tip-43--how-to-
* read-8--and-24-bit-microsoft-windows-bitmaps-in-java-applications.html
*
* see also: http://en.wikipedia.org/wiki/BMP_file_format
*
* Modified by Bob Hanson [email protected]
*
* @author Bob Hanson ([email protected])
*
*/
public class BMPDecoder {
public BMPDecoder() {
// for reflection
}
private BufferedInputStream bis;
/**
* original comment:
*
* loadbitmap() method converted from Windows C code. Reads only uncompressed
* 24- and 8-bit images. Tested with images saved using Microsoft Paint in
* Windows 95. If the image is not a 24- or 8-bit image, the program refuses
* to even try. I guess one could include 4-bit images by masking the byte by
* first 1100 and then 0011. I am not really interested in such images. If a
* compressed image is attempted, the routine will probably fail by generating
* an IOException. Look for variable ncompression to be different from 0 to
* indicate compression is present.
*
* @param bytes
* @return [image byte array, width, height]
*/
public Object[] decodeWindowsBMP(byte[] bytes) {
try {
bis = Rdr.getBIS(bytes);
temp = new byte[4];
// read BITMAPFILEHEADER
if (readByte() != 'B' || readByte() != 'M')
return null;
readInt(); // file size; ignored
readShort(); // reserved
readShort(); // reserved
readInt(); // ptr to pixel array; ignored
int imageWidth, imageHeight, bitsPerPixel, nColors = 0, imageSize = 0;
// read BITMAP header
int headerSize = readInt();
switch (headerSize) {
case 12:
// BITMAPCOREHEADER
imageWidth = readShort();
imageHeight = readShort();
readShort(); // planes
bitsPerPixel = readShort();
break;
case 40:
// BITMAPINFOHEADER
imageWidth = readInt();
imageHeight = readInt();
readShort(); // planes
bitsPerPixel = readShort();
int ncompression = readInt();
if (ncompression != 0) {
System.out.println("BMP Compression is :" + ncompression
+ " -- aborting");
return null;
}
imageSize = readInt();
readInt(); // hres
readInt(); // vres
nColors = readInt();
readInt(); // colors used
break;
default:
System.out.println("BMP Header unrecognized, length=" + headerSize
+ " -- aborting");
return null;
}
boolean isYReversed = (imageHeight < 0);
if (isYReversed)
imageHeight = -imageHeight;
int nPixels = imageHeight * imageWidth;
int bytesPerPixel = bitsPerPixel / 8;
nColors = (nColors > 0 ? nColors : 1 << bitsPerPixel);
int npad = (bytesPerPixel == 4 ? 0
: imageSize == 0 ? 4 - (imageWidth % 4) : (imageSize / imageHeight)
- imageWidth * bytesPerPixel) % 4;
int[] palette;
int[] buf = new int[nPixels];
int dpt = (isYReversed ? imageWidth : -imageWidth);
int pt0 = (isYReversed ? 0 : nPixels + dpt);
int pt1 = (isYReversed ? nPixels : dpt);
switch (bitsPerPixel) {
case 32:
case 24:
for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
for (int i = 0; i < imageWidth; i++)
buf[pt + i] = readColor(bytesPerPixel);
break;
case 8:
palette = new int[nColors];
for (int i = 0; i < nColors; i++)
palette[i] = readColor(4);
for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
for (int i = 0; i < imageWidth; i++)
buf[pt + i] = palette[readByte()];
break;
case 4:
npad = (4 - (((imageWidth + 1) / 2) % 4)) % 4;
palette = new int[nColors];
for (int i = 0; i < nColors; i++)
palette[i] = readColor(4);
int b4 = 0;
for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
for (int i = 0, shift = 4; i < imageWidth; i++, shift = 4 - shift)
buf[pt + i] = palette[((shift == 4 ? (b4 = readByte()) : b4) >> shift) & 0xF];
break;
case 1:
int color1 = readColor(3);
int color2 = readColor(3);
npad = (4 - (((imageWidth + 7) / 8) % 4)) % 4;
int b = 0;
for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
for (int i = 0, bpt = -1; i < imageWidth; i++, bpt--) {
if (bpt < 0) {
b = readByte();
bpt = 7;
}
buf[pt + i] = ((b & (1 << bpt)) == 0 ? color1 : color2);
}
break;
case 64:
case 2:
default:
System.out
.println("Not a 32-, 24-, 8-, 4-, or 1-bit Windows Bitmap, aborting...");
return null;
}
return new Object[] { buf, Integer.valueOf(imageWidth),
Integer.valueOf(imageHeight) };
} catch (Exception e) {
System.out.println("Caught exception in loadbitmap!");
}
return null;
}
private boolean pad(int npad) throws IOException {
for (int i = 0; i < npad; i++)
readByte();
return true;
}
private byte[] temp;
private int readColor(int n) throws IOException {
bis.read(temp, 0, n);
return 0xff << 24 | ((temp[2] & 0xff) << 16)
| ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
}
private int readInt() throws IOException {
bis.read(temp, 0, 4);
return ((temp[3] & 0xff) << 24) | ((temp[2] & 0xff) << 16)
| ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
}
private int readShort() throws IOException {
bis.read(temp, 0, 2);
return ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
}
private int readByte() throws IOException {
bis.read(temp, 0, 1);
return temp[0] & 0xff;
}
}