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