Mega Code Archive

 
Categories / Java / 2D Graphics GUI
 

Image format info

/* #IFNDEF ALT_LICENSE                            ThinWire(R) RIA Ajax Framework                  Copyright (C) 2003-2007 Custom Credit Systems   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., 59   Temple Place, Suite 330, Boston, MA 02111-1307 USA   Users who would rather have a commercial license, warranty or support should   contact the following company who invented, built and supports the technology:                    Custom Credit Systems, Richardson, TX 75081, USA.                 email: info@thinwire.com    ph: +1 (888) 644-6405                           http://www.thinwire.com #ENDIF  [ v1.2_RC2 ]  */ import java.io.DataInput; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /**  * @author Joshua J. Gertzen  */ public class ImageInfo {     public enum Format {GIF,JPEG,PNG}          private String stringValue;     private String name;     private Format format;     private int width;     private int height;     public ImageInfo(String name) {         setName(name);     }          public int getWidth() {         return width;     }          public int getHeight() {         return height;     }          public Format getFormat() {         return format;     }          public String getName() {         return name;     }          private void setName(String name) {                 try {                                    InputStream is = new FileInputStream(name);                              if (is != null) {                 this.name = name;                 ImageParser ii = new ImageParser();                                         ii.setInput(is);                                  if (!ii.check())                     throw new UnsupportedOperationException("Unknown image file format for file.");                                  switch (ii.getFormat()) {                     case ImageParser.FORMAT_GIF:                         this.format = Format.GIF;                                                 break;                                              case ImageParser.FORMAT_JPEG:                         this.format = Format.JPEG;                         break;                                              case ImageParser.FORMAT_PNG:                         this.format = Format.PNG;                          break;                                          default:                         throw new UnsupportedOperationException("Unsupported image file format '" + ii.getFormatName() + "'.");                 }                 this.width = ii.getWidth();                 this.height = ii.getHeight();             } else {                 this.width = -1;                 this.height = -1;                 this.format = null;                 this.name = "";             }         } catch (Exception e) {             if (!(e instanceof RuntimeException)) e = new RuntimeException(e);             throw (RuntimeException)e;         }     }             public boolean equals(Object o) {         return o instanceof ImageInfo && toString().equals(o.toString());     }          public int hashCode() {         return toString().hashCode();     }          public String toString() {         if (stringValue == null) stringValue = "ImageInfo{name:" + name + ",format:" + format + ",width:" + width + ",height:" + height + "}";          return stringValue;     } } /* XXX Note: This class is a public domain class that is used by  * ImageInfo (above) to determine the width and height of an image.  * It is made package-private because it is not intended to be used  * directly.  */ /*  * ImageInfo.java  *  * Version 1.5  *  * A Java class to determine image width, height and color depth for  * a number of image file formats.  *  * Written by Marco Schmidt   * <http://www.geocities.com/marcoschmidt.geo/contact.html>.  *  * Contributed to the Public Domain.  *  * Last modification 2004-02-29  */ /**  * Get file format, image resolution, number of bits per pixel and optionally   * number of images, comments and physical resolution from   * JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM, PSD and SWF files   * (or input streams).  * <p>  * Use the class like this:  * <pre>  * ImageInfo ii = new ImageInfo();  * ii.setInput(in); // in can be InputStream or RandomAccessFile  * ii.setDetermineImageNumber(true); // default is false  * ii.setCollectComments(true); // default is false  * if (!ii.check()) {  *   System.err.println("Not a supported image file format.");  *   return;  * }  * System.out.println(ii.getFormatName() + ", " + ii.getMimeType() +   *   ", " + ii.getWidth() + " x " + ii.getHeight() + " pixels, " +   *   ii.getBitsPerPixel() + " bits per pixel, " + ii.getNumberOfImages() +  *   " image(s), " + ii.getNumberOfComments() + " comment(s).");  *  // there are other properties, check out the API documentation  * </pre>  * You can also use this class as a command line program.  * Call it with a number of image file names and URLs as parameters:  * <pre>  *   java ImageInfo *.jpg *.png *.gif http://somesite.tld/image.jpg  * </pre>  * or call it without parameters and pipe data to it:  * <pre>  *   java ImageInfo &lt; image.jpg    * </pre>  * <p>  * Known limitations:  * <ul>  * <li>When the determination of the number of images is turned off, GIF bits   *  per pixel are only read from the global header.  *  For some GIFs, local palettes change this to a typically larger  *  value. To be certain to get the correct color depth, call  *  setDetermineImageNumber(true) before calling check().  *  The complete scan over the GIF file will take additional time.</li>  * <li>Transparency information is not included in the bits per pixel count.  *  Actually, it was my decision not to include those bits, so it's a feature! ;-)</li>  * </ul>  * <p>  * Requirements:  * <ul>  * <li>Java 1.1 or higher</li>  * </ul>  * <p>  * The latest version can be found at <a href="http://www.geocities.com/marcoschmidt.geo/image-info.html">http://www.geocities.com/marcoschmidt.geo/image-info.html</a>.  * <p>  * Written by <a href="http://www.geocities.com/marcoschmidt.geo/contact.html">Marco Schmidt</a>.  * <p>  * This class is contributed to the Public Domain.  * Use it at your own risk.  * <p>  * Last modification 2004-02-29.  * <p>  * History:  * <ul>  * <li><strong>2001-08-24</strong> Initial version.</li>  * <li><strong>2001-10-13</strong> Added support for the file formats BMP and PCX.</li>  * <li><strong>2001-10-16</strong> Fixed bug in read(int[], int, int) that returned  * <li><strong>2002-01-22</strong> Added support for file formats Amiga IFF and Sun Raster (RAS).</li>  * <li><strong>2002-01-24</strong> Added support for file formats Portable Bitmap / Graymap / Pixmap (PBM, PGM, PPM) and Adobe Photoshop (PSD).  *   Added new method getMimeType() to return the MIME type associated with a particular file format.</li>  * <li><strong>2002-03-15</strong> Added support to recognize number of images in file. Only works with GIF.  *   Use {@link #setDetermineImageNumber} with <code>true</code> as argument to identify animated GIFs  *   ({@link #getNumberOfImages()} will return a value larger than <code>1</code>).</li>  * <li><strong>2002-04-10</strong> Fixed a bug in the feature 'determine number of images in animated GIF' introduced with version 1.1.  *   Thanks to Marcelo P. Lima for sending in the bug report.   *   Released as 1.1.1.</li>  * <li><strong>2002-04-18</strong> Added {@link #setCollectComments(boolean)}.   *  That new method lets the user specify whether textual comments are to be    *  stored in an internal list when encountered in an input image file / stream.  *  Added two methods to return the physical width and height of the image in dpi:   *   {@link #getPhysicalWidthDpi()} and {@link #getPhysicalHeightDpi()}.  *  If the physical resolution could not be retrieved, these methods return <code>-1</code>.  *  </li>  * <li><strong>2002-04-23</strong> Added support for the new properties physical resolution and  *   comments for some formats. Released as 1.2.</li>  * <li><strong>2002-06-17</strong> Added support for SWF, sent in by Michael Aird.  *  Changed checkJpeg() so that other APP markers than APP0 will not lead to a failure anymore.  *  Released as 1.3.</li>  * <li><strong>2003-07-28</strong> Bug fix - skip method now takes return values into consideration.  *  Less bytes than necessary may have been skipped, leading to flaws in the retrieved information in some cases.  *  Thanks to Bernard Bernstein for pointing that out.  *  Released as 1.4.</li>  * <li><strong>2004-02-29</strong> Added support for recognizing progressive JPEG and  *  interlaced PNG and GIF. A new method {@link #isProgressive()} returns whether ImageInfo  *  has found that the storage type is progressive (or interlaced).   *  Thanks to Joe Germuska for suggesting the feature.  *  Bug fix: BMP physical resolution is now correctly determined.  *  Released as 1.5.</li>  * </ul>  */ final class ImageParser {     /**      * Return value of {@link #getFormat()} for JPEG streams.      * ImageInfo can extract physical resolution and comments      * from JPEGs (only from APP0 headers).      * Only one image can be stored in a file.      * It is determined whether the JPEG stream is progressive       * (see {@link #isProgressive()}).      */     public static final int FORMAT_JPEG = 0;     /**      * Return value of {@link #getFormat()} for GIF streams.      * ImageInfo can extract comments from GIFs and count the number      * of images (GIFs with more than one image are animations).      * If you know of a place where GIFs store the physical resolution      * of an image, please      * <a href="http://www.geocities.com/marcoschmidt.geo/contact.html">send me a mail</a>!      * It is determined whether the GIF stream is interlaced (see {@link #isProgressive()}).      */     public static final int FORMAT_GIF = 1;     /**      * Return value of {@link #getFormat()} for PNG streams.      * PNG only supports one image per file.      * Both physical resolution and comments can be stored with PNG,      * but ImageInfo is currently not able to extract those.      * It is determined whether the PNG stream is interlaced (see {@link #isProgressive()}).      */     public static final int FORMAT_PNG = 2;     /**      * Return value of {@link #getFormat()} for BMP streams.      * BMP only supports one image per file.      * BMP does not allow for comments.      * The physical resolution can be stored.      */     public static final int FORMAT_BMP = 3;     /**      * Return value of {@link #getFormat()} for PCX streams.      * PCX does not allow for comments or more than one image per file.      * However, the physical resolution can be stored.      */     public static final int FORMAT_PCX = 4;     /**      * Return value of {@link #getFormat()} for IFF streams.      */     public static final int FORMAT_IFF = 5;     /**      * Return value of {@link #getFormat()} for RAS streams.      * Sun Raster allows for one image per file only and is not able to      * store physical resolution or comments.      */     public static final int FORMAT_RAS = 6;     /** Return value of {@link #getFormat()} for PBM streams. */     public static final int FORMAT_PBM = 7;     /** Return value of {@link #getFormat()} for PGM streams. */     public static final int FORMAT_PGM = 8;     /** Return value of {@link #getFormat()} for PPM streams. */     public static final int FORMAT_PPM = 9;     /** Return value of {@link #getFormat()} for PSD streams. */     public static final int FORMAT_PSD = 10;     /** Return value of {@link #getFormat()} for SWF (Shockwave) streams. */     public static final int FORMAT_SWF = 11;     public static final int COLOR_TYPE_UNKNOWN = -1;     public static final int COLOR_TYPE_TRUECOLOR_RGB = 0;     public static final int COLOR_TYPE_PALETTED = 1;     public static final int COLOR_TYPE_GRAYSCALE= 2;     public static final int COLOR_TYPE_BLACK_AND_WHITE = 3;     /**      * The names of all supported file formats.      * The FORMAT_xyz int constants can be used as index values for      * this array.      */     private static final String[] FORMAT_NAMES =         {"JPEG", "GIF", "PNG", "BMP", "PCX",           "IFF", "RAS", "PBM", "PGM", "PPM",           "PSD", "SWF"};     /**      * The names of the MIME types for all supported file formats.      * The FORMAT_xyz int constants can be used as index values for      * this array.      */     private static final String[] MIME_TYPE_STRINGS =         {"image/jpeg", "image/gif", "image/png", "image/bmp", "image/pcx",           "image/iff", "image/ras", "image/x-portable-bitmap", "image/x-portable-graymap", "image/x-portable-pixmap",           "image/psd", "application/x-shockwave-flash"};          private int width;     private int height;     private int bitsPerPixel;     private boolean progressive;     private int format;     private InputStream in;     private DataInput din;     private boolean collectComments = true;     private List<String> comments;     private boolean determineNumberOfImages;     private int numberOfImages;     private int physicalHeightDpi;     private int physicalWidthDpi;     private int bitBuf;     private int bitPos;     private void addComment(String s) {         if (comments == null) {             comments = new ArrayList<String>();         }         comments.add(s);     }                  /**      * Call this method after you have provided an input stream or file      * using {@link #setInput(InputStream)} or {@link #setInput(DataInput)}.      * If true is returned, the file format was known and information      * on the file's content can be retrieved using the various getXyz methods.      * @return if information could be retrieved from input      */     public boolean check() {         format = -1;         width = -1;         height = -1;         bitsPerPixel = -1;         numberOfImages = 1;         physicalHeightDpi = -1;         physicalWidthDpi = -1;         comments = null;         try {             int b1 = read() & 0xff;             int b2 = read() & 0xff;             if (b1 == 0x47 && b2 == 0x49) {                 return checkGif();             }             else             if (b1 == 0x89 && b2 == 0x50) {                 return checkPng();             }             else             if (b1 == 0xff && b2 == 0xd8) {                 return checkJpeg();             }             else             if (b1 == 0x42 && b2 == 0x4d) {                 return checkBmp();             }             else             if (b1 == 0x0a && b2 < 0x06) {                 return checkPcx();             }             else             if (b1 == 0x46 && b2 == 0x4f) {                 return checkIff();             }             else             if (b1 == 0x59 && b2 == 0xa6) {                 return checkRas();             }             else             if (b1 == 0x50 && b2 >= 0x31 && b2 <= 0x36) {                 return checkPnm(b2 - '0');             }             else             if (b1 == 0x38 && b2 == 0x42) {                 return checkPsd();             }             else             if (b1 == 0x46 && b2 == 0x57) {                 return checkSwf();             }             else {                 return false;             }         } catch (IOException ioe) {             return false;         }     }     private boolean checkBmp() throws IOException {         byte[] a = new byte[44];         if (read(a) != a.length) {             return false;         }         width = getIntLittleEndian(a, 16);         height = getIntLittleEndian(a, 20);         if (width < 1 || height < 1) {             return false;         }         bitsPerPixel = getShortLittleEndian(a, 26);         if (bitsPerPixel != 1 && bitsPerPixel != 4 &&             bitsPerPixel != 8 && bitsPerPixel != 16 &&             bitsPerPixel != 24 && bitsPerPixel != 32) {             return false;         }         int x = (int)(getIntLittleEndian(a, 36) * 0.0254);         if (x > 0) {             setPhysicalWidthDpi(x);         }         int y = (int)(getIntLittleEndian(a, 40) * 0.0254);         if (y > 0) {             setPhysicalHeightDpi(y);         }         format = FORMAT_BMP;         return true;     }     private boolean checkGif() throws IOException {         final byte[] GIF_MAGIC_87A = {0x46, 0x38, 0x37, 0x61};         final byte[] GIF_MAGIC_89A = {0x46, 0x38, 0x39, 0x61};         byte[] a = new byte[11]; // 4 from the GIF signature + 7 from the global header         if (read(a) != 11) {             return false;         }         if ((!equals(a, 0, GIF_MAGIC_89A, 0, 4)) &&             (!equals(a, 0, GIF_MAGIC_87A, 0, 4))) {             return false;         }         format = FORMAT_GIF;         width = getShortLittleEndian(a, 4);         height = getShortLittleEndian(a, 6);         int flags = a[8] & 0xff;         bitsPerPixel = ((flags >> 4) & 0x07) + 1;         progressive = (flags & 0x02) != 0;         if (!determineNumberOfImages) {             return true;         }         // skip global color palette         if ((flags & 0x80) != 0) {             int tableSize = (1 << ((flags & 7) + 1)) * 3;             skip(tableSize);         }         numberOfImages = 0;         int blockType;         do         {             blockType = read();             switch(blockType)             {                 case(0x2c): // image separator                 {                     if (read(a, 0, 9) != 9) {                         return false;                     }                     flags = a[8] & 0xff;                     int localBitsPerPixel = (flags & 0x07) + 1;                     if (localBitsPerPixel > bitsPerPixel) {                         bitsPerPixel = localBitsPerPixel;                     }                     if ((flags & 0x80) != 0) {                         skip((1 << localBitsPerPixel) * 3);                     }                     skip(1); // initial code length                     int n;                     do                     {                         n = read();                         if (n > 0) {                             skip(n);                         }                         else                         if (n == -1) {                             return false;                         }                     }                     while (n > 0);                     numberOfImages++;                     break;                 }                 case(0x21): // extension                 {                     int extensionType = read();                     if (collectComments && extensionType == 0xfe) {                         StringBuilder sb = new StringBuilder();                         int n;                         do                         {                             n = read();                             if (n == -1) {                                 return false;                             }                             if (n > 0) {                                 for (int i = 0; i < n; i++) {                                     int ch = read();                                     if (ch == -1) {                                         return false;                                     }                                     sb.append((char)ch);                                 }                             }                         }                         while (n > 0);                     } else {                         int n;                         do                         {                             n = read();                             if (n > 0) {                                 skip(n);                             }                             else                             if (n == -1) {                                 return false;                             }                         }                         while (n > 0);                     }                     break;                 }                 case(0x3b): // end of file                 {                     break;                 }                 default:                 {                     return false;                 }             }         }         while (blockType != 0x3b);         return true;     }     private boolean checkIff() throws IOException {         byte[] a = new byte[10];         // read remaining 2 bytes of file id, 4 bytes file size          // and 4 bytes IFF subformat         if (read(a, 0, 10) != 10) {             return false;         }         final byte[] IFF_RM = {0x52, 0x4d};         if (!equals(a, 0, IFF_RM, 0, 2)) {             return false;         }         int type = getIntBigEndian(a, 6);         if (type != 0x494c424d && // type must be ILBM...             type != 0x50424d20) { // ...or PBM             return false;         }         // loop chunks to find BMHD chunk         do {             if (read(a, 0, 8) != 8) {                 return false;             }             int chunkId = getIntBigEndian(a, 0);             int size = getIntBigEndian(a, 4);             if ((size & 1) == 1) {                 size++;             }             if (chunkId == 0x424d4844) { // BMHD chunk                 if (read(a, 0, 9) != 9) {                     return false;                 }                 format = FORMAT_IFF;                 width = getShortBigEndian(a, 0);                 height = getShortBigEndian(a, 2);                 bitsPerPixel = a[8] & 0xff;                 return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel < 33);             } else {                 skip(size);             }         } while (true);     }     private boolean checkJpeg() throws IOException {         byte[] data = new byte[12];         while (true) {             if (read(data, 0, 4) != 4) {                 return false;             }             int marker = getShortBigEndian(data, 0);             int size = getShortBigEndian(data, 2);             if ((marker & 0xff00) != 0xff00) {                 return false; // not a valid marker             }             if (marker == 0xffe0) { // APPx                  if (size < 14) {                     return false; // APPx header must be >= 14 bytes                 }                 if (read(data, 0, 12) != 12) {                     return false;                 }                 final byte[] APP0_ID = {0x4a, 0x46, 0x49, 0x46, 0x00};                 if (equals(APP0_ID, 0, data, 0, 5)) {                     if (data[7] == 1) {                         setPhysicalWidthDpi(getShortBigEndian(data, 8));                         setPhysicalHeightDpi(getShortBigEndian(data, 10));                     }                     else                     if (data[7] == 2) {                         int x = getShortBigEndian(data, 8);                         int y = getShortBigEndian(data, 10);                         setPhysicalWidthDpi((int)(x * 2.54f));                         setPhysicalHeightDpi((int)(y * 2.54f));                     }                 }                 skip(size - 14);             }             else             if (collectComments && size > 2 && marker == 0xfffe) { // comment                 size -= 2;                 byte[] chars = new byte[size];                 if (read(chars, 0, size) != size) {                     return false;                 }                 String comment = new String(chars, "iso-8859-1");                 comment = comment.trim();                 addComment(comment);             }             else             if (marker >= 0xffc0 && marker <= 0xffcf && marker != 0xffc4 && marker != 0xffc8) {                 if (read(data, 0, 6) != 6) {                     return false;                 }                 format = FORMAT_JPEG;                 bitsPerPixel = (data[0] & 0xff) * (data[5] & 0xff);                 progressive = marker == 0xffc2 || marker == 0xffc6 ||                     marker == 0xffca || marker == 0xffce;                 width = getShortBigEndian(data, 3);                 height = getShortBigEndian(data, 1);                 return true;             } else {                 skip(size - 2);             }         }     }     private boolean checkPcx() throws IOException {         byte[] a = new byte[64];         if (read(a) != a.length) {             return false;         }         if (a[0] != 1) { // encoding, 1=RLE is only valid value             return false;         }         // width / height         int x1 = getShortLittleEndian(a, 2);         int y1 = getShortLittleEndian(a, 4);         int x2 = getShortLittleEndian(a, 6);         int y2 = getShortLittleEndian(a, 8);         if (x1 < 0 || x2 < x1 || y1 < 0 || y2 < y1) {             return false;         }         width = x2 - x1 + 1;         height = y2 - y1 + 1;         // color depth         int bits = a[1];         int planes = a[63];         if (planes == 1 &&             (bits == 1 || bits == 2 || bits == 4 || bits == 8)) {             // paletted             bitsPerPixel = bits;         } else         if (planes == 3 && bits == 8) {             // RGB truecolor             bitsPerPixel = 24;         } else {             return false;         }         setPhysicalWidthDpi(getShortLittleEndian(a, 10));         setPhysicalHeightDpi(getShortLittleEndian(a, 10));         format = FORMAT_PCX;         return true;     }     private boolean checkPng() throws IOException {         final byte[] PNG_MAGIC = {0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};         byte[] a = new byte[27];         if (read(a) != 27) {             return false;         }         if (!equals(a, 0, PNG_MAGIC, 0, 6)) {             return false;         }         format = FORMAT_PNG;         width = getIntBigEndian(a, 14);         height = getIntBigEndian(a, 18);         bitsPerPixel = a[22] & 0xff;         int colorType = a[23] & 0xff;         if (colorType == 2 || colorType == 6) {             bitsPerPixel *= 3;         }         progressive = (a[26] & 0xff) != 0;         return true;     }     private boolean checkPnm(int id) throws IOException {         if (id < 1 || id > 6) {             return false;         }         final int[] PNM_FORMATS = {FORMAT_PBM, FORMAT_PGM, FORMAT_PPM};         format = PNM_FORMATS[(id - 1) % 3];         boolean hasPixelResolution = false;         String s;         while (true)         {             s = readLine();             if (s != null) {                 s = s.trim();             }             if (s == null || s.length() < 1) {                 continue;             }             if (s.charAt(0) == '#') { // comment                 if (collectComments && s.length() > 1) {                     addComment(s.substring(1));                 }                 continue;             }             if (!hasPixelResolution) { // split "343 966" into width=343, height=966                 int spaceIndex = s.indexOf(' ');                 if (spaceIndex == -1) {                     return false;                 }                 String widthString = s.substring(0, spaceIndex);                 spaceIndex = s.lastIndexOf(' ');                 if (spaceIndex == -1) {                     return false;                 }                 String heightString = s.substring(spaceIndex + 1);                 try {                     width = Integer.parseInt(widthString);                     height = Integer.parseInt(heightString);                 } catch (NumberFormatException nfe) {                     return false;                 }                 if (width < 1 || height < 1) {                     return false;                 }                 if (format == FORMAT_PBM) {                     bitsPerPixel = 1;                     return true;                 }                 hasPixelResolution = true;             }             else             {                 int maxSample;                 try {                     maxSample = Integer.parseInt(s);                 } catch (NumberFormatException nfe) {                     return false;                 }                 if (maxSample < 0) {                     return false;                 }                 for (int i = 0; i < 25; i++) {                     if (maxSample < (1 << (i + 1))) {                         bitsPerPixel = i + 1;                         if (format == FORMAT_PPM) {                             bitsPerPixel *= 3;                         }                         return true;                     }                 }                 return false;             }         }     }     private boolean checkPsd() throws IOException {         byte[] a = new byte[24];         if (read(a) != a.length) {             return false;         }         final byte[] PSD_MAGIC = {0x50, 0x53};         if (!equals(a, 0, PSD_MAGIC, 0, 2)) {             return false;         }         format = FORMAT_PSD;         width = getIntBigEndian(a, 16);         height = getIntBigEndian(a, 12);         int channels = getShortBigEndian(a, 10);         int depth = getShortBigEndian(a, 20);         bitsPerPixel = channels * depth;         return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 64);     }     private boolean checkRas() throws IOException {         byte[] a = new byte[14];         if (read(a) != a.length) {             return false;         }         final byte[] RAS_MAGIC = {0x6a, (byte)0x95};         if (!equals(a, 0, RAS_MAGIC, 0, 2)) {             return false;         }         format = FORMAT_RAS;         width = getIntBigEndian(a, 2);         height = getIntBigEndian(a, 6);         bitsPerPixel = getIntBigEndian(a, 10);         return (width > 0 && height > 0 && bitsPerPixel > 0 && bitsPerPixel <= 24);     }     // Written by Michael Aird.     private boolean checkSwf() throws IOException {         //get rid of the last byte of the signature, the byte of the version and 4 bytes of the size         byte[] a = new byte[6];         if (read(a) != a.length) {             return false;         }         format = FORMAT_SWF;         int bitSize = (int)readUBits( 5 );         int maxX = (int)readSBits( bitSize );         int maxY = (int)readSBits( bitSize );         width = maxX/20; //cause we're in twips         height = maxY/20;  //cause we're in twips         setPhysicalWidthDpi(72);         setPhysicalHeightDpi(72);         return (width > 0 && height > 0);     }     private boolean equals(byte[] a1, int offs1, byte[] a2, int offs2, int num) {         while (num-- > 0) {             if (a1[offs1++] != a2[offs2++]) {                 return false;             }         }         return true;     }     /**       * If {@link #check()} was successful, returns the image's number of bits per pixel.      * Does not include transparency information like the alpha channel.      * @return number of bits per image pixel      */     public int getBitsPerPixel() {         return bitsPerPixel;     }     /**      * Returns the index'th comment retrieved from the image.      * @throws IllegalArgumentException if index is smaller than 0 or larger than or equal      * to the number of comments retrieved      * @see #getNumberOfComments      */     public String getComment(int index) {         if (comments == null || index < 0 || index >= comments.size()) {             throw new IllegalArgumentException("Not a valid comment index: " + index);         }         return comments.get(index);     }     /**      * If {@link #check()} was successful, returns the image format as one      * of the FORMAT_xyz constants from this class.      * Use {@link #getFormatName()} to get a textual description of the file format.      * @return file format as a FORMAT_xyz constant      */     public int getFormat() {         return format;     }     /**      * If {@link #check()} was successful, returns the image format's name.      * Use {@link #getFormat()} to get a unique number.      * @return file format name      */     public String getFormatName() {         if (format >= 0 && format < FORMAT_NAMES.length) {             return FORMAT_NAMES[format];         } else {             return "?";         }     }     /**       * If {@link #check()} was successful, returns one the image's vertical      * resolution in pixels.      * @return image height in pixels      */     public int getHeight() {         return height;     }     private int getIntBigEndian(byte[] a, int offs) {         return             (a[offs] & 0xff) << 24 |              (a[offs + 1] & 0xff) << 16 |              (a[offs + 2] & 0xff) << 8 |              a[offs + 3] & 0xff;     }     private int getIntLittleEndian(byte[] a, int offs) {         return             (a[offs + 3] & 0xff) << 24 |              (a[offs + 2] & 0xff) << 16 |              (a[offs + 1] & 0xff) << 8 |              a[offs] & 0xff;     }     /**       * If {@link #check()} was successful, returns a String with the      * MIME type of the format.      * @return MIME type, e.g. <code>image/jpeg</code>      */     public String getMimeType() {         if (format >= 0 && format < MIME_TYPE_STRINGS.length) {             if (format == FORMAT_JPEG && progressive)             {                 return "image/pjpeg";             }             return MIME_TYPE_STRINGS[format];         } else {             return null;         }     }     /**      * If {@link #check()} was successful and {@link #setCollectComments(boolean)} was called with      * <code>true</code> as argument, returns the number of comments retrieved       * from the input image stream / file.      * Any number &gt;= 0 and smaller than this number of comments is then a      * valid argument for the {@link #getComment(int)} method.      * @return number of comments retrieved from input image      */     public int getNumberOfComments()     {         if (comments == null) {             return 0;         } else {             return comments.size();         }     }     /**      * Returns the number of images in the examined file.      * Assumes that <code>setDetermineImageNumber(true);</code> was called before      * a successful call to {@link #check()}.      * This value can currently be only different from <code>1</code> for GIF images.      * @return number of images in file      */     public int getNumberOfImages()     {         return numberOfImages;     }     /**      * Returns the physical height of this image in dots per inch (dpi).      * Assumes that {@link #check()} was successful.      * Returns <code>-1</code> on failure.      * @return physical height (in dpi)      * @see #getPhysicalWidthDpi()      * @see #getPhysicalHeightInch()      */     public int getPhysicalHeightDpi() {         return physicalHeightDpi;     }     /**      * If {@link #check()} was successful, returns the physical width of this image in dpi (dots per inch)      * or -1 if no value could be found.      * @return physical height (in dpi)      * @see #getPhysicalHeightDpi()      * @see #getPhysicalWidthDpi()      * @see #getPhysicalWidthInch()      */     public float getPhysicalHeightInch() {         int h = getHeight();         int ph = getPhysicalHeightDpi();         if (h > 0 && ph > 0) {             return ((float)h) / ((float)ph);         } else {             return -1.0f;         }     }     /**      * If {@link #check()} was successful, returns the physical width of this image in dpi (dots per inch)      * or -1 if no value could be found.      * @return physical width (in dpi)      * @see #getPhysicalHeightDpi()      * @see #getPhysicalWidthInch()      * @see #getPhysicalHeightInch()      */     public int getPhysicalWidthDpi() {         return physicalWidthDpi;     }     /**      * Returns the physical width of an image in inches, or      * <code>-1.0f</code> if width information is not available.      * Assumes that {@link #check} has been called successfully.      * @return physical width in inches or <code>-1.0f</code> on failure      * @see #getPhysicalWidthDpi      * @see #getPhysicalHeightInch      */     public float getPhysicalWidthInch() {         int w = getWidth();         int pw = getPhysicalWidthDpi();         if (w > 0 && pw > 0) {             return ((float)w) / ((float)pw);         } else {             return -1.0f;         }     }     private int getShortBigEndian(byte[] a, int offs) {         return             (a[offs] & 0xff) << 8 |              (a[offs + 1] & 0xff);     }     private int getShortLittleEndian(byte[] a, int offs) {         return (a[offs] & 0xff) | (a[offs + 1] & 0xff) << 8;     }     /**       * If {@link #check()} was successful, returns one the image's horizontal      * resolution in pixels.      * @return image width in pixels      */     public int getWidth() {         return width;     }     /**      * Returns whether the image is stored in a progressive (also called: interlaced) way.      * @return true for progressive/interlaced, false otherwise      */     public boolean isProgressive()     {         return progressive;     }     private int read() throws IOException {         if (in != null) {             return in.read();         } else {             return din.readByte();         }     }     private int read(byte[] a) throws IOException {         if (in != null) {             return in.read(a);         } else {             din.readFully(a);             return a.length;         }     }     private int read(byte[] a, int offset, int num) throws IOException {         if (in != null) {             return in.read(a, offset, num);         } else {             din.readFully(a, offset, num);             return num;         }     }     private String readLine() throws IOException {         return readLine(new StringBuilder());     }     private String readLine(StringBuilder sb) throws IOException {         boolean finished;         do {             int value = read();             finished = (value == -1 || value == 10);             if (!finished) {                 sb.append((char)value);             }         } while (!finished);         return sb.toString();     }     private long readUBits( int numBits ) throws IOException     {         if (numBits == 0) {             return 0;         }         int bitsLeft = numBits;         long result = 0;         if (bitPos == 0) { //no value in the buffer - read a byte             if (in != null) {                 bitBuf = in.read();             } else {                 bitBuf = din.readByte();             }             bitPos = 8;         }                  while( true )         {             int shift = bitsLeft - bitPos;             if( shift > 0 )             {                 // Consume the entire buffer                 result |= bitBuf << shift;                 bitsLeft -= bitPos;                 // Get the next byte from the input stream                 if (in != null) {                   bitBuf = in.read();                 } else {                   bitBuf = din.readByte();                 }                 bitPos = 8;             }             else             {                 // Consume a portion of the buffer                 result |= bitBuf >> -shift;                 bitPos -= bitsLeft;                 bitBuf &= 0xff >> (8 - bitPos); // mask off the consumed bits                 return result;             }         }             }              /**      * Read a signed value from the given number of bits      */     private int readSBits( int numBits ) throws IOException     {         // Get the number as an unsigned value.         long uBits = readUBits( numBits );         // Is the number negative?         if( ( uBits & (1L << (numBits - 1))) != 0 )         {             // Yes. Extend the sign.             uBits |= -1L << numBits;         }         return (int)uBits;             }       /**      * Specify whether textual comments are supposed to be extracted from input.      * Default is <code>false</code>.      * If enabled, comments will be added to an internal list.      * @param newValue if <code>true</code>, this class will read comments      * @see #getNumberOfComments      * @see #getComment      */     public void setCollectComments(boolean newValue)     {         collectComments = newValue;     }     /**      * Specify whether the number of images in a file is to be      * determined - default is <code>false</code>.      * This is a special option because some file formats require running over      * the entire file to find out the number of images, a rather time-consuming      * task.      * Not all file formats support more than one image.      * If this method is called with <code>true</code> as argument,      * the actual number of images can be queried via       * {@link #getNumberOfImages()} after a successful call to      * {@link #check()}.      * @param newValue will the number of images be determined?      * @see #getNumberOfImages      */     public void setDetermineImageNumber(boolean newValue)     {         determineNumberOfImages = newValue;     }     /**      * Set the input stream to the argument stream (or file).       * Note that {@link java.io.RandomAccessFile} implements      * {@link java.io.DataInput}.      * @param dataInput the input stream to read from      */     public void setInput(DataInput dataInput) {         din = dataInput;         in = null;     }     /**      * Set the input stream to the argument stream (or file).      * @param inputStream the input stream to read from      */     public void setInput(InputStream inputStream) {         in = inputStream;         din = null;     }     private void setPhysicalHeightDpi(int newValue) {         physicalWidthDpi = newValue;     }     private void setPhysicalWidthDpi(int newValue) {         physicalHeightDpi = newValue;     }     private void skip(int num) throws IOException {         while (num > 0) {             long result;             if (in != null) {                 result = in.skip(num);             } else {                 result = din.skipBytes(num);             }             if (result > 0) {                 num -= result;             }         }     } }