Java/2D Graphics GUI/ImageReader — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
 
м (1 версия)
 
(нет различий)

Текущая версия на 06:54, 1 июня 2010

Add Image IO Read Progress Listener to ImageReader

  
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
public class Main{
  static public void main(String args[]) throws Exception {
    FileInputStream fileInputStream = new FileInputStream("a.gif");
    Iterator readers = ImageIO.getImageReadersBySuffix("GIF");
    ImageReader imageReader = (ImageReader) readers.next();
    ImageInputStream imageInputStream = ImageIO.createImageInputStream(fileInputStream);
    imageReader.setInput(imageInputStream, false);
    imageReader.addIIOReadProgressListener(new MyIIOReadProgressListener());
    BufferedImage image = imageReader.read(0);
    Iterator imageWriters = ImageIO.getImageWritersBySuffix("JPG");
    ImageWriter imageWriter = (ImageWriter) imageWriters.next();
    File file = new File("b.JPG");
    ImageOutputStream ios = ImageIO.createImageOutputStream(file);
    imageWriter.setOutput(ios);
    imageWriter.write(image);
  }
}
class MyIIOReadProgressListener implements IIOReadProgressListener{
  public void imageComplete(ImageReader source) {
    System.out.println("image complete " + source);
  }
  public void imageProgress(ImageReader source, float percentageDone) {
    System.out.println("image progress " + source + ": " + percentageDone + "%");
  }
  public void imageStarted(ImageReader source, int imageIndex) {
    System.out.println("image #" + imageIndex + " started " + source);
  }
  public void readAborted(ImageReader source) {
    System.out.println("read aborted " + source);
  }
  public void sequenceComplete(ImageReader source) {
    System.out.println("sequence complete " + source);
  }
  public void sequenceStarted(ImageReader source, int minIndex) {
    System.out.println("sequence started " + source + ": " + minIndex);
  }
  public void thumbnailComplete(ImageReader source) {
    System.out.println("thumbnail complete " + source);
  }
  public void thumbnailProgress(ImageReader source, float percentageDone) {
    System.out.println("thumbnail started " + source + ": " + percentageDone + "%");
  }
  public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {
    System.out.println("thumbnail progress " + source + ", " + thumbnailIndex + " of "
        + imageIndex);
  }
}



Detect the file type of the input stream prior to reading the image

  
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class Main {
  public static void main(String[] argv) throws Exception {
    ImageInputStream imageStream = ImageIO.createImageInputStream(new URL("").openStream());
    Iterator<ImageReader> readers = ImageIO.getImageReaders(imageStream);
    ImageReader reader = null;
    if (!readers.hasNext()) {
      imageStream.close();
      return;
    } else {
      reader = readers.next();
    }
    String formatName = reader.getFormatName();
    if (!formatName.equalsIgnoreCase("jpeg") && !formatName.equalsIgnoreCase("png")
        && !formatName.equalsIgnoreCase("gif")) {
      imageStream.close();
      return;
    }
    reader.setInput(imageStream, true, true);
    BufferedImage theImage = reader.read(0);
    reader.dispose();
    imageStream.close();
  }
}



Determining the Format of an Image in a File

  
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class Main {
  public static void main(String[] argv) throws Exception {
    File file = new File("image.gif");
    System.out.println(getFormatName(file));
    InputStream is = new FileInputStream(file);
    is.close();
    System.out.println(getFormatName(is));
  }
  private static String getFormatName(Object o) {
    try {
      ImageInputStream iis = ImageIO.createImageInputStream(o);
      Iterator iter = ImageIO.getImageReaders(iis);
      if (!iter.hasNext()) {
        return null;
      }
      ImageReader reader = (ImageReader) iter.next();
      iis.close();
      return reader.getFormatName();
    } catch (IOException e) {
    }
    return null;
  }
}



Get file format, image resolution, number of bits per pixel (JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM, PSD and SWF files)

   
//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)
/*
 * 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.ru/marcoschmidt.geo/contact.html>.
 *
 * Contributed to the Public Domain.
 *
 * Last modification 2004-02-29
 */
/*
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://wingsframework.org).
 *
 * wingS 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.
 *
 * Please see COPYING for the complete licence.
 */
