Java/2D Graphics GUI/ImageReader
Содержание
- 1 Add Image IO Read Progress Listener to ImageReader
- 2 Detect the file type of the input stream prior to reading the image
- 3 Determining the Format of an Image in a File
- 4 Get file format, image resolution, number of bits per pixel (JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM, PSD and SWF files)
- 5 Image format info
- 6 Image observer blocks until the image is completely loaded. AWT defers the loading of images until they are painted on a graphic.
- 7 List the image formats that can be read and written
- 8 Read an Image from a file
- 9 Read an Image from inputStream
- 10 Read an Image from URL
- 11 Show Image with ImageReader
Add Image IO Read Progress Listener to ImageReader
<source lang="java"> 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); }
}
</source>
Detect the file type of the input stream prior to reading the image
<source lang="java"> 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(); }
}
</source>
Determining the Format of an Image in a File
<source lang="java"> 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; }
}
</source>
Get file format, image resolution, number of bits per pixel (JPEG, GIF, BMP, PCX, PNG, IFF, RAS, PBM, PGM, PPM, PSD and SWF files)
<source lang="java"> //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:*
* 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 *
* You can also use this class as a command line program. * Call it with a number of image file names and URLs as parameters:*
* java ImageInfo *.jpg *.png *.gif http://somesite.tld/image.jpg *
* or call it without parameters and pipe data to it:*
* java ImageInfo < image.jpg *
* <p/> * Known limitations:*
-
*
- 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. *
- 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! ;-) *
* <p/> * Requirements:*
-
*
- Java 1.1 or higher *
* <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-c
. */ 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.image/jpeg
*/ 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 *true
as argument, returns the number of comments retrieved * from the input image stream / file. * Any number >= 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 thatsetDetermineImageNumber(true);
was called before * a successful call to {@link #check()}. * This value can currently be only different from1
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-1
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 *-1.0f
if width information is not available. * Assumes that {@link #check} has been called successfully. * * @return physical width in inches or-1.0f
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 isfalse
. * If enabled, comments will be added to an internal list. * * @param newValue iftrue
, 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 isfalse
. * 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 withtrue
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; } } }
}
</source>
Image format info
<source lang="java"> /*
- 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).*
* Use the class like this: *
* 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 *
* You can also use this class as a command line program. * Call it with a number of image file names and URLs as parameters:*
* java ImageInfo *.jpg *.png *.gif http://somesite.tld/image.jpg *
* or call it without parameters and pipe data to it:*
* java ImageInfo < image.jpg *
* <p> * Known limitations:*
-
*
- 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. *
- 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! ;-) *
* <p> * Requirements:*
-
*
- Java 1.1 or higher *
* <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.image/jpeg
*/ 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 *true
as argument, returns the number of comments retrieved * from the input image stream / file. * Any number >= 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 thatsetDetermineImageNumber(true);
was called before * a successful call to {@link #check()}. * This value can currently be only different from1
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-1
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 *-1.0f
if width information is not available. * Assumes that {@link #check} has been called successfully. * @return physical width in inches or-1.0f
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 isfalse
. * If enabled, comments will be added to an internal list. * @param newValue iftrue
, 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 isfalse
. * 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 withtrue
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; } } }
}
</source>
Image observer blocks until the image is completely loaded. AWT defers the loading of images until they are painted on a graphic.
<source lang="java"> /*
* 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 newImageObserver<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
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:WIDTH
,HEIGHT
, *PROPERTIES
,SOMEBITS
, *FRAMEBITS
,ALLBITS
, *ERROR
,ABORT
. * @param x the x coordinate. * @param y the y coordinate. * @param width the width. * @param height the height. * * @returnfalse
if the infoflags indicate that the * image is completely loaded;true
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); } } } /** * Returnstrue
if loading is complete, andfalse
* 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; }
}
</source>
List the image formats that can be read and written
<source lang="java"> 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)); }
}
</source>
Read an Image from a file
<source lang="java"> 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); }
}
</source>
Read an Image from inputStream
<source lang="java"> 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); }
}
</source>
Read an Image from URL
<source lang="java"> 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); }
}
</source>
Show Image with ImageReader
<source lang="java"> 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); }
}