Source for gnu.javax.imageio.png.PNGHeader

   1: /* PNGHeader.java -- PNG Header
   2:    Copyright (C) 2006 Free Software Foundation
   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.png;
  39: 
  40: /**
  41:  * A PNG Header chunk.
  42:  */
  43: public class PNGHeader extends PNGChunk
  44: {
  45:   private int width, height, depth;
  46:   private int colorType, compression, filter, interlace;
  47: 
  48:   /**
  49:    * The valid interlace types.
  50:    */
  51:   public static final int INTERLACE_NONE = 0;
  52:   public static final int INTERLACE_ADAM7 = 1;
  53: 
  54:   /**
  55:    * The valid color types.
  56:    */
  57:   public static final int GRAYSCALE = 0;
  58:   public static final int RGB = 2;
  59:   public static final int INDEXED = 3;
  60:   public static final int GRAYSCALE_WITH_ALPHA = 4;
  61:   public static final int RGB_WITH_ALPHA = 6;
  62: 
  63:   /**
  64:    * Parses a PNG Header chunk.
  65:    */
  66:   protected PNGHeader( int type, byte[] data, int crc ) throws PNGException
  67:   {
  68:     super( type, data, crc );
  69:     if( data.length < 13 )
  70:       throw new PNGException("Unexpectedly short header chunk. (" + data.length
  71:                              + " bytes)");
  72: 
  73:     width = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) |
  74:       ((data[2] & 0xFF) << 8) | (data[3] & 0xFF);
  75:     height = ((data[4] & 0xFF) << 24) | ( (data[5] & 0xFF) << 16 ) |
  76:       ((data[6] & 0xFF) << 8) | (data[7] & 0xFF);
  77:     depth = (data[8] & 0xFF);
  78:     colorType = (data[9] & 0xFF);
  79:     compression = (data[10] & 0xFF);
  80:     filter = (data[11] & 0xFF);
  81:     interlace = (data[12] & 0xFF);
  82:   }
  83: 
  84:   /**
  85:    * Create a PNG header chunk.
  86:    * Warning: This trusts that the parameters are valid.
  87:    */
  88:   public PNGHeader(int width, int height, int depth,
  89:                    int colorType, boolean interlace)
  90:   {
  91:     super( TYPE_HEADER );
  92:     data = new byte[ 13 ];
  93: 
  94:     this.width = width;
  95:     this.height = height;
  96:     this.depth = depth;
  97:     compression = filter = 0;
  98:     this.colorType = colorType;
  99:     this.interlace = interlace ? 1 : 0;
 100: 
 101:     // Build the data chunk.
 102:     byte[] a = getInt( width );
 103:     byte[] b = getInt( height );
 104:     data[0] = a[0]; data[1] = a[1]; data[2] = a[2]; data[3] = a[3];
 105:     data[4] = b[0]; data[5] = b[1]; data[6] = b[2]; data[7] = b[3];
 106:     data[8] = (byte)depth;
 107:     data[9] = (byte)colorType;
 108:     data[10] = (byte)compression;
 109:     data[11] = (byte)filter;
 110:     data[12] = (byte)this.interlace;
 111:   }
 112: 
 113:   /**
 114:    * Validates the header fields
 115:    */
 116:   public boolean isValidChunk()
 117:   {
 118:     if( !super.isValidChunk() )
 119:       return false;
 120: 
 121:     // width and height must be nonzero
 122:     if( width == 0 || height == 0 )
 123:       return false;
 124:     // colorType can be 0,2,3,4,6
 125:     if( (colorType & 0xFFFFFFF8) != 0 || colorType == 5 || colorType == 1)
 126:       return false;
 127:     // Possible valid depths are 1,2,4,8,16
 128:     if( !((depth == 1) || (depth == 2) || (depth == 4) ||
 129:         (depth == 8) || (depth == 16)) )
 130:       return false;
 131:     if( colorType == INDEXED && depth == 16 )
 132:       return false;
 133:     if( ( colorType == RGB || colorType == GRAYSCALE_WITH_ALPHA ||
 134:           colorType == RGB_WITH_ALPHA ) &&
 135:         depth < 8 )
 136:       return false;
 137:     // Only compression and filter methods zero are defined
 138:     if( compression != 0 || filter != 0 )
 139:       return false;
 140:     // Interlace methods, 0 and 1 are valid values.
 141:     if( (interlace & 0xFFFFFFFE) != 0 )
 142:       return false;
 143: 
 144:     return true;
 145:   }
 146: 
 147:   /**
 148:    * Returns <code>true</code> if this PNG is indexed-color
 149:    */
 150:   public boolean isIndexed()
 151:   {
 152:     return (colorType == INDEXED);
 153:   }
 154: 
 155:   /**
 156:    * Returns <code>true</code> if this PNG is grayscale
 157:    */
 158:   public boolean isGrayscale()
 159:   {
 160:     return ((colorType ==  GRAYSCALE) || (colorType == GRAYSCALE_WITH_ALPHA));
 161:   }
 162: 
 163:   /**
 164:    * Returns the color type of the image.
 165:    */
 166:   public int getColorType()
 167:   {
 168:     return colorType;
 169:   }
 170: 
 171:   /**
 172:    * Returns whether the image is interlaced or not.
 173:    */
 174:   public boolean isInterlaced()
 175:   {
 176:     return (interlace != 0);
 177:   }
 178: 
 179:   /**
 180:    * Returns the number of bytes per pixel.
 181:    */
 182:   public int bytesPerPixel()
 183:   {
 184:     switch( colorType )
 185:       {
 186:       case GRAYSCALE_WITH_ALPHA:
 187:         return ((depth * 2) >> 3);
 188:       case RGB:
 189:         return ((depth * 3) >> 3);
 190:       case RGB_WITH_ALPHA:
 191:         return ((depth * 4) >> 3);
 192: 
 193:       default:
 194:       case GRAYSCALE:
 195:       case INDEXED:
 196:         int i = (depth >> 3);
 197:         if( i > 0 ) return i;
 198:         return 1; // if bytes per pixel < 1, return 1 anyway.
 199:       }
 200:   }
 201: 
 202:   /**
 203:    * Returns the stride of one scanline, in bytes.
 204:    */
 205:   public int getScanlineStride()
 206:   {
 207:     long nBits = 0; // bits per scanline - scanlines are on byte offsets.
 208:     switch( colorType )
 209:       {
 210:       case GRAYSCALE:
 211:         nBits = width * depth;
 212:         break;
 213:       case RGB:
 214:         nBits = width * depth * 3;
 215:         break;
 216:       case INDEXED:
 217:         nBits = depth * width;
 218:         break;
 219:       case GRAYSCALE_WITH_ALPHA:
 220:         nBits = depth * width * 2;
 221:         break;
 222:       case RGB_WITH_ALPHA:
 223:         nBits = depth * width * 4;
 224:         break;
 225:       }
 226:     // Round up number of bits to the nearest byte
 227:     if( (nBits & 0x07) != 0 )
 228:       nBits += (8 - (nBits & 0x07));
 229: 
 230:     return (int)(nBits >> 3); // return # of bytes.
 231:   }
 232: 
 233:   public int getWidth()
 234:   {
 235:     return width;
 236:   }
 237: 
 238:   public int getHeight()
 239:   {
 240:     return height;
 241:   }
 242: 
 243:   public int getDepth()
 244:   {
 245:     return depth;
 246:   }
 247: 
 248:   /**
 249:    * Debugging string.
 250:    */
 251:   public String toString()
 252:   {
 253:     return "Header Chunk. Image width:"+width+" height:"+height+
 254:       " depth:"+depth+" color type:"+colorType+" compression type:"+
 255:       compression+" filter type:"+ filter+" interlace:"+interlace;
 256:   }
 257: }