import java.io.DataInput;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
 * 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 !
     * 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.
     */
    public 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.
     */
    public 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 int colorType = COLOR_TYPE_UNKNOWN;
    private boolean progressive;
    private int format;
    private InputStream in;
    private DataInput din;
    private boolean collectComments = true;
    private List 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();
        }
        comments.add(s);
    }
    /**
     * Call this method after you have provided an input stream or file
     * using {@link #setInput(java.io.InputStream)} or {@link #setInput(java.io.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)) {
                    //System.out.println("data 7=" + data[7]);
                    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;
        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 minX = readSBits(bitSize);
        int maxX = readSBits(bitSize);
        int minY = readSBits(bitSize);
        int maxY = 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);
    }
    /**
     * Run over String list, return false iff at least one of the arguments
     * equals <code>-c</code>.
     */
    private static boolean determineVerbosity(String[] args) {
        if (args != null && args.length > 0) {
            for (int i = 0; i < args.length; i++) {
                if ("-c".equals(args[i])) {
                    return false;
                }
            }
        }
        return true;
    }
    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 java.lang.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 (String) 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;
    }
    /**
     * To use this class as a command line application, give it either
     * some file names as parameters (information on them will be
     * printed to standard output, one line per file) or call
     * it with no parameters. It will then check data given to it
     * via standard input.
     *
     * @param args the program arguments which must be file names
     */
    public static void main(String[] args) {
        ImageInfo imageInfo = new ImageInfo();
        imageInfo.setDetermineImageNumber(true);
        boolean verbose = determineVerbosity(args);
        if (args.length == 0) {
            run(null, System.in, imageInfo, verbose);
        } else {
            int index = 0;
            while (index < args.length) {
                InputStream in = null;
                try {
                    String name = args[index++];
                    System.out.print(name + ";");
                    if (name.startsWith("http://")) {
                        in = new URL(name).openConnection().getInputStream();
                    } else {
                        in = new FileInputStream(name);
                    }
                    run(name, in, imageInfo, verbose);
                    in.close();
                } catch (Exception e) {
                    System.out.println(e);
                    try {
                        in.close();
                    } catch (Exception ee) {
                    }
                }
            }
        }
    }
    private static void print(String sourceName, ImageInfo ii, boolean verbose) {
        if (verbose) {
            printVerbose(sourceName, ii);
        } else {
            printCompact(sourceName, ii);
        }
    }
    private static void printCompact(String sourceName, ImageInfo imageInfo) {
        System.out.println(imageInfo.getFormatName() + ";" +
                imageInfo.getMimeType() + ";" +
                imageInfo.getWidth() + ";" +
                imageInfo.getHeight() + ";" +
                imageInfo.getBitsPerPixel() + ";" +
                imageInfo.getNumberOfImages() + ";" +
                imageInfo.getPhysicalWidthDpi() + ";" +
                imageInfo.getPhysicalHeightDpi() + ";" +
                imageInfo.getPhysicalWidthInch() + ";" +
                imageInfo.getPhysicalHeightInch() + ";" +
                imageInfo.isProgressive());
    }
    private static void printLine(int indentLevels, String text, float value, float minValidValue) {
        if (value < minValidValue) {
            return;
        }
        printLine(indentLevels, text, Float.toString(value));
    }
    private static void printLine(int indentLevels, String text, int value, int minValidValue) {
        if (value >= minValidValue) {
            printLine(indentLevels, text, Integer.toString(value));
        }
    }
    private static void printLine(int indentLevels, String text, String value) {
        if (value == null || value.length() == 0) {
            return;
        }
        while (indentLevels-- > 0) {
            System.out.print("\t");
        }
        if (text != null && text.length() > 0) {
            System.out.print(text);
            System.out.print(" ");
        }
        System.out.println(value);
    }
    private static void printVerbose(String sourceName, ImageInfo ii) {
        printLine(0, null, sourceName);
        printLine(1, "File format: ", ii.getFormatName());
        printLine(1, "MIME type: ", ii.getMimeType());
        printLine(1, "Width (pixels): ", ii.getWidth(), 1);
        printLine(1, "Height (pixels): ", ii.getHeight(), 1);
        printLine(1, "Bits per pixel: ", ii.getBitsPerPixel(), 1);
        printLine(1, "Progressive: ", Boolean.toString(ii.isProgressive()));
        printLine(1, "Number of images: ", ii.getNumberOfImages(), 1);
        printLine(1, "Physical width (dpi): ", ii.getPhysicalWidthDpi(), 1);
        printLine(1, "Physical height (dpi): ", ii.getPhysicalHeightDpi(), 1);
        printLine(1, "Physical width (inches): ", ii.getPhysicalWidthInch(), 1.0f);
        printLine(1, "Physical height (inches): ", ii.getPhysicalHeightInch(), 1.0f);
        int numComments = ii.getNumberOfComments();
        printLine(1, "Number of textual comments: ", numComments, 1);
        if (numComments > 0) {
            for (int i = 0; i < numComments; i++) {
                printLine(2, null, ii.getComment(i));
            }
        }
    }
    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;
    }
    private void synchBits() {
        bitBuf = 0;
        bitPos = 0;
    }
    private String readLine(int firstChar) throws IOException {
        StringBuilder result = new StringBuilder();
        result.append((char) firstChar);
        return readLine(result);
    }
    private static void run(String sourceName, InputStream in, ImageInfo imageInfo, boolean verbose) {
        imageInfo.setInput(in);
        imageInfo.setDetermineImageNumber(false);
        imageInfo.setCollectComments(verbose);
        if (imageInfo.check()) {
            print(sourceName, imageInfo, verbose);
        }
    }
    /**
     * 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;
            }
        }
    }
}



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.ru    ph: +1 (888) 644-6405
                          http://www.thinwire.ru
#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.ru/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 !
     * 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;
            }
        }
    }
}



Image observer blocks until the image is completely loaded. AWT defers the loading of images until they are painted on a graphic.

  
/* 
 * JCommon : a free general purpose class library for the Java(tm) platform
 * 
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 *
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
 * in the United States and other countries.]
 *
 * -------------------------
 * WaitingImageObserver.java
 * -------------------------
 * (C)opyright 2000-2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner
 * Contributor(s):   Stefan Prange;
 *
 * $Id: WaitingImageObserver.java,v 1.8 2008/09/10 09:24:41 mungady Exp $
 *
 * Changes (from 8-Feb-2002)
 * -------------------------
 * 15-Apr-2002 : first version used by ImageElement.
 * 16-May-2002 : Line delimiters adjusted
 * 04-Jun-2002 : Documentation and added a NullPointerCheck for the constructor.
 * 14-Jul-2002 : BugFixed: WaitingImageObserver dead-locked (bugfix by Stefan
 *               Prange)
 * 18-Mar-2003 : Updated header and made minor Javadoc changes (DG);
 * 21-Sep-2003 : Moved from JFreeReport.
 */

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.Serializable;
/**
 * This image observer blocks until the image is completely loaded. AWT
 * defers the loading of images until they are painted on a graphic.
 *
 * While printing reports it is not very nice, not to know whether a image
 * was completely loaded, so this observer forces the loading of the image
 * until a final state (either ALLBITS, ABORT or ERROR) is reached.
 *
 * @author Thomas Morgner
 */
