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 */ BMPInfoHeader(ImageInputStream in)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 */ BMPInfoHeader(ImageOutputStream out, IIOImage im, ImageWriteParam param)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 */ intToWord(int val)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 */ intToDWord(int val)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 setBitCount(short bitcount)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 getBitCount()243 public short getBitCount() 244 { 245 return biBitCount; 246 } 247 setCompression(int compression)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 getNumberOfPaletteEntries()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 getCompression()292 public int getCompression() 293 { 294 return biCompression; 295 } 296 getSize()297 public Dimension getSize() 298 { 299 return new Dimension(biWidth, biHeight); 300 } 301 getWidth()302 public int getWidth() 303 { 304 return biWidth; 305 } 306 getHeight()307 public int getHeight() 308 { 309 return biHeight; 310 } 311 setSize(Dimension d)312 public void setSize(Dimension d) 313 { 314 biWidth = (int) d.getWidth(); 315 biHeight = (int) d.getHeight(); 316 } 317 } 318