X-Git-Url: http://source.jalview.org/gitweb/?p=jalviewjs.git;a=blobdiff_plain;f=src%2Fjavajs%2Fimg%2FBMPDecoder.java;h=68fb24dc4102af5d6d8fa28a20b58bbc532f82c3;hp=b71e7f8c3557a12669b4e7a4f8ff163230ace74e;hb=b9b7a352eee79b7764c3b09c9d19663075061d8c;hpb=8ffd05b3abe52c0b6b79b011c0966361f82d5fe6 diff --git a/src/javajs/img/BMPDecoder.java b/src/javajs/img/BMPDecoder.java index b71e7f8..68fb24d 100644 --- a/src/javajs/img/BMPDecoder.java +++ b/src/javajs/img/BMPDecoder.java @@ -1,208 +1,208 @@ -/* $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: jmol-developers@lists.sf.net - * - * 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 hansonr@stolaf.edu - * - * @author Bob Hanson (hansonr@stolaf.edu) - * - */ -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; - } - -} +/* $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: jmol-developers@lists.sf.net + * + * 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 hansonr@stolaf.edu + * + * @author Bob Hanson (hansonr@stolaf.edu) + * + */ +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; + } + +}