public class WaitingImageObserver implements ImageObserver, Serializable,
                                             Cloneable
{
  /** For serialization. */
  static final long serialVersionUID = -807204410581383550L;
  /** The lock. */
  private boolean lock;
  /** The image. */
  private Image image;
  /** A flag that signals an error. */
  private boolean error;
  /**
   * Creates a new <code>ImageObserver<code> for the given <code>Image<code>.
   * The observer has to be started by an external thread.
   *
   * @param image  the image to observe (<code>null</code> not permitted).
   */
  public WaitingImageObserver(final Image image) {
    if (image == null) {
      throw new NullPointerException();
    }
    this.image = image;
    this.lock = true;
  }
  /**
   * Callback function used by AWT to inform that more data is available. The
   * observer waits until either all data is loaded or AWT signals that the
   * image cannot be loaded.
   *
   * @param     img   the image being observed.
   * @param     infoflags   the bitwise inclusive OR of the following
   *               flags:  <code>WIDTH</code>, <code>HEIGHT</code>,
   *               <code>PROPERTIES</code>, <code>SOMEBITS</code>,
   *               <code>FRAMEBITS</code>, <code>ALLBITS</code>,
   *               <code>ERROR</code>, <code>ABORT</code>.
   * @param     x   the <i>x</i> coordinate.
   * @param     y   the <i>y</i> coordinate.
   * @param     width    the width.
   * @param     height   the height.
   *
   * @return    <code>false</code> if the infoflags indicate that the
   *            image is completely loaded; <code>true</code> otherwise.
   */
  public synchronized boolean imageUpdate(
      final Image img,
      final int infoflags,
      final int x,
      final int y,
      final int width,
      final int height) {
    if ((infoflags & ImageObserver.ALLBITS) == ImageObserver.ALLBITS) {
        this.lock = false;
        this.error = false;
        notifyAll();
        return false;
    }
    else if ((infoflags & ImageObserver.ABORT) == ImageObserver.ABORT
        || (infoflags & ImageObserver.ERROR) == ImageObserver.ERROR) {
        this.lock = false;
        this.error = true;
        notifyAll();
        return false;
    }
    //notifyAll();
    return true;
  }
  /**
   * The workerthread. Simply draws the image to a BufferedImage"s
   * Graphics-Object and waits for the AWT to load the image.
   */
  public synchronized void waitImageLoaded() {
    if (this.lock == false)
    {
      return;
    }
    final BufferedImage img = new BufferedImage(
        1, 1, BufferedImage.TYPE_INT_RGB
    );
    final Graphics g = img.getGraphics();
    while (this.lock) {
      if (g.drawImage(this.image, 0, 0, img.getWidth(this),
            img.getHeight(this), this)) {
        return;
      }
      try {
        wait(500);
      }
      catch (InterruptedException e) {
        System.out.println("WaitingImageObserver.waitImageLoaded(): InterruptedException thrown"+e);
      }
    }
  }
  /**
   * Returns <code>true</code> if loading is complete, and <code>false</code>
   * otherwise.
   *
   * @return A boolean.
   */
  public boolean isLoadingComplete() {
    return this.lock == false;
  }
  /**
   * Returns true if there is an error condition, and false otherwise.
   *
   * @return A boolean.
   */
  public boolean isError() {
    return this.error;
  }
}



