?? exif.java
字號:
// Exif.java// $Id: Exif.java,v 1.1 2003/07/23 12:08:01 ylafon Exp $// Copyright (c) 2003 Norman Walsh// Please first read the full copyright statement in file COPYRIGHTpackage org.w3c.tools.jpeg;import java.util.Hashtable;/** * An API for accessing EXIF encoded information in a JPEG file. * * <p>JPEG images are stored in a tagged format reminiscent of TIFF files. * Each component of the image is identified with a tag number and a size. * This allows applications that read JPEG files to skip over information * that they don't understand.</p> * * <p>Additional resources:</p> * <ul> * <li>Official standards, http://www.exif.org/specifications.html</li> * <li>TsuruZoh Tachibanaya's excellent description, * http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html * </li> * <li>Matthias Wandel's JHead, http://www.sentex.net/~mwandel/jhead * </ul> * * <p>This class treats a byte array as a JPEG image and parses the tags * searching for EXIF data. EXIF data is also tagged. Based on information * provided by the caller, this class builds a hash of EXIF data and * makes it available to the caller.</p> * * <p>Most simple EXIF values are tagged with both their identity and their * format. For example, ExposureTime (0x829A) is a rational number and * this class can extract that value. However, some fields are of "unknown" * format. If you decode one of these, you can add a special purpose decode * for that field by associating the name of the decoder class with the * field name. For example, my Nikon CoolPix 950 includes a MakerNote (0x927C) * field that's tagged "unknown" format. Using information from TsuruZoh's * page, I've built a decoder for that field and added it as an example.</p> * * <p>In addition to the tagged data, JPEG images have five intrinisic * properties: height, width, the compression algorithm used, the number of * bits used to store each pixel value, and the number of color components. * This class allows the caller to unify those intrinsic components with the * tagged data.</p> * * <p>In an effort to be flexible without requiring users to change the * source, a fair bit of setup is needed to use this class.</p> * * <p>The caller must:</p> * * <ol> * <li>Construct an Exif object, <code>exif = new Exif()</code>.</li> * <li>Associate names with each of the tags of interest, * <code>exif.addTag(<em>nnn</em>, "<em>name</em>")</code>.</li> * <li>Associate names with the intrinsic values: * <ul> * <li><code>exif.addHeight("<em>name</em>")</code> * <li><code>exif.addWidth("<em>name</em>")</code> * <li><code>exif.addCompression("<em>name</em>")</code> * <li><code>exif.addNumberOfColorComponents("<em>name</em>")</code> * <li><code>exif.addBitsPerPixel("<em>name</em>")</code> * </ul> * </li> * <li>Finally, the caller may associate a decoder with specific fields: * <code>exif.addDecoder("<em>name</em>", "<em>java.class.name</em>")</code>. * </li> * </ol> * * <p>Having setup the exif object, it can be passed to JpegHeaders to be * filled in when the JPEG file is parsed.</p> * * <p>The caller must also explicitly set the intrinsic values since they do * not come from the EXIF data.</p> * * <p>After parsing the JPEG, call <code>exif.getTags()</code> to get back the * has of name/value pairs.</p> * * @version $Revision: 1.1 $ * @author Norman Walsh * @see ExifData * @see TagDecoder * @see JpegHeaders */public class Exif { private static final int TAG_EXIF_OFFSET = 0x8769; private static final int TAG_INTEROP_OFFSET = 0xa005; private Hashtable tags = new Hashtable(); private Hashtable exif = new Hashtable(); private Hashtable decoder = new Hashtable(); private ExifData data = null; private boolean intelOrder = false; private String tagHeight = null; private String tagWidth = null; private String tagComp = null; private String tagBPP = null; private String tagNumCC = null; public void parseExif(byte[] exifData) { data = new ExifData(exifData); if (!data.isExifData()) { return; } int firstOffset = data.get32u(10); processExifDir(6+firstOffset, 6); } public void setHeight(int height) { if (tagHeight != null) { exif.put(tagHeight, ""+height); } } public void setWidth(int width) { if (tagWidth != null) { exif.put(tagWidth, ""+width); } } public void setCompression(String comp) { if (tagComp != null) { exif.put(tagComp, comp); } } public void setBPP(int bitsPP) { if (tagBPP != null) { exif.put(tagBPP, ""+bitsPP); } } public void setNumCC(int numCC) { if (tagNumCC != null) { exif.put(tagNumCC, ""+numCC); } } public void addHeight(String name) { tagHeight = name; } public void addWidth(String name) { tagWidth = name; } public void addCompression(String name) { tagComp = name; } public void addBitsPerPixel(String name) { tagBPP = name; } public void addNumberOfColorComponents(String name) { tagNumCC = name; } public void addTag(int tag, String tagName) { tags.put(new Integer(tag), tagName); } public void addDecoder(String name, String className) { decoder.put(name, className); } public Hashtable getTags() { return exif; } protected void processExifDir(int dirStart, int offsetBase) { int numEntries = data.get16u(dirStart); //System.err.println("EXIF: numEntries: " + numEntries); for (int de = 0; de < numEntries; de++) { int dirOffset = dirStart + 2 + (12 * de); int tag = data.get16u(dirOffset); int format = data.get16u(dirOffset+2); int components = data.get32u(dirOffset+4); //System.err.println("EXIF: entry: 0x" + Integer.toHexString(tag) // + " " + format // + " " + components); if (format < 0 || format > data.NUM_FORMATS) { System.err.println("Bad number of formats in EXIF dir: " + format); return; } int byteCount = components * ExifData.bytesPerFormat[format]; int valueOffset = dirOffset + 8; if (byteCount > 4) { int offsetVal = data.get32u(dirOffset+8); valueOffset = offsetBase + offsetVal; } //System.err.println("valueOffset: " + valueOffset + // " byteCount: " + byteCount); Integer iTag = new Integer(tag); if (tag == TAG_EXIF_OFFSET || tag == TAG_INTEROP_OFFSET) { int subdirOffset = data.get32u(valueOffset); //System.err.println("offset: " + subdirOffset+ // ":"+offsetBase+subdirOffset); processExifDir(offsetBase+subdirOffset, offsetBase); } else { String tagName = "BugBugBug"; boolean usedTag = false; if (tags.containsKey(iTag)) { tagName = (String) tags.get(iTag); usedTag = true; } else { tagName = ":unknown0x" + Integer.toHexString(iTag.intValue()); } if (decoder.containsKey(tagName)) { String className = (String) decoder.get(tagName); TagDecoder decoder = null; try { decoder = (TagDecoder) Class.forName(className).newInstance(); } catch (ClassNotFoundException cnfe) { System.err.println("Class not found: " + className); } catch (InstantiationException cnfe) { System.err.println("Failed to instantiate " + className); } catch (IllegalAccessException cnfe) { System.err.println("Illegal access instantiating " + className); } catch (ClassCastException cnfe) { System.err.println("Class " + className + " is not a TagDecoder"); } if (decoder != null) { decoder.decode(exif, data, format, valueOffset, byteCount); } } else { switch (format) { case ExifData.FMT_UNDEFINED: assignUndefined(tagName, valueOffset, byteCount); break; case ExifData.FMT_STRING: assignString(tagName, valueOffset, byteCount); break; case ExifData.FMT_SBYTE: assignSByte(tagName, valueOffset); break; case ExifData.FMT_BYTE: assignByte(tagName, valueOffset); break; case ExifData.FMT_USHORT: assignUShort(tagName, valueOffset); break; case ExifData.FMT_SSHORT: assignSShort(tagName, valueOffset); break; case ExifData.FMT_ULONG: assignULong(tagName, valueOffset); break; case ExifData.FMT_SLONG: assignSLong(tagName, valueOffset); break; case ExifData.FMT_URATIONAL: case ExifData.FMT_SRATIONAL: assignRational(tagName, valueOffset); break; default: //System.err.println("Unknown format " + format + // " for " + tagName); } } } } } protected void assignUndefined(String tagName, int offset, int length) { String result = data.getUndefined(offset, length); if (!"".equals(result)) { exif.put(tagName, result); } } protected void assignString(String tagName, int offset, int length) { String result = data.getString(offset, length); if (!"".equals(result)) { exif.put(tagName, result); } } protected void assignSByte(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_SBYTE, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignByte(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_BYTE, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignUShort(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_USHORT, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignSShort(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_SSHORT, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignULong(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_ULONG, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignSLong(String tagName, int offset) { int result = (int) data.convertAnyValue(ExifData.FMT_SLONG, offset); //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); } protected void assignRational(String tagName, int offset) { int num = data.get32s(offset); int den = data.get32s(offset+4); String result = ""; // This is a bit silly, I really ought to find a real GCD algorithm if (num % 10 == 0 && den % 10 == 0) { num = num / 10; den = den / 10; } if (num % 5 == 0 && den % 5 == 0) { num = num / 5; den = den / 5; } if (num % 3 == 0 && den % 3 == 0) { num = num / 3; den = den / 3; } if (num % 2 == 0 && den % 2 == 0) { num = num / 2; den = den / 2; } if (den == 0) { result = "0"; } else if (den == 1) { result = "" + num; // "" + int sure looks ugly... } else { result = "" + num + "/" + den; } //System.err.println("\t" + tagName + ": " + result); exif.put(tagName, ""+result); }}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -