Source for gnu.javax.imageio.bmp.BMPInfoHeader

   1: /* BMPInfoHeader.java --
   2:    Copyright (C)  2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: package gnu.javax.imageio.bmp;
  39: 
  40: import java.awt.Dimension;
  41: import java.awt.image.ColorModel;
  42: import java.awt.image.RenderedImage;
  43: import java.io.IOException;
  44: import java.nio.ByteBuffer;
  45: import java.nio.ByteOrder;
  46: 
  47: import javax.imageio.IIOImage;
  48: import javax.imageio.ImageWriteParam;
  49: import javax.imageio.stream.ImageInputStream;
  50: import javax.imageio.stream.ImageOutputStream;
  51: 
  52: public class BMPInfoHeader
  53: {
  54:     /** Size of the bitmap info header */
  55:   protected int biSize;
  56: 
  57:   /** Pixel width of the bitmap */
  58:   protected int biWidth;
  59: 
  60:   /** Pixel height of the bitmap */
  61:   protected int biHeight;
  62: 
  63:   /** Number of bitplanes = 1 */
  64:   protected short biPlanes;
  65: 
  66:   /** Number of bpp = 1,4,8,24 */
  67:   protected short biBitCount;
  68: 
  69:   /** Compression type, RGB8, RLE8, RLE4, BITFIELDS */
  70:   protected int biCompression;
  71: 
  72:   /** Byte size of the uncompressed bitmap, can be 0. */
  73:   protected int biSizeImage;
  74: 
  75:   /** X resolution, dots per meter */
  76:   protected int biXPelsPerMeter;
  77: 
  78:   /** Y resolution, dots per meter */
  79:   protected int biYPelsPerMeter;
  80: 
  81:   /** Number of colors used (palette only, can be 0 for all) */
  82:   protected int biClrUsed;
  83: 
  84:   /** Number of 'important' colors, 0 for all */
  85:   protected int biClrImportant;
  86: 
  87:   /** BITMAPINFOHEADER is 40 bytes */
  88:   public static final int SIZE = 40;
  89: 
  90:     /**
  91:      * Compression types
  92:      */
  93:     public static final int BI_RGB = 0;
  94:     public static final int BI_RLE8 = 1;
  95:     public static final int BI_RLE4 = 2;
  96:     public static final int BI_BITFIELDS = 3;
  97: 
  98:     /**
  99:      * Creates the header from an input stream, which is not closed.
 100:      *
 101:      * @param in - the image input stream
 102:      * @throws IOException if an I/O error occured.
 103:      * @throws BMPException if the header was invalid
 104:      */
 105:   public BMPInfoHeader(ImageInputStream in) throws IOException, BMPException
 106:   {
 107:     byte[] data = new byte[SIZE];
 108: 
 109:     if (in.read(data) != SIZE)
 110:       throw new IOException("Couldn't read header.");
 111:     ByteBuffer buf = ByteBuffer.wrap(data);
 112:     buf.order(ByteOrder.LITTLE_ENDIAN);
 113: 
 114:     int n;
 115:     if ((n = buf.getInt()) != SIZE)
 116:       throw new BMPException("Invalid BITMAPINFOHEADER size: " + n);
 117: 
 118:     biWidth = buf.getInt();
 119:     biHeight = buf.getInt();
 120:     biPlanes = buf.getShort();
 121:     setBitCount(buf.getShort());
 122:     setCompression(buf.getInt());
 123:     biSizeImage = buf.getInt();
 124:     biXPelsPerMeter = buf.getInt();
 125:     biYPelsPerMeter = buf.getInt();
 126:     biClrUsed = buf.getInt();
 127:     biClrImportant = buf.getInt();
 128:   }
 129: 
 130:   /**
 131:    * Creates the info header from an output stream, which is not closed.
 132:    *
 133:    * @param out - the image output stream
 134:    * @param im - the image
 135:    * @param param - the image write param.
 136:    * @throws IOException if an I/O error occured.
 137:    */
 138:   public BMPInfoHeader(ImageOutputStream out, IIOImage im, ImageWriteParam param) throws IOException
 139:   {
 140:     RenderedImage img = im.getRenderedImage();
 141:     ColorModel cMod = img.getColorModel();
 142: 
 143:     biSize = SIZE;
 144:     biWidth = img.getWidth();
 145:     biHeight = img.getHeight();
 146:     biPlanes = 1;
 147: 
 148:     if (param != null && param.canWriteCompressed())
 149:       {
 150:         String compType = param.getCompressionType();
 151:         if (compType.equals("BI_RLE8"))
 152:           {
 153:             biCompression = BI_RLE8;
 154:             biBitCount = 8;
 155:           }
 156:         else if (compType.equals("BI_RLE4"))
 157:           {
 158:             biCompression = BI_RLE4;
 159:             biBitCount = 4;
 160:           }
 161:         else
 162:           {
 163:             biCompression = BI_RGB;
 164:             biBitCount = (short) cMod.getPixelSize();
 165:           }
 166:       }
 167:     else
 168:       {
 169:         biBitCount = (short) cMod.getPixelSize();
 170:         biCompression = BI_RGB;
 171:       }
 172: 
 173:     biXPelsPerMeter = 0x0;
 174:     biYPelsPerMeter = 0x0;
 175:     biClrUsed = 0;
 176:     biClrImportant = 0;
 177:     biSizeImage = ((biWidth * biHeight) * 3)
 178:                   + ((4 - ((biWidth * 3) % 4)) * biHeight);
 179:     out.write(intToDWord(biSize));
 180:     out.write(intToDWord(biWidth));
 181:     out.write(intToDWord(biHeight));
 182:     out.write(intToWord(biPlanes));
 183:     out.write(intToWord(biBitCount));
 184:     out.write(intToDWord(biCompression));
 185:     out.write(intToDWord(biSizeImage));
 186:     out.write(intToDWord(biXPelsPerMeter));
 187:     out.write(intToDWord(biYPelsPerMeter));
 188:     out.write(intToDWord(biClrUsed));
 189:     out.write(intToDWord(biClrImportant));
 190:   }
 191: 
 192:   /**
 193:    * Converts an int to a word, where the return value is stored in a
 194:    * 2-byte array.
 195:    *
 196:    * @param val - the value to convert
 197:    * @return the array
 198:    */
 199:   private byte[] intToWord(int val)
 200:   {
 201:     byte b[] = new byte[2];
 202:     b[0] = (byte) (val & 0x00FF);
 203:     b[1] = (byte) ((val >> 8) & 0x00FF);
 204:     return b;
 205:   }
 206: 
 207:   /**
 208:    * Converts an int to a double word, where the return value is
 209:    * stored in a 4-byte array.
 210:    *
 211:    * @param val - the value to convert
 212:    * @return the array
 213:    */
 214:   private byte[] intToDWord(int val)
 215:   {
 216:     byte b[] = new byte[4];
 217:     b[0] = (byte) (val & 0x00FF);
 218:     b[1] = (byte) ((val >> 8) & 0x000000FF);
 219:     b[2] = (byte) ((val >> 16) & 0x000000FF);
 220:     b[3] = (byte) ((val >> 24) & 0x000000FF);
 221:     return b;
 222:   }
 223: 
 224: 
 225:   public void setBitCount(short bitcount) throws BMPException
 226:   {
 227:     switch (bitcount)
 228:       {
 229:       case 1:
 230:       case 4:
 231:       case 8:
 232:       case 16:
 233:       case 24:
 234:       case 32:
 235:         biBitCount = bitcount;
 236:         break;
 237: 
 238:       default:
 239:         throw new BMPException("Invalid number of bits per pixel: " + bitcount);
 240:       }
 241:   }
 242: 
 243:   public short getBitCount()
 244:   {
 245:     return biBitCount;
 246:   }
 247: 
 248:   public void setCompression(int compression) throws BMPException
 249:   {
 250:     switch (compression)
 251:       {
 252:       case BI_RLE8:
 253:         if (getBitCount() != 8)
 254:           throw new BMPException("Invalid number of bits per pixel.");
 255:         biCompression = compression;
 256:         break;
 257:       case BI_RLE4:
 258:         if (getBitCount() != 4)
 259:           throw new BMPException("Invalid number of bits per pixel.");
 260:         biCompression = compression;
 261:         break;
 262: 
 263:       case BI_RGB:
 264:       case BI_BITFIELDS:
 265:         biCompression = compression;
 266:         break;
 267: 
 268:       default:
 269:         throw new BMPException("Unknown bitmap compression type.");
 270:       }
 271:   }
 272: 
 273:   public int getNumberOfPaletteEntries()
 274:   {
 275:     if (biClrUsed == 0)
 276:       switch (biBitCount)
 277:         {
 278:         case 1:
 279:           return 2;
 280:         case 4:
 281:           return 16;
 282:         case 8:
 283:           return 256;
 284: 
 285:         default: // should not happen
 286:           return 0;
 287:         }
 288: 
 289:     return biClrUsed;
 290:   }
 291: 
 292:   public int getCompression()
 293:   {
 294:     return biCompression;
 295:   }
 296: 
 297:   public Dimension getSize()
 298:   {
 299:     return new Dimension(biWidth, biHeight);
 300:   }
 301: 
 302:   public int getWidth()
 303:   {
 304:     return biWidth;
 305:   }
 306: 
 307:   public int getHeight()
 308:   {
 309:     return biHeight;
 310:   }
 311: 
 312:   public void setSize(Dimension d)
 313:   {
 314:     biWidth = (int) d.getWidth();
 315:     biHeight = (int) d.getHeight();
 316:   }
 317: }