List the image formats that can be read and written

  
import java.util.Arrays;
import javax.imageio.ImageIO;
public class Main {
  public static void main(String[] argv) throws Exception {
    String[] formatNames = ImageIO.getReaderFormatNames();
    System.out.println(Arrays.toString(formatNames));
  }
}



Read an Image from a file

  
import java.awt.BorderLayout;
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
  public static void main(String[] argv) throws Exception {
    File sourceimage = new File("source.gif");
    Image image = ImageIO.read(sourceimage);
    JFrame frame = new JFrame();
    JLabel label = new JLabel(new ImageIcon(image));
    frame.getContentPane().add(label, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
  }
}



Read an Image from inputStream

  
import java.awt.BorderLayout;
import java.awt.Image;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
  public static void main(String[] argv) throws Exception {
    InputStream is = new BufferedInputStream(new FileInputStream("s.gif"));
    Image image = ImageIO.read(is);
    JFrame frame = new JFrame();
    JLabel label = new JLabel(new ImageIcon(image));
    frame.getContentPane().add(label, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
  }
}



Read an Image from URL

  
import java.awt.BorderLayout;
import java.awt.Image;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main {
  public static void main(String[] argv) throws Exception {
    URL url = new URL("http://yourServer.ru/source.gif");
    Image image = ImageIO.read(url);
    JFrame frame = new JFrame();
    JLabel label = new JLabel(new ImageIcon(image));
    frame.getContentPane().add(label, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
  }
}



Show Image with ImageReader

  
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.JFrame;
public class Main extends Panel {
  private BufferedImage images[];
  private int imageIndex = 0;
  public Main() throws Exception {
    String filename = "a.png";
    FileInputStream inputStream = new FileInputStream(filename);
    String extensionName = filename.substring(filename.lastIndexOf(".") + 1);
    Iterator readers = ImageIO.getImageReadersBySuffix(extensionName);
    ImageReader imageReader = (ImageReader) readers.next();
    ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream);
    imageReader.setInput(imageInputStream, false);
    int num = imageReader.getNumImages(true);
    images = new BufferedImage[num];
    for (int i = 0; i < num; ++i) {
      images[i] = imageReader.read(i);
    }
    inputStream.close();
  }
  public void paint(Graphics g) {
    if (images == null)
      return;
    g.drawImage(images[imageIndex], 0, 0, null);
    imageIndex = (imageIndex + 1) % images.length;
  }
  static public void main(String args[]) throws Exception {
    JFrame frame = new JFrame();
    Panel panel = new Main();
    frame.add(panel);
    frame.setSize(400, 400);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
  }
}