📄 imageinfo.java
字号:
/* * ImageInfo.java * * Version 1.9 * * A Java class to determine image width, height and color depth for * a number of image file formats. * * Written by Marco Schmidt * * Contributed to the Public Domain. */package org.devlib.schmidt.imageinfo;import java.io.DataInput;import java.io.FileInputStream;import java.io.InputStream;import java.io.IOException;import java.net.URL;import java.util.Vector;/** * 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 and PSD 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 < image.jpg * </pre> * <p> * Known limitations: * <ul> * <li>When the determination of the number of images is turned off, GIF bits * per pixel are only read from the global header. * For some GIFs, local palettes change this to a typically larger * value. To be certain to get the correct color depth, call * setDetermineImageNumber(true) before calling check(). * The complete scan over the GIF file will take additional time.</li> * <li>Transparency information is not included in the bits per pixel count. * Actually, it was my decision not to include those bits, so it's a feature! ;-)</li> * </ul> * <p> * Requirements: * <ul> * <li>Java 1.1 or higher</li> * </ul> * <p> * The latest version can be found at <a href="http://schmidt.devlib.org/image-info/">http://schmidt.devlib.org/image-info/</a>. * <p> * Written by Marco Schmidt. * <p> * This class is contributed to the Public Domain. * Use it at your own risk. * <p> * <a name="history">History</a>: * <ul> * <li><strong>2001-08-24</strong> Initial version.</li> * <li><strong>2001-10-13</strong> Added support for the file formats BMP and PCX.</li> * <li><strong>2001-10-16</strong> Fixed bug in read(int[], int, int) that returned * <li><strong>2002-01-22</strong> Added support for file formats Amiga IFF and Sun Raster (RAS).</li> * <li><strong>2002-01-24</strong> Added support for file formats Portable Bitmap / Graymap / Pixmap (PBM, PGM, PPM) and Adobe Photoshop (PSD). * Added new method getMimeType() to return the MIME type associated with a particular file format.</li> * <li><strong>2002-03-15</strong> Added support to recognize number of images in file. Only works with GIF. * Use {@link #setDetermineImageNumber} with <code>true</code> as argument to identify animated GIFs * ({@link #getNumberOfImages()} will return a value larger than <code>1</code>).</li> * <li><strong>2002-04-10</strong> Fixed a bug in the feature 'determine number of images in animated GIF' introduced with version 1.1. * Thanks to Marcelo P. Lima for sending in the bug report. * Released as 1.1.1.</li> * <li><strong>2002-04-18</strong> Added {@link #setCollectComments(boolean)}. * That new method lets the user specify whether textual comments are to be * stored in an internal list when encountered in an input image file / stream. * Added two methods to return the physical width and height of the image in dpi: * {@link #getPhysicalWidthDpi()} and {@link #getPhysicalHeightDpi()}. * If the physical resolution could not be retrieved, these methods return <code>-1</code>. * </li> * <li><strong>2002-04-23</strong> Added support for the new properties physical resolution and * comments for some formats. Released as 1.2.</li> * <li><strong>2002-06-17</strong> Added support for SWF, sent in by Michael Aird. * Changed checkJpeg() so that other APP markers than APP0 will not lead to a failure anymore. * Released as 1.3.</li> * <li><strong>2003-07-28</strong> Bug fix - skip method now takes return values into consideration. * Less bytes than necessary may have been skipped, leading to flaws in the retrieved information in some cases. * Thanks to Bernard Bernstein for pointing that out. * Released as 1.4.</li> * <li><strong>2004-02-29</strong> Added support for recognizing progressive JPEG and * interlaced PNG and GIF. A new method {@link #isProgressive()} returns whether ImageInfo * has found that the storage type is progressive (or interlaced). * Thanks to Joe Germuska for suggesting the feature. * Bug fix: BMP physical resolution is now correctly determined. * Released as 1.5.</li> * <li><strong>2004-11-30</strong> Bug fix: recognizing progressive GIFs * (interlaced in GIF terminology) did not work (thanks to Franz Jeitler for * pointing this out). Now it should work, but only if the number of images is determined. * This is because information on interlacing is stored in a local image header. * In theory, different images could be stored interlaced and non-interlaced in one * file. However, I think that's unlikely. Right now, the last image in the GIF file * that is examined by ImageInfo is used for the "progressive" status.</li> * <li><strong>2005-01-02</strong> Some code clean up (unused methods and variables * commented out, missing javadoc comments, etc.). Thanks to George Sexton for a long list. * Removed usage of Boolean.toString because * it's a Java 1.4+ feature (thanks to Gregor Dupont). * Changed delimiter character in compact output from semicolon to tabulator * (for better integration with cut(1) and other Unix tools). * Added some points to the <a href="http://schmidt.devlib.org/image-info/index.html#knownissues">'Known * issues' section of the website</a>. * Released as 1.6.</li> * <li><strong>2005-07-26</strong> Removed code to identify Flash (SWF) files. * Has repeatedly led to problems and support requests, and I don't know the * format and don't have the time and interest to fix it myself. * I repeatedly included fixes by others which didn't work for some people. * I give up on SWF. Please do not contact me about it anymore. * Set package of ImageInfo class to org.devlib.schmidt.imageinfo (a package * was repeatedly requested by some users). * Released as 1.7.</li> * <li><strong>2006-02-23</strong> Removed Flash helper methods which weren't used elsewhere. * Updated skip method which tries "read" whenever "skip(Bytes)" returns a result of 0. * The old method didn't work with certain input stream types on truncated data streams. * Thanks to Martin Leidig for reporting this and sending in code. * Released as 1.8.</li> * </li> * <li><strong>2006-11-13</strong> Removed check that made ImageInfo report JPEG APPx * markers smaller than 14 bytes as files in unknown format. Such JPEGs seem to be * generated by Google's Picasa application. First reported with fix by * Karl von Randow. Released as 1.9.</li> * </ul> * @author Marco Schmidt */@SuppressWarnings("unchecked")public class ImageInfo { /** * Return value of {@link #getFormat()} for JPEG streams. * ImageInfo can extract physical resolution and comments * from JPEGs (only from APP0 headers). * Only one image can be stored in a file. * It is determined whether the JPEG stream is progressive * (see {@link #isProgressive()}). */ public static final int FORMAT_JPEG = 0; /** * Return value of {@link #getFormat()} for GIF streams. * ImageInfo can extract comments from GIFs and count the number * of images (GIFs with more than one image are animations). * 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;/* 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"}; /** * 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"}; 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 Vector comments; private boolean determineNumberOfImages; private int numberOfImages; private int physicalHeightDpi; private int physicalWidthDpi; private void addComment(String s) { if (comments == null) { comments = new Vector(); } comments.addElement(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 { 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; progressive = (flags & 0x40) != 0; /*int locWidth = getShortLittleEndian(a, 4); int locHeight = getShortLittleEndian(a, 6); System.out.println("LOCAL: " + locWidth + " x " + locHeight);*/ 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -