Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1267 → Rev 1268

/contrib/metadata-extractor/trunk/ChangeLog.txt
0,0 → 1,182
v2.3.1 - 25 Feb 2006
-------------------------------
- Fixed copy-and-paste errors in ExifDescriptor.java. Thanks to Ferret Renaud.
 
v2.3.0 - 12 Jan 2006
-------------------------------
- New tags from Exif 2.2 specification (A401-A420).
- Fixed stack overflow exception in ExifReader for cyclic directory references.
Thanks to John Sidney-Woollett for reporting this bug (reported for Fuji FinePix A101 and Canon 20D).
- Fixed rounding error in the shutter speed description which was giving the wrong value most of the
time (for example, 1/32 instead of 1/50).
Thanks for Gli Blr and Mark Edwards for pointing out this error.
- Fix thread safety bug in ExifReader.
- Fixed OutOfMemoryError seen in certain Canon 20D images.
Thanks to Henry Yeung for providing an image to reproduce this error.
- Support for Windows XP Exif tags (Author, title, comments, etc).
- Added more documentation, and removed commented/unused code.
- Enhanced descriptor support for Exif tags.
- Extract comments in non-ASCII encodings.
- Improved camera model MakerNote support:
- New models:
- Epson (thanks to David Carlson for pointing me in the right direction with this)
- Kyocera / Contax (very limited)
- Minolta (it utilises the Olympus format)
- Panasonic
- Pentax / Asahi
- Improved support for models:
- Olympus
- Canon (tested with newer Canon models, including the 20D)
- Casio (for more modern models)
- Source distribution filesize reduced by using .metadata files, rather than entire sample JPEG files.
These .metadata files contain all non-image JPEG segments, making them suitable for unit tests whilst
being much smaller on disk.
 
v2.2.2 - 22 Nov 2003
-------------------------------
 
- Fixed a bug where version strings were assumed to be comprised of exactly four parts,
and cases were found where a different number existed
 
v2.2.1 - 24 Oct 2003
-------------------------------
 
- Fixed a bug where JpegDirectory had tag names for image width and height around
the wrong way. Thanks to Sander Smith for pointing this out
 
v2.2 - 18 Oct 2003
-------------------------------
 
- Added support for extraction of Jpeg image information (from the SOF0 segment)
Thanks to Darrell Silver for commencing the code for this extension
- Added support for reading Jpeg comments
- Additional Nikon camera makernote support for D1/D100 family models
Thanks to Daniel Waeber for providing sample images and to Fabrizio Giudici for
publishing his work in decoding this makernote data
- Added convenient writing of thumbnails to files from ExifDirectory
- Fixed a bug in date format strings, whereby times in the AM / PM were indistinguishable
Thanks to Bill Boland for being the first person to point this out (this was a popular one!)
- Fixed bug for multi-component tag values of certain types
Thanks to Derek Wegner for identifying the bug and providing a solution
- More unit tests (consequently, the source-code download is much larger)
- First version with an Ant build script
 
v2.1 - 12 Jan 2003
-------------------------------
 
- Extract methods no longer throw exceptions, with error information stored
in Metadata instances, using hasErrors() and getErrors()
- Metadata and dependant classes now serializable for network transmission,
and persistance in files & databases
- Support for extracting metadata from InputStreams, such as network connections
- Replaced code that depended upon JDK 1.4
 
v2.0 - 10 Dec 2002
-------------------------------
 
Enormous changes to the class and package structure in this release prohibit a
class-by-class breakdown of changes. The focus is no longer on Exif metadata
alone, but now on general metadata extraction from multiple media types.
 
Changes support:
- easier future extensibility
- Iptc metadata extraction
- multiple directories of tags
- descriptor class for interpreting values in a given directory
- multiple media and metadata types
- enhanced handling of exif makernote values
- many more unit tests
- numerous enhancements
- minor bug fixes
 
Simpler extensibility changes the focus from exif extraction alone and opens
the scope to general metadata extraction. Future development will introduce
new media and metadata support with little or no impact to existing classes.
 
v1.2 - 6 Nov 2002
-------------------------------
 
ExifExtractor.java
- Proper traversing of Exif file structure and complete refactor & tidy of
the codebase (a few unnoticed bugs removed)
- Reads makernote data for 6 families of camera (5 makes)
- Tags now stored in directories... use the IFD_* constants to refer to the
image file directory you require (Exif, Interop, GPS and Makernote*) --
this avoids collisions where two tags share the same code
- Correct extraction of multi-component values
- No longer decodes image to extract Exif data -- this is much faster
- Takes componentCount of unknown tags into account
- Now understands GPS tags (thanks to Colin Briton for his help with this)
- Returns null when no Exif data present, instead of throwing an exception
- Some other bug fixes, pointed out by users around the world. Thanks!
 
ExifLoader
- Removed (unnecessary)
 
ImageInfo.java
- Stored IFD directories in separate tag-spaces
- iterator() now returns an Iterator over a list of TagValue objects
- More get*Description() methods to detail GPS tags, among others
 
TagValue.java
- New class to encapsualte information about a particular tag
 
Rational.java
- Improved toSimpleString() to factor more complex rational numbers into
a simpler form
i.e.
10/15 -> 2/3
- toSimpleString() now accepts a boolean flag, 'allowDecimals' which will
display the rational number in decimal form if it fits within 5 digits
i.e.
3/4 -> 0.75 when allowDecimal == true
 
JpegSegmentReader
- New class to extract APP1 segment (and others) from a Jpeg file -- this
avoids decoding images just to get metadata
 
tests\*.java
- First collection of basic unit tests, to compile against JUnit
- Doesn't yet cover all classes
 
Website
- A collection of JPEGs from various digital camera models, collected on
the web and contributed by many users of ExifExtractor
- Updated documentation
 
 
v1.1.1
-------------------------------
 
Rational.java
- Added toSimpleString() method, which returns a simplified and hopefully
more readable version of the Rational
i.e.
2/10 -> 1/5
10/2 -> 5
 
ExifExtractor.java
- Removed unnecessary casting operations
- Added a few more comments
- Removed redundant and commented code (I'm using a CVS system now)
 
ExifLoader.java
- Added a much-needed close() call to a created input stream, allowing
continued use of the File object passed to ExifLoader.getImageInfo(File)
 
ImageInfo.java
- Make use of new Rational method toSimpleString() for more elegant output -
Use of DecimalFormatter to tidy output in selected get***Description() methods
 
v1.1.0 - 28 Aug 2002
-------------------------------
 
- Descriptive tag values, including units and text for enumerations
- Decoupling from JDK 1.4-specific libraries (tested with JDK 1.3)
- More complete list of tags, both as constants for direct lookup, and via the
static lookup method
 
v1.0
-------------------------------
 
- Initial release
/contrib/metadata-extractor/trunk/src/com/drew/imaging/PhotographicConversions.java
0,0 → 1,51
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.imaging;
 
/**
* Contains helper methods that perform photographic conversions.
*/
public class PhotographicConversions
{
public final static double ROOT_TWO = Math.sqrt(2);
 
private PhotographicConversions()
{}
 
/**
* Converts an aperture value to its corresponding F-stop number.
* @param aperture the aperture value to convert
* @return the F-stop number of the specified aperture
*/
public static double apertureToFStop(double aperture)
{
double fStop = Math.pow(ROOT_TWO, aperture);
return fStop;
 
// Puzzle?!
// jhead uses a different calculation as far as i can tell... this confuses me...
// fStop = (float)Math.exp(aperture * Math.log(2) * 0.5));
}
 
/**
* Converts a shutter speed to an exposure time.
* @param shutterSpeed the shutter speed to convert
* @return the exposure time of the specified shutter speed
*/
public static double shutterSpeedToExposureTime(double shutterSpeed)
{
return (float)(1 / Math.exp(shutterSpeed * Math.log(2)));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegMetadataReader.java
0,0 → 1,172
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 18:51:36 using IntelliJ IDEA.
*/
package com.drew.imaging.jpeg;
 
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.Tag;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.ExifReader;
import com.drew.metadata.iptc.IptcReader;
import com.drew.metadata.jpeg.JpegCommentReader;
import com.drew.metadata.jpeg.JpegReader;
import com.sun.image.codec.jpeg.JPEGDecodeParam;
 
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
 
/**
*
*/
public class JpegMetadataReader
{
// public static Metadata readMetadata(IIOMetadata metadata) throws JpegProcessingException {}
// public static Metadata readMetadata(ImageInputStream in) throws JpegProcessingException{}
// public static Metadata readMetadata(IIOImage image) throws JpegProcessingException{}
// public static Metadata readMetadata(ImageReader reader) throws JpegProcessingException{}
 
public static Metadata readMetadata(InputStream in) throws JpegProcessingException
{
JpegSegmentReader segmentReader = new JpegSegmentReader(in);
return extractMetadataFromJpegSegmentReader(segmentReader);
}
 
public static Metadata readMetadata(File file) throws JpegProcessingException
{
JpegSegmentReader segmentReader = new JpegSegmentReader(file);
return extractMetadataFromJpegSegmentReader(segmentReader);
}
 
public static Metadata extractMetadataFromJpegSegmentReader(JpegSegmentReader segmentReader)
{
final Metadata metadata = new Metadata();
try {
byte[] exifSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1);
new ExifReader(exifSegment).extract(metadata);
} catch (JpegProcessingException e) {
// in the interests of catching as much data as possible, continue
// TODO lodge error message within exif directory?
}
 
try {
byte[] iptcSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD);
new IptcReader(iptcSegment).extract(metadata);
} catch (JpegProcessingException e) {
// TODO lodge error message within iptc directory?
}
 
try {
byte[] jpegSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_SOF0);
new JpegReader(jpegSegment).extract(metadata);
} catch (JpegProcessingException e) {
// TODO lodge error message within jpeg directory?
}
 
try {
byte[] jpegCommentSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_COM);
new JpegCommentReader(jpegCommentSegment).extract(metadata);
} catch (JpegProcessingException e) {
// TODO lodge error message within jpegcomment directory?
}
 
return metadata;
}
 
public static Metadata readMetadata(JPEGDecodeParam decodeParam)
{
final Metadata metadata = new Metadata();
 
/* We should only really be seeing Exif in _data[0]... the 2D array exists
* because markers can theoretically appear multiple times in the file.
*/
// TODO test this method
byte[][] exifSegment = decodeParam.getMarkerData(JPEGDecodeParam.APP1_MARKER);
if (exifSegment != null && exifSegment[0].length>0) {
new ExifReader(exifSegment[0]).extract(metadata);
}
 
// similarly, use only the first IPTC segment
byte[][] iptcSegment = decodeParam.getMarkerData(JPEGDecodeParam.APPD_MARKER);
if (iptcSegment != null && iptcSegment[0].length>0) {
new IptcReader(iptcSegment[0]).extract(metadata);
}
 
// NOTE: Unable to utilise JpegReader for the SOF0 frame here, as the decodeParam doesn't contain the byte[]
 
// similarly, use only the first Jpeg Comment segment
byte[][] jpegCommentSegment = decodeParam.getMarkerData(JPEGDecodeParam.COMMENT_MARKER);
if (jpegCommentSegment != null && jpegCommentSegment[0].length>0) {
new JpegCommentReader(jpegCommentSegment[0]).extract(metadata);
}
 
return metadata;
}
 
private JpegMetadataReader()
{
}
 
public static void main(String[] args) throws MetadataException, IOException
{
Metadata metadata = null;
try {
metadata = JpegMetadataReader.readMetadata(new File(args[0]));
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
 
// iterate over the exif data and print to System.out
Iterator directories = metadata.getDirectoryIterator();
while (directories.hasNext()) {
Directory directory = (Directory)directories.next();
Iterator tags = directory.getTagIterator();
while (tags.hasNext()) {
Tag tag = (Tag)tags.next();
try {
System.out.println("[" + directory.getName() + "] " + tag.getTagName() + " = " + tag.getDescription());
} catch (MetadataException e) {
System.err.println(e.getMessage());
System.err.println(tag.getDirectoryName() + " " + tag.getTagName() + " (error)");
}
}
if (directory.hasErrors()) {
Iterator errors = directory.getErrors();
while (errors.hasNext()) {
System.out.println("ERROR: " + errors.next());
}
}
}
 
if (args.length>1 && args[1].trim().equals("/thumb"))
{
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
if (directory.containsThumbnail())
{
System.out.println("Writing thumbnail...");
directory.writeThumbnail(args[0].trim() + ".thumb.jpg");
}
else
{
System.out.println("No thumbnail data exists in this image");
}
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegSegmentReader.java
0,0 → 1,283
/*
* JpegSegmentReader.java
*
* This class written by Drew Noakes, in accordance with the Jpeg specification.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 04-Nov-2002 00:54:00 using IntelliJ IDEA
*/
package com.drew.imaging.jpeg;
 
import java.io.*;
 
/**
* Performs read functions of Jpeg files, returning specific file segments.
* TODO add a findAvailableSegments() method
* TODO add more segment identifiers
* TODO add a getSegmentDescription() method, returning for example 'App1 application data segment, commonly containing Exif data'
* @author Drew Noakes http://drewnoakes.com
*/
public class JpegSegmentReader
{
// Jpeg data can be sourced from either a file, byte[] or InputStream
 
/** Jpeg file */
private final File _file;
/** Jpeg data as byte array */
private final byte[] _data;
/** Jpeg data as an InputStream */
private final InputStream _stream;
 
private JpegSegmentData _segmentData;
 
/**
* Private, because this segment crashes my algorithm, and searching for
* it doesn't work (yet).
*/
private static final byte SEGMENT_SOS = (byte)0xDA;
 
/**
* Private, because one wouldn't search for it.
*/
private static final byte MARKER_EOI = (byte)0xD9;
 
/** APP0 Jpeg segment identifier -- Jfif data. */
public static final byte SEGMENT_APP0 = (byte)0xE0;
/** APP1 Jpeg segment identifier -- where Exif data is kept. */
public static final byte SEGMENT_APP1 = (byte)0xE1;
/** APP2 Jpeg segment identifier. */
public static final byte SEGMENT_APP2 = (byte)0xE2;
/** APP3 Jpeg segment identifier. */
public static final byte SEGMENT_APP3 = (byte)0xE3;
/** APP4 Jpeg segment identifier. */
public static final byte SEGMENT_APP4 = (byte)0xE4;
/** APP5 Jpeg segment identifier. */
public static final byte SEGMENT_APP5 = (byte)0xE5;
/** APP6 Jpeg segment identifier. */
public static final byte SEGMENT_APP6 = (byte)0xE6;
/** APP7 Jpeg segment identifier. */
public static final byte SEGMENT_APP7 = (byte)0xE7;
/** APP8 Jpeg segment identifier. */
public static final byte SEGMENT_APP8 = (byte)0xE8;
/** APP9 Jpeg segment identifier. */
public static final byte SEGMENT_APP9 = (byte)0xE9;
/** APPA Jpeg segment identifier -- can hold Unicode comments. */
public static final byte SEGMENT_APPA = (byte)0xEA;
/** APPB Jpeg segment identifier. */
public static final byte SEGMENT_APPB = (byte)0xEB;
/** APPC Jpeg segment identifier. */
public static final byte SEGMENT_APPC = (byte)0xEC;
/** APPD Jpeg segment identifier -- IPTC data in here. */
public static final byte SEGMENT_APPD = (byte)0xED;
/** APPE Jpeg segment identifier. */
public static final byte SEGMENT_APPE = (byte)0xEE;
/** APPF Jpeg segment identifier. */
public static final byte SEGMENT_APPF = (byte)0xEF;
/** Start Of Image segment identifier. */
public static final byte SEGMENT_SOI = (byte)0xD8;
/** Define Quantization Table segment identifier. */
public static final byte SEGMENT_DQT = (byte)0xDB;
/** Define Huffman Table segment identifier. */
public static final byte SEGMENT_DHT = (byte)0xC4;
/** Start-of-Frame Zero segment identifier. */
public static final byte SEGMENT_SOF0 = (byte)0xC0;
/** Jpeg comment segment identifier. */
public static final byte SEGMENT_COM = (byte)0xFE;
 
/**
* Creates a JpegSegmentReader for a specific file.
* @param file the Jpeg file to read segments from
*/
public JpegSegmentReader(File file) throws JpegProcessingException
{
_file = file;
_data = null;
_stream = null;
 
readSegments();
}
 
/**
* Creates a JpegSegmentReader for a byte array.
* @param fileContents the byte array containing Jpeg data
*/
public JpegSegmentReader(byte[] fileContents) throws JpegProcessingException
{
_file = null;
_data = fileContents;
_stream = null;
 
readSegments();
}
 
public JpegSegmentReader(InputStream in) throws JpegProcessingException
{
_stream = in;
_file = null;
_data = null;
readSegments();
}
 
public JpegSegmentReader(JpegSegmentData segmentData)
{
_file = null;
_data = null;
_stream = null;
 
_segmentData = segmentData;
}
 
/**
* Reads the first instance of a given Jpeg segment, returning the contents as
* a byte array.
* @param segmentMarker the byte identifier for the desired segment
* @return the byte array if found, else null
* @throws JpegProcessingException for any problems processing the Jpeg data,
* including inner IOExceptions
*/
public byte[] readSegment(byte segmentMarker) throws JpegProcessingException
{
return readSegment(segmentMarker, 0);
}
 
/**
* Reads the first instance of a given Jpeg segment, returning the contents as
* a byte array.
* @param segmentMarker the byte identifier for the desired segment
* @param occurrence the occurrence of the specified segment within the jpeg file
* @return the byte array if found, else null
*/
public byte[] readSegment(byte segmentMarker, int occurrence)
{
return _segmentData.getSegment(segmentMarker, occurrence);
}
 
public final int getSegmentCount(byte segmentMarker)
{
return _segmentData.getSegmentCount(segmentMarker);
}
 
public final JpegSegmentData getSegmentData()
{
return _segmentData;
}
 
private void readSegments() throws JpegProcessingException
{
_segmentData = new JpegSegmentData();
 
BufferedInputStream inStream = getJpegInputStream();
try {
int offset = 0;
// first two bytes should be jpeg magic number
if (!isValidJpegHeaderBytes(inStream)) {
throw new JpegProcessingException("not a jpeg file");
}
offset += 2;
do {
// next byte is 0xFF
byte segmentIdentifier = (byte)(inStream.read() & 0xFF);
if ((segmentIdentifier & 0xFF) != 0xFF) {
throw new JpegProcessingException("expected jpeg segment start identifier 0xFF at offset " + offset + ", not 0x" + Integer.toHexString(segmentIdentifier & 0xFF));
}
offset++;
// next byte is <segment-marker>
byte thisSegmentMarker = (byte)(inStream.read() & 0xFF);
offset++;
// next 2-bytes are <segment-size>: [high-byte] [low-byte]
byte[] segmentLengthBytes = new byte[2];
inStream.read(segmentLengthBytes, 0, 2);
offset += 2;
int segmentLength = ((segmentLengthBytes[0] << 8) & 0xFF00) | (segmentLengthBytes[1] & 0xFF);
// segment length includes size bytes, so subtract two
segmentLength -= 2;
if (segmentLength > inStream.available())
throw new JpegProcessingException("segment size would extend beyond file stream length");
else if (segmentLength < 0)
throw new JpegProcessingException("segment size would be less than zero");
byte[] segmentBytes = new byte[segmentLength];
inStream.read(segmentBytes, 0, segmentLength);
offset += segmentLength;
if ((thisSegmentMarker & 0xFF) == (SEGMENT_SOS & 0xFF)) {
// The 'Start-Of-Scan' segment's length doesn't include the image data, instead would
// have to search for the two bytes: 0xFF 0xD9 (EOI).
// It comes last so simply return at this point
return;
} else if ((thisSegmentMarker & 0xFF) == (MARKER_EOI & 0xFF)) {
// the 'End-Of-Image' segment -- this should never be found in this fashion
return;
} else {
_segmentData.addSegment(thisSegmentMarker, segmentBytes);
}
// didn't find the one we're looking for, loop through to the next segment
} while (true);
} catch (IOException ioe) {
//throw new JpegProcessingException("IOException processing Jpeg file", ioe);
throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe);
} finally {
try {
if (inStream != null) {
inStream.close();
}
} catch (IOException ioe) {
//throw new JpegProcessingException("IOException processing Jpeg file", ioe);
throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe);
}
}
}
 
/**
* Private helper method to create a BufferedInputStream of Jpeg data from whichever
* data source was specified upon construction of this instance.
* @return a a BufferedInputStream of Jpeg data
* @throws JpegProcessingException for any problems obtaining the stream
*/
private BufferedInputStream getJpegInputStream() throws JpegProcessingException
{
if (_stream!=null) {
if (_stream instanceof BufferedInputStream) {
return (BufferedInputStream) _stream;
} else {
return new BufferedInputStream(_stream);
}
}
InputStream inputStream;
if (_data == null) {
try {
inputStream = new FileInputStream(_file);
} catch (FileNotFoundException e) {
throw new JpegProcessingException("Jpeg file does not exist", e);
}
} else {
inputStream = new ByteArrayInputStream(_data);
}
return new BufferedInputStream(inputStream);
}
 
/**
* Helper method that validates the Jpeg file's magic number.
* @param fileStream the InputStream to read bytes from, which must be positioned
* at its start (i.e. no bytes read yet)
* @return true if the magic number is Jpeg (0xFFD8)
* @throws IOException for any problem in reading the file
*/
private boolean isValidJpegHeaderBytes(InputStream fileStream) throws IOException
{
byte[] header = new byte[2];
fileStream.read(header, 0, 2);
return (header[0] & 0xFF) == 0xFF && (header[1] & 0xFF) == 0xD8;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegSegmentDataTest.java
0,0 → 1,158
/*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.imaging.jpeg.test;
 
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.lang.test.TestHelper;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class JpegSegmentDataTest extends TestCase
{
public JpegSegmentDataTest(String name)
{
super(name);
}
 
public void testAddAndGetSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker = (byte)12;
byte[] segmentBytes = new byte[] { 1,2,3 };
 
segmentData.addSegment(segmentMarker, segmentBytes);
assertEquals(1, segmentData.getSegmentCount(segmentMarker));
TestHelper.assertEqualArrays(segmentBytes, segmentData.getSegment(segmentMarker));
}
 
public void testContainsSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker = (byte)12;
byte[] segmentBytes = new byte[] { 1,2,3 };
 
assertTrue(!segmentData.containsSegment(segmentMarker));
 
segmentData.addSegment(segmentMarker, segmentBytes);
 
assertTrue(segmentData.containsSegment(segmentMarker));
}
 
public void testAddingMultipleSegments() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker1 = (byte)12;
byte segmentMarker2 = (byte)21;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
 
segmentData.addSegment(segmentMarker1, segmentBytes1);
segmentData.addSegment(segmentMarker2, segmentBytes2);
assertEquals(1, segmentData.getSegmentCount(segmentMarker1));
assertEquals(1, segmentData.getSegmentCount(segmentMarker2));
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker1));
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker2));
}
 
public void testSegmentWithMultipleOccurrences() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker = (byte)12;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
 
segmentData.addSegment(segmentMarker, segmentBytes1);
segmentData.addSegment(segmentMarker, segmentBytes2);
assertEquals(2, segmentData.getSegmentCount(segmentMarker));
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker));
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker, 1));
}
 
public void testRemoveSegmentOccurrence() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker = (byte)12;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
 
segmentData.addSegment(segmentMarker, segmentBytes1);
segmentData.addSegment(segmentMarker, segmentBytes2);
 
assertEquals(2, segmentData.getSegmentCount(segmentMarker));
 
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
 
segmentData.removeSegmentOccurrence(segmentMarker, 0);
 
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker, 0));
}
 
public void testRemoveSegment() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
 
byte segmentMarker = (byte)12;
byte[] segmentBytes1 = new byte[] { 1,2,3 };
byte[] segmentBytes2 = new byte[] { 3,2,1 };
 
segmentData.addSegment(segmentMarker, segmentBytes1);
segmentData.addSegment(segmentMarker, segmentBytes2);
 
assertEquals(2, segmentData.getSegmentCount(segmentMarker));
assertTrue(segmentData.containsSegment(segmentMarker));
 
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0));
 
segmentData.removeSegment(segmentMarker);
 
assertTrue(!segmentData.containsSegment(segmentMarker));
assertEquals(0, segmentData.getSegmentCount(segmentMarker));
}
 
public void testToAndFromFile() throws Exception
{
JpegSegmentData segmentData = new JpegSegmentData();
byte segmentMarker = (byte)12;
byte[] segmentBytes = new byte[] { 1,2,3 };
 
segmentData.addSegment(segmentMarker, segmentBytes);
assertTrue(segmentData.containsSegment(segmentMarker));
 
File tempFile = File.createTempFile("JpegSegmentDataTest", "tmp");
JpegSegmentData.ToFile(tempFile, segmentData);
assertTrue(tempFile.exists());
assertTrue(tempFile.length() > 0);
segmentData = JpegSegmentData.FromFile(tempFile);
 
tempFile.delete();
assertTrue(!tempFile.exists());
 
assertNotNull(segmentData);
assertTrue(segmentData.containsSegment(segmentMarker));
TestHelper.assertEqualArrays(segmentBytes, segmentData.getSegment(segmentMarker));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegMetadataReaderTest.java
0,0 → 1,60
/*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 18:52:05 using IntelliJ IDEA.
*/
package com.drew.imaging.jpeg.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import junit.framework.TestCase;
 
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
 
/**
*
*/
public class JpegMetadataReaderTest extends TestCase
{
public JpegMetadataReaderTest(String s)
{
super(s);
}
 
public void testExtractMetadata() throws Exception
{
File withExif = new File("src/com/drew/metadata/exif/test/withExif.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(withExif);
assertTrue(metadata.containsDirectory(ExifDirectory.class));
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals("80", directory.getString(ExifDirectory.TAG_ISO_EQUIVALENT));
}
 
public void testExtractMetadataUsingInputStream() throws Exception
{
File withExif = new File("src/com/drew/metadata/exif/test/withExif.jpg");
InputStream in = new BufferedInputStream(new FileInputStream((withExif)));
Metadata metadata = JpegMetadataReader.readMetadata(in);
assertTrue(metadata.containsDirectory(ExifDirectory.class));
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals("80", directory.getString(ExifDirectory.TAG_ISO_EQUIVALENT));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/withExifAndIptc.metadata
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegSegmentReaderTest.java
0,0 → 1,157
/*
* JpegSegmentReaderTest.java
*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 04-Nov-2002 00:54:00 using IntelliJ IDEA
*/
package com.drew.imaging.jpeg.test;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.exif.ExifReader;
import com.drew.metadata.iptc.IptcReader;
import junit.framework.TestCase;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
 
/**
* Contains JUnit tests for the JpegSegmentReader class.
*/
public class JpegSegmentReaderTest extends TestCase
{
public JpegSegmentReaderTest(String s)
{
super(s);
}
 
public void testIsJpegWithJpegFile() throws Exception
{
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg");
try {
new JpegSegmentReader(jpeg);
} catch (JpegProcessingException e) {
fail("Error creating JpegSegmentReader");
}
}
 
public void testIsJpegWithNonJpegFile() throws Exception
{
File nonJpeg = new File("src/com/drew/metadata/test/AllTests.java");
try {
new JpegSegmentReader(nonJpeg);
fail("shouldn't be able to construct JpegSegmentReader with non-jpeg file");
} catch (JpegProcessingException e) {
// expect exception
}
}
 
public void testReadApp1Segment() throws Exception
{
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg");
JpegSegmentReader segmentReader = new JpegSegmentReader(jpeg);
byte[] exifData = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1);
assertTrue("exif data too short", exifData.length > 4);
assertEquals("Exif", new String(exifData, 0, 4));
}
 
public void testReadDQTSegment() throws Exception
{
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg");
JpegSegmentReader segmentReader = new JpegSegmentReader(jpeg);
byte[] quantizationTableData = segmentReader.readSegment(JpegSegmentReader.SEGMENT_DQT);
assertTrue("shouldn't have zero length quantizationTableData", quantizationTableData.length > 0);
assertTrue("quantizationTableData shouldn't start with 'Exif'", !"Exif".equals(new String(quantizationTableData, 0, 4)));
}
 
public void testReadJpegByteArray() throws Exception
{
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg");
byte[] fileContents = new byte[(int)jpeg.length()];
new FileInputStream(jpeg).read(fileContents);
new JpegSegmentReader(fileContents).readSegment(JpegSegmentReader.SEGMENT_APP1);
}
 
public void testCreateWithInputStream() throws Exception
{
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg");
InputStream in = new FileInputStream(jpeg);
JpegSegmentReader reader = null;
try {
reader = new JpegSegmentReader(in);
} catch (JpegProcessingException e) {
fail("Error constructing JpegSegmentReader using InputStream");
}
// this will never happen, as fail() is guaranteed to throw an AssertionException
if (reader==null)
return;
byte[] exifData = reader.readSegment(JpegSegmentReader.SEGMENT_APP1);
assertEquals("Exif", new String(exifData, 0, 4));
}
 
public void testReadSecondSegmentInstanace() throws Exception
{
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg");
JpegSegmentReader reader = new JpegSegmentReader(jpeg);
byte[] exifData0 = reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 0);
byte[] exifData1 = reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 1);
assertEquals("Exif", new String(exifData0, 0, 4));
assertEquals("http", new String(exifData1, 0, 4));
}
 
public void testReadNonExistantSegmentInstance() throws Exception
{
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg");
JpegSegmentReader reader = new JpegSegmentReader(jpeg);
assertNull("third exif segment shouldn't exist", reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 3));
}
 
public void testGetSegmentCount() throws Exception
{
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg");
JpegSegmentReader reader = new JpegSegmentReader(jpeg);
assertEquals(2, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP1));
assertEquals(1, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP2));
assertEquals(0, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP3));
}
 
public void testCreateWithFileAndReadMultipleSegments() throws Exception
{
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg");
JpegSegmentReader reader = new JpegSegmentReader(jpeg);
validateMultipleSegmentRead(reader);
}
 
public void testCreateWithInputStreamAndReadMultipleSegments() throws Exception
{
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg");
InputStream in = new FileInputStream(jpeg);
JpegSegmentReader reader = new JpegSegmentReader(in);
validateMultipleSegmentRead(reader);
}
 
private void validateMultipleSegmentRead(JpegSegmentReader reader) throws JpegProcessingException
{
byte[] iptcData = reader.readSegment(JpegSegmentReader.SEGMENT_APPD);
byte[] exifData = reader.readSegment(JpegSegmentReader.SEGMENT_APP1);
assertTrue("exif data too short", exifData.length > 4);
new ExifReader(exifData).extract();
new IptcReader(iptcData).extract();
assertEquals("Exif", new String(exifData, 0, 4));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegProcessingException.java
0,0 → 1,44
/*
* JpegProcessingException.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 04-Nov-2002 19:31:29 using IntelliJ IDEA.
*/
package com.drew.imaging.jpeg;
 
import com.drew.lang.CompoundException;
 
/**
* An exception class thrown upon unexpected and fatal conditions while processing
* a Jpeg file.
* @author Drew Noakes http://drewnoakes.com
*/
public class JpegProcessingException extends CompoundException
{
public JpegProcessingException(String message)
{
super(message);
}
 
public JpegProcessingException(String message, Throwable cause)
{
super(message, cause);
}
 
public JpegProcessingException(Throwable cause)
{
super(cause);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegSegmentData.java
0,0 → 1,132
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.imaging.jpeg;
 
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
 
/**
* Holds a collection of Jpeg data segments. This need not necessarily be all segments
* within the Jpeg. For example, it may be convenient to port about only the non-image
* segments when analysing (or serializing) metadata.
*/
public class JpegSegmentData implements Serializable
{
static final long serialVersionUID = 7110175216435025451L;
/** A map of byte[], keyed by the segment marker */
private final HashMap _segmentDataMap;
 
public JpegSegmentData()
{
_segmentDataMap = new HashMap(10);
}
 
public void addSegment(byte segmentMarker, byte[] segmentBytes)
{
List segmentList = getOrCreateSegmentList(segmentMarker);
segmentList.add(segmentBytes);
}
 
public byte[] getSegment(byte segmentMarker)
{
return getSegment(segmentMarker, 0);
}
 
public byte[] getSegment(byte segmentMarker, int occurrence)
{
final List segmentList = getSegmentList(segmentMarker);
 
if (segmentList==null || segmentList.size()<=occurrence)
return null;
else
return (byte[]) segmentList.get(occurrence);
}
 
public int getSegmentCount(byte segmentMarker)
{
final List segmentList = getSegmentList(segmentMarker);
if (segmentList==null)
return 0;
else
return segmentList.size();
}
 
public void removeSegmentOccurrence(byte segmentMarker, int occurrence)
{
final List segmentList = (List)_segmentDataMap.get(new Byte(segmentMarker));
segmentList.remove(occurrence);
}
 
public void removeSegment(byte segmentMarker)
{
_segmentDataMap.remove(new Byte(segmentMarker));
}
 
private List getSegmentList(byte segmentMarker)
{
return (List)_segmentDataMap.get(new Byte(segmentMarker));
}
 
private List getOrCreateSegmentList(byte segmentMarker)
{
List segmentList;
Byte key = new Byte(segmentMarker);
if (_segmentDataMap.containsKey(key)) {
segmentList = (List)_segmentDataMap.get(key);
} else {
segmentList = new ArrayList();
_segmentDataMap.put(key, segmentList);
}
return segmentList;
}
 
public boolean containsSegment(byte segmentMarker)
{
return _segmentDataMap.containsKey(new Byte(segmentMarker));
}
 
public static void ToFile(File file, JpegSegmentData segmentData) throws IOException
{
ObjectOutputStream outputStream = null;
try
{
outputStream = new ObjectOutputStream(new FileOutputStream(file));
outputStream.writeObject(segmentData);
}
finally
{
if (outputStream!=null)
outputStream.close();
}
}
 
public static JpegSegmentData FromFile(File file) throws IOException, ClassNotFoundException
{
ObjectInputStream inputStream = null;
try
{
inputStream = new ObjectInputStream(new FileInputStream(file));
return (JpegSegmentData)inputStream.readObject();
}
finally
{
if (inputStream!=null)
inputStream.close();
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/TagDescriptor.java
0,0 → 1,46
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata;
 
import java.io.Serializable;
 
/**
* Abstract base class for all tag descriptor classes. Implementations are responsible for
* providing the human-readable string represenation of tag values stored in a directory.
* The directory is provided to the tag descriptor via its constructor.
*/
public abstract class TagDescriptor implements Serializable
{
protected final Directory _directory;
 
public TagDescriptor(Directory directory)
{
_directory = directory;
}
 
/**
* Returns a descriptive value of the the specified tag for this image.
* Where possible, known values will be substituted here in place of the raw
* tokens actually kept in the Exif segment. If no substitution is
* available, the value provided by getString(int) will be returned.
* <p>
* This and getString(int) are the only 'get' methods that won't throw an
* exception.
* @param tagType the tag to find a description for
* @return a description of the image's value for the specified tag, or
* <code>null</code> if the tag hasn't been defined.
*/
public abstract String getDescription(int tagType) throws MetadataException;
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/Tag.java
0,0 → 1,101
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Nov-2002 18:29:12 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
import java.io.Serializable;
 
/**
*
*/
public class Tag implements Serializable
{
private final int _tagType;
private final Directory _directory;
 
public Tag(int tagType, Directory directory)
{
_tagType = tagType;
_directory = directory;
}
 
/**
* Gets the tag type as an int
* @return the tag type as an int
*/
public int getTagType()
{
return _tagType;
}
 
/**
* Gets the tag type in hex notation as a String with padded leading
* zeroes if necessary (i.e. <code>0x100E</code>).
* @return the tag type as a string in hexadecimal notation
*/
public String getTagTypeHex()
{
String hex = Integer.toHexString(_tagType);
while (hex.length() < 4) hex = "0" + hex;
return "0x" + hex;
}
 
/**
* Get a description of the tag's value, considering enumerated values
* and units.
* @return a description of the tag's value
*/
public String getDescription() throws MetadataException
{
return _directory.getDescription(_tagType);
}
 
/**
* Get the name of the tag, such as <code>Aperture</code>, or
* <code>InteropVersion</code>.
* @return the tag's name
*/
public String getTagName()
{
return _directory.getTagName(_tagType);
}
 
/**
* Get the name of the directory in which the tag exists, such as
* <code>Exif</code>, <code>GPS</code> or <code>Interoperability</code>.
* @return name of the directory in which this tag exists
*/
public String getDirectoryName()
{
return _directory.getName();
}
 
/**
* A basic representation of the tag's type and value in format:
* <code>FNumber - F2.8</code>.
* @return the tag's type and value
*/
public String toString()
{
String description;
try {
description = getDescription();
} catch (MetadataException e) {
description = _directory.getString(getTagType()) + " (unable to formulate description)";
}
return "[" + _directory.getName() + "] " + getTagName() + " - " + description;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/FujifilmMakernoteDescriptor.java
0,0 → 1,311
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Fujifilm's digicam added the MakerNote tag from the Year2000's model (e.g.Finepix1400,
* Finepix4700). It uses IFD format and start from ASCII character 'FUJIFILM', and next 4
* bytes(value 0x000c) points the offset to first IFD entry. Example of actual data
* structure is shown below.
*
* :0000: 46 55 4A 49 46 49 4C 4D-0C 00 00 00 0F 00 00 00 :0000: FUJIFILM........
* :0010: 07 00 04 00 00 00 30 31-33 30 00 10 02 00 08 00 :0010: ......0130......
*
* There are two big differences to the other manufacturers.
* - Fujifilm's Exif data uses Motorola align, but MakerNote ignores it and uses Intel
* align.
* - The other manufacturer's MakerNote counts the "offset to data" from the first byte
* of TIFF header (same as the other IFD), but Fujifilm counts it from the first byte
* of MakerNote itself.
*/
public class FujifilmMakernoteDescriptor extends TagDescriptor
{
public FujifilmMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS:
return getSharpnessDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE:
return getWhiteBalanceDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR:
return getColorDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE:
return getToneDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE:
return getFlashModeDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH:
return getFlashStrengthDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO:
return getMacroDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE:
return getFocusModeDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO:
return getSlowSyncDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE:
return getPictureModeDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING:
return getContinuousTakingOrAutoBrackettingDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING:
return getBlurWarningDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING:
return getFocusWarningDescription();
case FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING:
return getAutoExposureWarningDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getAutoExposureWarningDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING);
switch (value) {
case 0:
return "AE good";
case 1:
return "Over exposed (>1/1000s @ F11)";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusWarningDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING);
switch (value) {
case 0:
return "Auto focus good";
case 1:
return "Out of focus";
default:
return "Unknown (" + value + ")";
}
}
 
public String getBlurWarningDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING);
switch (value) {
case 0:
return "No blur warning";
case 1:
return "Blur warning";
default:
return "Unknown (" + value + ")";
}
}
 
public String getContinuousTakingOrAutoBrackettingDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING);
switch (value) {
case 0:
return "Off";
case 1:
return "On";
default:
return "Unknown (" + value + ")";
}
}
 
public String getPictureModeDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE);
switch (value) {
case 0:
return "Auto";
case 1:
return "Portrait scene";
case 2:
return "Landscape scene";
case 4:
return "Sports scene";
case 5:
return "Night scene";
case 6:
return "Program AE";
case 256:
return "Aperture priority AE";
case 512:
return "Shutter priority AE";
case 768:
return "Manual exposure";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSlowSyncDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO);
switch (value) {
case 0:
return "Off";
case 1:
return "On";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusModeDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE);
switch (value) {
case 0:
return "Auto focus";
case 1:
return "Manual focus";
default:
return "Unknown (" + value + ")";
}
}
 
public String getMacroDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO);
switch (value) {
case 0:
return "Off";
case 1:
return "On";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashStrengthDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH)) return null;
Rational value = _directory.getRational(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH);
return value.toSimpleString(false) + " EV (Apex)";
}
 
public String getFlashModeDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE);
switch (value) {
case 0:
return "Auto";
case 1:
return "On";
case 2:
return "Off";
case 3:
return "Red-eye reduction";
default:
return "Unknown (" + value + ")";
}
}
 
public String getToneDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE);
switch (value) {
case 0:
return "Normal (STD)";
case 256:
return "High (HARD)";
case 512:
return "Low (ORG)";
default:
return "Unknown (" + value + ")";
}
}
 
public String getColorDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR);
switch (value) {
case 0:
return "Normal (STD)";
case 256:
return "High";
case 512:
return "Low (ORG)";
default:
return "Unknown (" + value + ")";
}
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE);
switch (value) {
case 0:
return "Auto";
case 256:
return "Daylight";
case 512:
return "Cloudy";
case 768:
return "DaylightColor-fluorescence";
case 769:
return "DaywhiteColor-fluorescence";
case 770:
return "White-fluorescence";
case 1024:
return "Incandenscense";
case 3840:
return "Custom white balance";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS)) return null;
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS);
switch (value) {
case 1:
return "Softest";
case 2:
return "Soft";
case 3:
return "Normal";
case 4:
return "Hard";
case 5:
return "Hardest";
default:
return "Unknown (" + value + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType2MakernoteDirectory.java
0,0 → 1,218
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment.
* Makernote data begins after a 6-byte header: "QVC\x00\x00\x00"
*/
public class CasioType2MakernoteDirectory extends Directory
{
/**
* 2 values - x,y dimensions in pixels.
*/
public static final int TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS = 0x0002;
/**
* Size in bytes
*/
public static final int TAG_CASIO_TYPE2_THUMBNAIL_SIZE = 0x0003;
/**
* Offset of Preview Thumbnail
*/
public static final int TAG_CASIO_TYPE2_THUMBNAIL_OFFSET = 0x0004;
/**
* 1 = Fine
* 2 = Super Fine
*/
public static final int TAG_CASIO_TYPE2_QUALITY_MODE = 0x0008;
/**
* 0 = 640 x 480 pixels
* 4 = 1600 x 1200 pixels
* 5 = 2048 x 1536 pixels
* 20 = 2288 x 1712 pixels
* 21 = 2592 x 1944 pixels
* 22 = 2304 x 1728 pixels
* 36 = 3008 x 2008 pixels
*/
public static final int TAG_CASIO_TYPE2_IMAGE_SIZE = 0x0009;
/**
* 0 = Normal
* 1 = Macro
*/
public static final int TAG_CASIO_TYPE2_FOCUS_MODE_1 = 0x000D;
/**
* 3 = 50
* 4 = 64
* 6 = 100
* 9 = 200
*/
public static final int TAG_CASIO_TYPE2_ISO_SENSITIVITY = 0x0014;
/**
* 0 = Auto
* 1 = Daylight
* 2 = Shade
* 3 = Tungsten
* 4 = Fluorescent
* 5 = Manual
*/
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_1 = 0x0019;
/**
* Units are tenths of a millimetre
*/
public static final int TAG_CASIO_TYPE2_FOCAL_LENGTH = 0x001D;
/**
* 0 = -1
* 1 = Normal
* 2 = +1
*/
public static final int TAG_CASIO_TYPE2_SATURATION = 0x001F;
/**
* 0 = -1
* 1 = Normal
* 2 = +1
*/
public static final int TAG_CASIO_TYPE2_CONTRAST = 0x0020;
/**
* 0 = -1
* 1 = Normal
* 2 = +1
*/
public static final int TAG_CASIO_TYPE2_SHARPNESS = 0x0021;
/**
* See PIM specification here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html
*/
public static final int TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO = 0x0E00;
/**
* Alternate thumbnail offset
*/
public static final int TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL = 0x2000;
/**
*
*/
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS = 0x2011;
/**
* 12 = Flash
* 0 = Manual
* 1 = Auto?
* 4 = Flash?
*/
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_2 = 0x2012;
/**
* Units are millimetres
*/
public static final int TAG_CASIO_TYPE2_OBJECT_DISTANCE = 0x2022;
/**
* 0 = Off
*/
public static final int TAG_CASIO_TYPE2_FLASH_DISTANCE = 0x2034;
/**
* 2 = Normal Mode
*/
public static final int TAG_CASIO_TYPE2_RECORD_MODE = 0x3000;
/**
* 1 = Off?
*/
public static final int TAG_CASIO_TYPE2_SELF_TIMER = 0x3001;
/**
* 3 = Fine
*/
public static final int TAG_CASIO_TYPE2_QUALITY = 0x3002;
/**
* 1 = Fixation
* 6 = Multi-Area Auto Focus
*/
public static final int TAG_CASIO_TYPE2_FOCUS_MODE_2 = 0x3003;
/**
* (string)
*/
public static final int TAG_CASIO_TYPE2_TIME_ZONE = 0x3006;
/**
*
*/
public static final int TAG_CASIO_TYPE2_BESTSHOT_MODE = 0x3007;
/**
* 0 = Off
* 1 = On?
*/
public static final int TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY = 0x3014;
/**
* 0 = Off
*/
public static final int TAG_CASIO_TYPE2_COLOUR_MODE = 0x3015;
/**
* 0 = Off
*/
public static final int TAG_CASIO_TYPE2_ENHANCEMENT = 0x3016;
/**
* 0 = Off
*/
public static final int TAG_CASIO_TYPE2_FILTER = 0x3017;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
// TODO add names
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS), "Thumbnail Dimensions");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_SIZE), "Thumbnail Size");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET), "Thumbnail Offset");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY_MODE), "Quality Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_IMAGE_SIZE), "Image Size");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_1), "Focus Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ISO_SENSITIVITY), "ISO Sensitivity");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_1), "White Balance");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCAL_LENGTH), "Focal Length");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SATURATION), "Saturation");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CONTRAST), "Contrast");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL), "Casio Preview Thumbnail");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS), "White Balance Bias");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_2), "White Balance");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_OBJECT_DISTANCE), "Object Distance");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FLASH_DISTANCE), "Flash Distance");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_RECORD_MODE), "Record Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SELF_TIMER), "Self Timer");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY), "Quality");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_2), "Focus Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_TIME_ZONE), "Time Zone");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_BESTSHOT_MODE), "BestShot Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY), "CCD ISO Sensitivity");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_COLOUR_MODE), "Colour Mode");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ENHANCEMENT), "Enhancement");
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FILTER), "Filter");
}
 
public CasioType2MakernoteDirectory()
{
this.setDescriptor(new CasioType2MakernoteDescriptor(this));
}
 
public String getName()
{
return "Casio Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifReader.java
0,0 → 1,668
/*
* EXIFExtractor.java
*
* This class based upon code from Jhead, a C program for extracting and
* manipulating the Exif data within files written by Matthias Wandel.
* http://www.sentex.net/~mwandel/jhead/
*
* Jhead is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. Similarly, I release this Java version under the
* same license, though I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site. Unlike
* Jhead, this code (as it stands) only supports reading of Exif data - no
* manipulation, and no thumbnail stuff.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew.noakes@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on 28 April 2002, 23:54
* Modified 04 Aug 2002
* - Renamed constants to be inline with changes to ExifTagValues interface
* - Substituted usage of JDK 1.4 features (java.nio package)
* Modified 29 Oct 2002 (v1.2)
* - Proper traversing of Exif file structure and complete refactor & tidy of
* the codebase (a few unnoticed bugs removed)
* - Reads makernote data for 6 families of camera (5 makes)
* - Tags now stored in directories... use the IFD_* constants to refer to the
* image file directory you require (Exif, Interop, GPS and Makernote*) --
* this avoids collisions where two tags share the same code
* - Takes componentCount of unknown tags into account
* - Now understands GPS tags (thanks to Colin Briton for his help with this)
* - Some other bug fixes, pointed out by users around the world. Thanks!
* Modified 27 Nov 2002 (v2.0)
* - Renamed to ExifReader
* - Moved to new package com.drew.metadata.exif
* Modified since, however changes have not been logged. See release notes for
* library-wide modifications.
*/
package com.drew.metadata.exif;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataReader;
 
import java.io.File;
import java.io.InputStream;
import java.util.HashMap;
 
/**
* Extracts Exif data from a JPEG header segment, providing information about the
* camera/scanner/capture device (if available). Information is encapsulated in
* an <code>Metadata</code> object.
* @author Drew Noakes http://drewnoakes.com
*/
public class ExifReader implements MetadataReader
{
/**
* The JPEG segment as an array of bytes.
*/
private final byte[] _data;
 
/**
* Represents the native byte ordering used in the JPEG segment. If true,
* then we're using Motorolla ordering (Big endian), else we're using Intel
* ordering (Little endian).
*/
private boolean _isMotorollaByteOrder;
 
/**
* Bean instance to store information about the image and camera/scanner/capture
* device.
*/
private Metadata _metadata;
 
/**
* The number of bytes used per format descriptor.
*/
private static final int[] BYTES_PER_FORMAT = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8};
 
/**
* The number of formats known.
*/
private static final int MAX_FORMAT_CODE = 12;
 
// Format types
// Note: Cannot use the DataFormat enumeration in the case statement that uses these tags.
// Is there a better way?
private static final int FMT_BYTE = 1;
private static final int FMT_STRING = 2;
private static final int FMT_USHORT = 3;
private static final int FMT_ULONG = 4;
private static final int FMT_URATIONAL = 5;
private static final int FMT_SBYTE = 6;
private static final int FMT_UNDEFINED = 7;
private static final int FMT_SSHORT = 8;
private static final int FMT_SLONG = 9;
private static final int FMT_SRATIONAL = 10;
private static final int FMT_SINGLE = 11;
private static final int FMT_DOUBLE = 12;
 
public static final int TAG_EXIF_OFFSET = 0x8769;
public static final int TAG_INTEROP_OFFSET = 0xA005;
public static final int TAG_GPS_INFO_OFFSET = 0x8825;
public static final int TAG_MAKER_NOTE = 0x927C;
 
public static final int TIFF_HEADER_START_OFFSET = 6;
 
/**
* Creates an ExifReader for a JpegSegmentData object.
* @param segmentData
*/
public ExifReader(JpegSegmentData segmentData)
{
this(segmentData.getSegment(JpegSegmentReader.SEGMENT_APP1));
}
 
/**
* Creates an ExifReader for a Jpeg file.
* @param file
* @throws JpegProcessingException
*/
public ExifReader(File file) throws JpegProcessingException
{
this(new JpegSegmentReader(file).readSegment(JpegSegmentReader.SEGMENT_APP1));
}
 
/**
* Creates an ExifReader for a Jpeg stream.
* @param is JPEG stream. Stream will be closed.
*/
public ExifReader(InputStream is) throws JpegProcessingException
{
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APP1));
}
 
/**
* Creates an ExifReader for the given JPEG header segment.
*/
public ExifReader(byte[] data)
{
_data = data;
}
 
/**
* Performs the Exif data extraction, returning a new instance of <code>Metadata</code>.
*/
public Metadata extract()
{
return extract(new Metadata());
}
 
/**
* Performs the Exif data extraction, adding found values to the specified
* instance of <code>Metadata</code>.
*/
public Metadata extract(Metadata metadata)
{
_metadata = metadata;
if (_data==null)
return _metadata;
 
// once we know there's some data, create the directory and start working on it
ExifDirectory directory = (ExifDirectory)_metadata.getDirectory(ExifDirectory.class);
 
// check for the header length
if (_data.length<=14) {
directory.addError("Exif data segment must contain at least 14 bytes");
return _metadata;
}
 
// check for the header preamble
if (!"Exif\0\0".equals(new String(_data, 0, 6))) {
directory.addError("Exif data segment doesn't begin with 'Exif'");
return _metadata;
}
 
// this should be either "MM" or "II"
String byteOrderIdentifier = new String(_data, 6, 2);
if (!setByteOrder(byteOrderIdentifier)) {
directory.addError("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier);
return _metadata;
}
 
// Check the next two values for correctness.
if (get16Bits(8)!=0x2a) {
directory.addError("Invalid Exif start - should have 0x2A at offset 8 in Exif header");
return _metadata;
}
 
int firstDirectoryOffset = get32Bits(10) + TIFF_HEADER_START_OFFSET;
 
// David Ekholm sent an digital camera image that has this problem
if (firstDirectoryOffset>=_data.length - 1) {
directory.addError("First exif directory offset is beyond end of Exif data segment");
// First directory normally starts 14 bytes in -- try it here and catch another error in the worst case
firstDirectoryOffset = 14;
}
 
HashMap processedDirectoryOffsets = new HashMap();
 
// 0th IFD (we merge with Exif IFD)
processDirectory(directory, processedDirectoryOffsets, firstDirectoryOffset, TIFF_HEADER_START_OFFSET);
 
// after the extraction process, if we have the correct tags, we may be able to store thumbnail information
storeThumbnailBytes(directory, TIFF_HEADER_START_OFFSET);
 
return _metadata;
}
 
private void storeThumbnailBytes(ExifDirectory exifDirectory, int tiffHeaderOffset)
{
if (!exifDirectory.containsTag(ExifDirectory.TAG_COMPRESSION))
return;
 
if (!exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH) ||
!exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET))
return;
 
try {
int offset = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET);
int length = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH);
byte[] result = new byte[length];
for (int i = 0; i<result.length; i++) {
result[i] = _data[tiffHeaderOffset + offset + i];
}
exifDirectory.setByteArray(ExifDirectory.TAG_THUMBNAIL_DATA, result);
} catch (Throwable e) {
exifDirectory.addError("Unable to extract thumbnail: " + e.getMessage());
}
}
 
private boolean setByteOrder(String byteOrderIdentifier)
{
if ("MM".equals(byteOrderIdentifier)) {
_isMotorollaByteOrder = true;
} else if ("II".equals(byteOrderIdentifier)) {
_isMotorollaByteOrder = false;
} else {
return false;
}
return true;
}
 
/**
* Process one of the nested Tiff IFD directories.
* 2 bytes: number of tags
* for each tag
* 2 bytes: tag type
* 2 bytes: format code
* 4 bytes: component count
*/
private void processDirectory(Directory directory, HashMap processedDirectoryOffsets, int dirStartOffset, int tiffHeaderOffset)
{
// check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist
if (processedDirectoryOffsets.containsKey(new Integer(dirStartOffset)))
return;
 
// remember that we've visited this directory so that we don't visit it again later
processedDirectoryOffsets.put(new Integer(dirStartOffset), "processed");
 
if (dirStartOffset>=_data.length || dirStartOffset<0) {
directory.addError("Ignored directory marked to start outside data segement");
return;
}
 
if (!isDirectoryLengthValid(dirStartOffset, tiffHeaderOffset)) {
directory.addError("Illegally sized directory");
return;
}
 
// First two bytes in the IFD are the number of tags in this directory
int dirTagCount = get16Bits(dirStartOffset);
 
// Handle each tag in this directory
for (int tagNumber = 0; tagNumber<dirTagCount; tagNumber++)
{
final int tagOffset = calculateTagOffset(dirStartOffset, tagNumber);
 
// 2 bytes for the tag type
final int tagType = get16Bits(tagOffset);
 
// 2 bytes for the format code
final int formatCode = get16Bits(tagOffset + 2);
if (formatCode<1 || formatCode>MAX_FORMAT_CODE) {
directory.addError("Invalid format code: " + formatCode);
continue;
}
 
// 4 bytes dictate the number of components in this tag's data
final int componentCount = get32Bits(tagOffset + 4);
if (componentCount<0) {
directory.addError("Negative component count in EXIF");
continue;
}
// each component may have more than one byte... calculate the total number of bytes
final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode];
final int tagValueOffset = calculateTagValueOffset(byteCount, tagOffset, tiffHeaderOffset);
if (tagValueOffset<0 || tagValueOffset > _data.length) {
directory.addError("Illegal pointer offset value in EXIF");
continue;
}
 
// Check that this tag isn't going to allocate outside the bounds of the data array.
// This addresses an uncommon OutOfMemoryError.
if (byteCount < 0 || tagValueOffset + byteCount > _data.length)
{
directory.addError("Illegal number of bytes: " + byteCount);
continue;
}
 
// Calculate the value as an offset for cases where the tag represents directory
final int subdirOffset = tiffHeaderOffset + get32Bits(tagValueOffset);
 
switch (tagType) {
case TAG_EXIF_OFFSET:
processDirectory(_metadata.getDirectory(ExifDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
continue;
case TAG_INTEROP_OFFSET:
processDirectory(_metadata.getDirectory(ExifInteropDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
continue;
case TAG_GPS_INFO_OFFSET:
processDirectory(_metadata.getDirectory(GpsDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
continue;
case TAG_MAKER_NOTE:
processMakerNote(tagValueOffset, processedDirectoryOffsets, tiffHeaderOffset);
continue;
default:
processTag(directory, tagType, tagValueOffset, componentCount, formatCode);
break;
}
}
 
// at the end of each IFD is an optional link to the next IFD
final int finalTagOffset = calculateTagOffset(dirStartOffset, dirTagCount);
int nextDirectoryOffset = get32Bits(finalTagOffset);
if (nextDirectoryOffset!=0) {
nextDirectoryOffset += tiffHeaderOffset;
if (nextDirectoryOffset>=_data.length) {
// Last 4 bytes of IFD reference another IFD with an address that is out of bounds
// Note this could have been caused by jhead 1.3 cropping too much
return;
} else if (nextDirectoryOffset < dirStartOffset) {
// Last 4 bytes of IFD reference another IFD with an address that is before the start of this directory
return;
}
// the next directory is of same type as this one
processDirectory(directory, processedDirectoryOffsets, nextDirectoryOffset, tiffHeaderOffset);
}
}
 
private void processMakerNote(int subdirOffset, HashMap processedDirectoryOffsets, int tiffHeaderOffset)
{
// Determine the camera model and makernote format
Directory exifDirectory = _metadata.getDirectory(ExifDirectory.class);
 
if (exifDirectory==null)
return;
 
String cameraModel = exifDirectory.getString(ExifDirectory.TAG_MAKE);
final String firstTwoChars = new String(_data, subdirOffset, 2);
final String firstThreeChars = new String(_data, subdirOffset, 3);
final String firstFourChars = new String(_data, subdirOffset, 4);
final String firstFiveChars = new String(_data, subdirOffset, 5);
final String firstSixChars = new String(_data, subdirOffset, 6);
final String firstSevenChars = new String(_data, subdirOffset, 7);
final String firstEightChars = new String(_data, subdirOffset, 8);
if ("OLYMP".equals(firstFiveChars) || "EPSON".equals(firstFiveChars) || "AGFA".equals(firstFourChars))
{
// Olympus Makernote
// Epson and Agfa use Olypus maker note standard, see:
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/
processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset);
}
else if (cameraModel!=null && cameraModel.trim().toUpperCase().startsWith("NIKON"))
{
if ("Nikon".equals(firstFiveChars))
{
/* There are two scenarios here:
* Type 1: **
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
* Type 3: **
* :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*...
* :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200
*/
if (_data[subdirOffset+6]==1)
processDirectory(_metadata.getDirectory(NikonType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset);
else if (_data[subdirOffset+6]==2)
processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 18, subdirOffset + 10);
else
exifDirectory.addError("Unsupported makernote data ignored.");
}
else
{
// The IFD begins with the first MakerNote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models.
processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
}
}
else if ("SONY CAM".equals(firstEightChars) || "SONY DSC".equals(firstEightChars))
{
processDirectory(_metadata.getDirectory(SonyMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset);
}
else if ("KDK".equals(firstThreeChars))
{
processDirectory(_metadata.getDirectory(KodakMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 20, tiffHeaderOffset);
}
else if ("Canon".equalsIgnoreCase(cameraModel))
{
processDirectory(_metadata.getDirectory(CanonMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
}
else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("CASIO"))
{
if ("QVC\u0000\u0000\u0000".equals(firstSixChars))
processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, tiffHeaderOffset);
else
processDirectory(_metadata.getDirectory(CasioType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
}
else if ("FUJIFILM".equals(firstEightChars) || "Fujifilm".equalsIgnoreCase(cameraModel))
{
// TODO make this field a passed parameter, to avoid threading issues
boolean byteOrderBefore = _isMotorollaByteOrder;
// bug in fujifilm makernote ifd means we temporarily use Intel byte ordering
_isMotorollaByteOrder = false;
// the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote
// IFD, though the offset is relative to the start of the makernote, not the TIFF
// header (like everywhere else)
int ifdStart = subdirOffset + get32Bits(subdirOffset + 8);
processDirectory(_metadata.getDirectory(FujifilmMakernoteDirectory.class), processedDirectoryOffsets, ifdStart, tiffHeaderOffset);
_isMotorollaByteOrder = byteOrderBefore;
}
else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("MINOLTA"))
{
// Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote
// area that commences immediately.
processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset);
}
else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars))
{
// This Konica data is not understood. Header identified in accordance with information at this site:
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html
// TODO determine how to process the information described at the above website
exifDirectory.addError("Unsupported Konica/Minolta data ignored.");
}
else if ("KYOCERA".equals(firstSevenChars))
{
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html
processDirectory(_metadata.getDirectory(KyoceraMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 22, tiffHeaderOffset);
}
else if ("Panasonic\u0000\u0000\u0000".equals(new String(_data, subdirOffset, 12)))
{
// NON-Standard TIFF IFD Data using Panasonic Tags. There is no Next-IFD pointer after the IFD
// Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment
// more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html
processDirectory(_metadata.getDirectory(PanasonicMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset);
}
else if ("AOC\u0000".equals(firstFourChars))
{
// NON-Standard TIFF IFD Data using Casio Type 2 Tags
// IFD has no Next-IFD pointer at end of IFD, and
// Offsets are relative to the start of the current IFD tag, not the TIFF header
// Observed for:
// - Pentax ist D
processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, subdirOffset);
}
else if (cameraModel!=null && (cameraModel.toUpperCase().startsWith("PENTAX") || cameraModel.toUpperCase().startsWith("ASAHI")))
{
// NON-Standard TIFF IFD Data using Pentax Tags
// IFD has no Next-IFD pointer at end of IFD, and
// Offsets are relative to the start of the current IFD tag, not the TIFF header
// Observed for:
// - PENTAX Optio 330
// - PENTAX Optio 430
processDirectory(_metadata.getDirectory(PentaxMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, subdirOffset);
}
else
{
// TODO how to store makernote data when it's not from a supported camera model?
// this is difficult as the starting offset is not known. we could look for it...
exifDirectory.addError("Unsupported makernote data ignored.");
}
}
 
private boolean isDirectoryLengthValid(int dirStartOffset, int tiffHeaderOffset)
{
int dirTagCount = get16Bits(dirStartOffset);
int dirLength = (2 + (12 * dirTagCount) + 4);
if (dirLength + dirStartOffset + tiffHeaderOffset>=_data.length) {
// Note: Files that had thumbnails trimmed with jhead 1.3 or earlier might trigger this
return false;
}
return true;
}
 
private void processTag(Directory directory, int tagType, int tagValueOffset, int componentCount, int formatCode)
{
// Directory simply stores raw values
// The display side uses a Descriptor class per directory to turn the raw values into 'pretty' descriptions
switch (formatCode)
{
case FMT_UNDEFINED:
// this includes exif user comments
final byte[] tagBytes = new byte[componentCount];
final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode];
for (int i=0; i<byteCount; i++)
tagBytes[i] = _data[tagValueOffset + i];
directory.setByteArray(tagType, tagBytes);
break;
case FMT_STRING:
directory.setString(tagType, readString(tagValueOffset, componentCount));
break;
case FMT_SRATIONAL:
case FMT_URATIONAL:
if (componentCount==1) {
Rational rational = new Rational(get32Bits(tagValueOffset), get32Bits(tagValueOffset + 4));
directory.setRational(tagType, rational);
} else {
Rational[] rationals = new Rational[componentCount];
for (int i = 0; i<componentCount; i++)
rationals[i] = new Rational(get32Bits(tagValueOffset + (8 * i)), get32Bits(tagValueOffset + 4 + (8 * i)));
directory.setRationalArray(tagType, rationals);
}
break;
case FMT_SBYTE:
case FMT_BYTE:
if (componentCount==1) {
// this may need to be a byte, but I think casting to int is fine
int b = _data[tagValueOffset];
directory.setInt(tagType, b);
} else {
int[] bytes = new int[componentCount];
for (int i = 0; i<componentCount; i++)
bytes[i] = _data[tagValueOffset + i];
directory.setIntArray(tagType, bytes);
}
break;
case FMT_SINGLE:
case FMT_DOUBLE:
if (componentCount==1) {
int i = _data[tagValueOffset];
directory.setInt(tagType, i);
} else {
int[] ints = new int[componentCount];
for (int i = 0; i<componentCount; i++)
ints[i] = _data[tagValueOffset + i];
directory.setIntArray(tagType, ints);
}
break;
case FMT_USHORT:
case FMT_SSHORT:
if (componentCount==1) {
int i = get16Bits(tagValueOffset);
directory.setInt(tagType, i);
} else {
int[] ints = new int[componentCount];
for (int i = 0; i<componentCount; i++)
ints[i] = get16Bits(tagValueOffset + (i * 2));
directory.setIntArray(tagType, ints);
}
break;
case FMT_SLONG:
case FMT_ULONG:
if (componentCount==1) {
int i = get32Bits(tagValueOffset);
directory.setInt(tagType, i);
} else {
int[] ints = new int[componentCount];
for (int i = 0; i<componentCount; i++)
ints[i] = get32Bits(tagValueOffset + (i * 4));
directory.setIntArray(tagType, ints);
}
break;
default:
directory.addError("Unknown format code " + formatCode + " for tag " + tagType);
}
}
 
private int calculateTagValueOffset(int byteCount, int dirEntryOffset, int tiffHeaderOffset)
{
if (byteCount>4) {
// If its bigger than 4 bytes, the dir entry contains an offset.
// dirEntryOffset must be passed, as some makernote implementations (e.g. FujiFilm) incorrectly use an
// offset relative to the start of the makernote itself, not the TIFF segment.
final int offsetVal = get32Bits(dirEntryOffset + 8);
if (offsetVal + byteCount>_data.length) {
// Bogus pointer offset and / or bytecount value
return -1; // signal error
}
return tiffHeaderOffset + offsetVal;
} else {
// 4 bytes or less and value is in the dir entry itself
return dirEntryOffset + 8;
}
}
 
/**
* Creates a String from the _data buffer starting at the specified offset,
* and ending where byte=='\0' or where length==maxLength.
*/
private String readString(int offset, int maxLength)
{
int length = 0;
while ((offset + length)<_data.length && _data[offset + length]!='\0' && length<maxLength)
length++;
 
return new String(_data, offset, length);
}
 
/**
* Determine the offset at which a given InteropArray entry begins within the specified IFD.
* @param dirStartOffset the offset at which the IFD starts
* @param entryNumber the zero-based entry number
*/
private int calculateTagOffset(int dirStartOffset, int entryNumber)
{
// add 2 bytes for the tag count
// each entry is 12 bytes, so we skip 12 * the number seen so far
return dirStartOffset + 2 + (12 * entryNumber);
}
 
/**
* Get a 16 bit value from file's native byte order. Between 0x0000 and 0xFFFF.
*/
private int get16Bits(int offset)
{
if (offset<0 || offset+2>_data.length)
throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")");
 
if (_isMotorollaByteOrder) {
// Motorola - MSB first
return (_data[offset] << 8 & 0xFF00) | (_data[offset + 1] & 0xFF);
} else {
// Intel ordering - LSB first
return (_data[offset + 1] << 8 & 0xFF00) | (_data[offset] & 0xFF);
}
}
 
/**
* Get a 32 bit value from file's native byte order.
*/
private int get32Bits(int offset)
{
if (offset<0 || offset+4>_data.length)
throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")");
 
if (_isMotorollaByteOrder) {
// Motorola - MSB first
return (_data[offset] << 24 & 0xFF000000) |
(_data[offset + 1] << 16 & 0xFF0000) |
(_data[offset + 2] << 8 & 0xFF00) |
(_data[offset + 3] & 0xFF);
} else {
// Intel ordering - LSB first
return (_data[offset + 3] << 24 & 0xFF000000) |
(_data[offset + 2] << 16 & 0xFF0000) |
(_data[offset + 1] << 8 & 0xFF00) |
(_data[offset] & 0xFF);
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/GpsDirectory.java
0,0 → 1,130
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Nov-2002 11:00:52 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class GpsDirectory extends Directory
{
/** GPS tag version GPSVersionID 0 0 BYTE 4 */
public static final int TAG_GPS_VERSION_ID = 0x0000;
/** North or South Latitude GPSLatitudeRef 1 1 ASCII 2 */
public static final int TAG_GPS_LATITUDE_REF = 0x0001;
/** Latitude GPSLatitude 2 2 RATIONAL 3 */
public static final int TAG_GPS_LATITUDE = 0x0002;
/** East or West Longitude GPSLongitudeRef 3 3 ASCII 2 */
public static final int TAG_GPS_LONGITUDE_REF = 0x0003;
/** Longitude GPSLongitude 4 4 RATIONAL 3 */
public static final int TAG_GPS_LONGITUDE = 0x0004;
/** Altitude reference GPSAltitudeRef 5 5 BYTE 1 */
public static final int TAG_GPS_ALTITUDE_REF = 0x0005;
/** Altitude GPSAltitude 6 6 RATIONAL 1 */
public static final int TAG_GPS_ALTITUDE = 0x0006;
/** GPS time (atomic clock) GPSTimeStamp 7 7 RATIONAL 3 */
public static final int TAG_GPS_TIME_STAMP = 0x0007;
/** GPS satellites used for measurement GPSSatellites 8 8 ASCII Any */
public static final int TAG_GPS_SATELLITES = 0x0008;
/** GPS receiver status GPSStatus 9 9 ASCII 2 */
public static final int TAG_GPS_STATUS = 0x0009;
/** GPS measurement mode GPSMeasureMode 10 A ASCII 2 */
public static final int TAG_GPS_MEASURE_MODE = 0x000A;
/** Measurement precision GPSDOP 11 B RATIONAL 1 */
public static final int TAG_GPS_DOP = 0x000B;
/** Speed unit GPSSpeedRef 12 C ASCII 2 */
public static final int TAG_GPS_SPEED_REF = 0x000C;
/** Speed of GPS receiver GPSSpeed 13 D RATIONAL 1 */
public static final int TAG_GPS_SPEED = 0x000D;
/** Reference for direction of movement GPSTrackRef 14 E ASCII 2 */
public static final int TAG_GPS_TRACK_REF = 0x000E;
/** Direction of movement GPSTrack 15 F RATIONAL 1 */
public static final int TAG_GPS_TRACK = 0x000F;
/** Reference for direction of image GPSImgDirectionRef 16 10 ASCII 2 */
public static final int TAG_GPS_IMG_DIRECTION_REF = 0x0010;
/** Direction of image GPSImgDirection 17 11 RATIONAL 1 */
public static final int TAG_GPS_IMG_DIRECTION = 0x0011;
/** Geodetic survey data used GPSMapDatum 18 12 ASCII Any */
public static final int TAG_GPS_MAP_DATUM = 0x0012;
/** Reference for latitude of destination GPSDestLatitudeRef 19 13 ASCII 2 */
public static final int TAG_GPS_DEST_LATITUDE_REF = 0x0013;
/** Latitude of destination GPSDestLatitude 20 14 RATIONAL 3 */
public static final int TAG_GPS_DEST_LATITUDE = 0x0014;
/** Reference for longitude of destination GPSDestLongitudeRef 21 15 ASCII 2 */
public static final int TAG_GPS_DEST_LONGITUDE_REF = 0x0015;
/** Longitude of destination GPSDestLongitude 22 16 RATIONAL 3 */
public static final int TAG_GPS_DEST_LONGITUDE = 0x0016;
/** Reference for bearing of destination GPSDestBearingRef 23 17 ASCII 2 */
public static final int TAG_GPS_DEST_BEARING_REF = 0x0017;
/** Bearing of destination GPSDestBearing 24 18 RATIONAL 1 */
public static final int TAG_GPS_DEST_BEARING = 0x0018;
/** Reference for distance to destination GPSDestDistanceRef 25 19 ASCII 2 */
public static final int TAG_GPS_DEST_DISTANCE_REF = 0x0019;
/** Distance to destination GPSDestDistance 26 1A RATIONAL 1 */
public static final int TAG_GPS_DEST_DISTANCE = 0x001A;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_GPS_VERSION_ID), "GPS Version ID");
tagNameMap.put(new Integer(TAG_GPS_LATITUDE_REF), "GPS Latitude Ref");
tagNameMap.put(new Integer(TAG_GPS_LATITUDE), "GPS Latitude");
tagNameMap.put(new Integer(TAG_GPS_LONGITUDE_REF), "GPS Longitude Ref");
tagNameMap.put(new Integer(TAG_GPS_LONGITUDE), "GPS Longitude");
tagNameMap.put(new Integer(TAG_GPS_ALTITUDE_REF), "GPS Altitude Ref");
tagNameMap.put(new Integer(TAG_GPS_ALTITUDE), "GPS Altitude");
tagNameMap.put(new Integer(TAG_GPS_TIME_STAMP), "GPS Time-Stamp");
tagNameMap.put(new Integer(TAG_GPS_SATELLITES), "GPS Satellites");
tagNameMap.put(new Integer(TAG_GPS_STATUS), "GPS Status");
tagNameMap.put(new Integer(TAG_GPS_MEASURE_MODE), "GPS Measure Mode");
tagNameMap.put(new Integer(TAG_GPS_DOP), "GPS DOP");
tagNameMap.put(new Integer(TAG_GPS_SPEED_REF), "GPS Speed Ref");
tagNameMap.put(new Integer(TAG_GPS_SPEED), "GPS Speed");
tagNameMap.put(new Integer(TAG_GPS_TRACK_REF), "GPS Track Ref");
tagNameMap.put(new Integer(TAG_GPS_TRACK), "GPS Track");
tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction Ref");
tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction");
tagNameMap.put(new Integer(TAG_GPS_MAP_DATUM), "GPS Map Datum");
tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE_REF), "GPS Dest Latitude Ref");
tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE), "GPS Dest Latitude");
tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE_REF), "GPS Dest Longitude Ref");
tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE), "GPS Dest Longitude");
tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING_REF), "GPS Dest Bearing Ref");
tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING), "GPS Dest Bearing");
tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE_REF), "GPS Dest Distance Ref");
tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE), "GPS Dest Distance");
}
 
public GpsDirectory()
{
this.setDescriptor(new GpsDescriptor(this));
}
 
public String getName()
{
return "GPS";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PanasonicMakernoteDescriptor.java
0,0 → 1,85
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a PanasonicMakernoteDirectory.
*
* Some information about this makernote taken from here:
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html
*/
public class PanasonicMakernoteDescriptor extends TagDescriptor
{
public PanasonicMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType)
{
case PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE:
return getMacroModeDescription();
case PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE:
return getRecordModeDescription();
case PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO:
return getPrintImageMatchingInfoDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getPrintImageMatchingInfoDescription() throws MetadataException
{
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null;
byte[] bytes = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO);
return "(" + bytes.length + " bytes)";
}
 
public String getMacroModeDescription() throws MetadataException
{
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null;
int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE);
switch (value) {
case 1:
return "On";
case 2:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getRecordModeDescription() throws MetadataException
{
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null;
int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE);
switch (value) {
case 1:
return "Normal";
case 2:
return "Portrait";
case 9:
return "Macro";
default:
return "Unknown (" + value + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifDirectory.java
0,0 → 1,954
/*
* ExifDirectory.java
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 25-Nov-2002 20:41:00 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
 
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
 
/**
*
*/
public class ExifDirectory extends Directory
{
// TODO do these tags belong in the exif directory?
public static final int TAG_SUB_IFDS = 0x014A;
public static final int TAG_GPS_INFO = 0x8825;
 
/**
* The actual aperture value of lens when the image was taken. Unit is APEX.
* To convert this value to ordinary F-number (F-stop), calculate this value's
* power of root 2 (=1.4142). For example, if the ApertureValue is '5',
* F-number is 1.4142^5 = F5.6.
*/
public static final int TAG_APERTURE = 0x9202;
/**
* When image format is no compression, this value shows the number of bits
* per component for each pixel. Usually this value is '8,8,8'.
*/
public static final int TAG_BITS_PER_SAMPLE = 0x0102;
/**
* Shows compression method for Thumbnail.
* 1 = Uncompressed
* 2 = CCITT 1D
* 3 = T4/Group 3 Fax
* 4 = T6/Group 4 Fax
* 5 = LZW
* 6 = JPEG (old-style)
* 7 = JPEG
* 8 = Adobe Deflate
* 9 = JBIG B&W
* 10 = JBIG Color
* 32766 = Next
* 32771 = CCIRLEW
* 32773 = PackBits
* 32809 = Thunderscan
* 32895 = IT8CTPAD
* 32896 = IT8LW
* 32897 = IT8MP
* 32898 = IT8BL
* 32908 = PixarFilm
* 32909 = PixarLog
* 32946 = Deflate
* 32947 = DCS
* 34661 = JBIG
* 34676 = SGILog
* 34677 = SGILog24
* 34712 = JPEG 2000
* 34713 = Nikon NEF Compressed
*/
public static final int TAG_COMPRESSION = 0x0103;
public static final int COMPRESSION_NONE = 1;
public static final int COMPRESSION_JPEG = 6;
 
/**
* Shows the color space of the image data components.
* 0 = WhiteIsZero
* 1 = BlackIsZero
* 2 = RGB
* 3 = RGB Palette
* 4 = Transparency Mask
* 5 = CMYK
* 6 = YCbCr
* 8 = CIELab
* 9 = ICCLab
* 10 = ITULab
* 32803 = Color Filter Array
* 32844 = Pixar LogL
* 32845 = Pixar LogLuv
* 34892 = Linear Raw
*/
public static final int TAG_PHOTOMETRIC_INTERPRETATION = 0x0106;
/**
* 1 = No dithering or halftoning
* 2 = Ordered dither or halftone
* 3 = Randomized dither
*/
public static final int TAG_THRESHOLDING = 0x0107;
public static final int PHOTOMETRIC_INTERPRETATION_MONOCHROME = 1;
public static final int PHOTOMETRIC_INTERPRETATION_RGB = 2;
public static final int PHOTOMETRIC_INTERPRETATION_YCBCR = 6;
 
/** The position in the file of raster data. */
public static final int TAG_STRIP_OFFSETS = 0x0111;
/** Each pixel is composed of this many samples. */
public static final int TAG_SAMPLES_PER_PIXEL = 0x0115;
/** The raster is codified by a single block of data holding this many rows. */
public static final int TAG_ROWS_PER_STRIP = 0x116;
/** The size of the raster data in bytes. */
public static final int TAG_STRIP_BYTE_COUNTS = 0x0117;
public static final int TAG_MIN_SAMPLE_VALUE = 0x0118;
public static final int TAG_MAX_SAMPLE_VALUE = 0x0119;
/**
* When image format is no compression YCbCr, this value shows byte aligns of
* YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for
* each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and
* stored to Y plane/Cb plane/Cr plane format.
*/
public static final int TAG_PLANAR_CONFIGURATION = 0x011C;
public static final int TAG_YCBCR_SUBSAMPLING = 0x0212;
public static final int TAG_IMAGE_DESCRIPTION = 0x010E;
public static final int TAG_SOFTWARE = 0x0131;
public static final int TAG_DATETIME = 0x0132;
public static final int TAG_WHITE_POINT = 0x013E;
public static final int TAG_PRIMARY_CHROMATICITIES = 0x013F;
public static final int TAG_YCBCR_COEFFICIENTS = 0x0211;
public static final int TAG_REFERENCE_BLACK_WHITE = 0x0214;
public static final int TAG_COPYRIGHT = 0x8298;
 
/**
* The new subfile type tag.
* 0 = Full-resolution Image
* 1 = Reduced-resolution image
* 2 = Single page of multi-page image
* 3 = Single page of multi-page reduced-resolution image
* 4 = Transparency mask
* 5 = Transparency mask of reduced-resolution image
* 6 = Transparency mask of multi-page image
* 7 = Transparency mask of reduced-resolution multi-page image
*/
public static final int TAG_NEW_SUBFILE_TYPE = 0x00FE;
/**
* The old subfile type tag.
* 1 = Full-resolution image (Main image)
* 2 = Reduced-resolution image (Thumbnail)
* 3 = Single page of multi-page image
*/
public static final int TAG_SUBFILE_TYPE = 0x00FF;
public static final int TAG_TRANSFER_FUNCTION = 0x012D;
public static final int TAG_ARTIST = 0x013B;
public static final int TAG_PREDICTOR = 0x013D;
public static final int TAG_TILE_WIDTH = 0x0142;
public static final int TAG_TILE_LENGTH = 0x0143;
public static final int TAG_TILE_OFFSETS = 0x0144;
public static final int TAG_TILE_BYTE_COUNTS = 0x0145;
public static final int TAG_JPEG_TABLES = 0x015B;
public static final int TAG_CFA_REPEAT_PATTERN_DIM = 0x828D;
/** There are two definitions for CFA pattern, I don't know the difference... */
public static final int TAG_CFA_PATTERN_2 = 0x828E;
public static final int TAG_BATTERY_LEVEL = 0x828F;
public static final int TAG_IPTC_NAA = 0x83BB;
public static final int TAG_INTER_COLOR_PROFILE = 0x8773;
public static final int TAG_SPECTRAL_SENSITIVITY = 0x8824;
public static final int TAG_OECF = 0x8828;
public static final int TAG_INTERLACE = 0x8829;
public static final int TAG_TIME_ZONE_OFFSET = 0x882A;
public static final int TAG_SELF_TIMER_MODE = 0x882B;
public static final int TAG_FLASH_ENERGY = 0x920B;
public static final int TAG_SPATIAL_FREQ_RESPONSE = 0x920C;
public static final int TAG_NOISE = 0x920D;
public static final int TAG_IMAGE_NUMBER = 0x9211;
public static final int TAG_SECURITY_CLASSIFICATION = 0x9212;
public static final int TAG_IMAGE_HISTORY = 0x9213;
public static final int TAG_SUBJECT_LOCATION = 0x9214;
/** There are two definitions for exposure index, I don't know the difference... */
public static final int TAG_EXPOSURE_INDEX_2 = 0x9215;
public static final int TAG_TIFF_EP_STANDARD_ID = 0x9216;
public static final int TAG_FLASH_ENERGY_2 = 0xA20B;
public static final int TAG_SPATIAL_FREQ_RESPONSE_2 = 0xA20C;
public static final int TAG_SUBJECT_LOCATION_2 = 0xA214;
public static final int TAG_MAKE = 0x010F;
public static final int TAG_MODEL = 0x0110;
public static final int TAG_ORIENTATION = 0x0112;
public static final int TAG_X_RESOLUTION = 0x011A;
public static final int TAG_Y_RESOLUTION = 0x011B;
public static final int TAG_PAGE_NAME = 0x011D;
public static final int TAG_RESOLUTION_UNIT = 0x0128;
public static final int TAG_THUMBNAIL_OFFSET = 0x0201;
public static final int TAG_THUMBNAIL_LENGTH = 0x0202;
public static final int TAG_YCBCR_POSITIONING = 0x0213;
/**
* Exposure time (reciprocal of shutter speed). Unit is second.
*/
public static final int TAG_EXPOSURE_TIME = 0x829A;
/**
* The actual F-number(F-stop) of lens when the image was taken.
*/
public static final int TAG_FNUMBER = 0x829D;
/**
* Exposure program that the camera used when image was taken. '1' means
* manual control, '2' program normal, '3' aperture priority, '4' shutter
* priority, '5' program creative (slow program), '6' program action
* (high-speed program), '7' portrait mode, '8' landscape mode.
*/
public static final int TAG_EXPOSURE_PROGRAM = 0x8822;
public static final int TAG_ISO_EQUIVALENT = 0x8827;
public static final int TAG_EXIF_VERSION = 0x9000;
public static final int TAG_DATETIME_ORIGINAL = 0x9003;
public static final int TAG_DATETIME_DIGITIZED = 0x9004;
public static final int TAG_COMPONENTS_CONFIGURATION = 0x9101;
/**
* Average (rough estimate) compression level in JPEG bits per pixel.
* */
public static final int TAG_COMPRESSION_LEVEL = 0x9102;
/**
* Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed';
* calculate this value's power of 2, then reciprocal. For example, if the
* ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second.
*/
public static final int TAG_SHUTTER_SPEED = 0x9201;
public static final int TAG_BRIGHTNESS_VALUE = 0x9203;
public static final int TAG_EXPOSURE_BIAS = 0x9204;
/**
* Maximum aperture value of lens. You can convert to F-number by calculating
* power of root 2 (same process of ApertureValue:0x9202).
* The actual aperture value of lens when the image was taken. To convert this
* value to ordinary f-number(f-stop), calculate the value's power of root 2
* (=1.4142). For example, if the ApertureValue is '5', f-number is 1.41425^5 = F5.6.
*/
public static final int TAG_MAX_APERTURE = 0x9205;
/**
* Indicates the distance the autofocus camera is focused to. Tends to be less accurate as distance increases.
*/
public static final int TAG_SUBJECT_DISTANCE = 0x9206;
/**
* Exposure metering method. '0' means unknown, '1' average, '2' center
* weighted average, '3' spot, '4' multi-spot, '5' multi-segment, '6' partial,
* '255' other.
*/
public static final int TAG_METERING_MODE = 0x9207;
 
public static final int TAG_LIGHT_SOURCE = 0x9208;
/**
* White balance (aka light source). '0' means unknown, '1' daylight,
* '2' fluorescent, '3' tungsten, '10' flash, '17' standard light A,
* '18' standard light B, '19' standard light C, '20' D55, '21' D65,
* '22' D75, '255' other.
*/
public static final int TAG_WHITE_BALANCE = 0x9208;
/**
* 0x0 = 0000000 = No Flash
* 0x1 = 0000001 = Fired
* 0x5 = 0000101 = Fired, Return not detected
* 0x7 = 0000111 = Fired, Return detected
* 0x9 = 0001001 = On
* 0xd = 0001101 = On, Return not detected
* 0xf = 0001111 = On, Return detected
* 0x10 = 0010000 = Off
* 0x18 = 0011000 = Auto, Did not fire
* 0x19 = 0011001 = Auto, Fired
* 0x1d = 0011101 = Auto, Fired, Return not detected
* 0x1f = 0011111 = Auto, Fired, Return detected
* 0x20 = 0100000 = No flash function
* 0x41 = 1000001 = Fired, Red-eye reduction
* 0x45 = 1000101 = Fired, Red-eye reduction, Return not detected
* 0x47 = 1000111 = Fired, Red-eye reduction, Return detected
* 0x49 = 1001001 = On, Red-eye reduction
* 0x4d = 1001101 = On, Red-eye reduction, Return not detected
* 0x4f = 1001111 = On, Red-eye reduction, Return detected
* 0x59 = 1011001 = Auto, Fired, Red-eye reduction
* 0x5d = 1011101 = Auto, Fired, Red-eye reduction, Return not detected
* 0x5f = 1011111 = Auto, Fired, Red-eye reduction, Return detected
* 6543210 (positions)
*
* This is a bitmask.
* 0 = flash fired
* 1 = return detected
* 2 = return able to be detected
* 3 = unknown
* 4 = auto used
* 5 = unknown
* 6 = red eye reduction used
*/
public static final int TAG_FLASH = 0x9209;
/**
* Focal length of lens used to take image. Unit is millimeter.
* Nice digital cameras actually save the focal length as a function of how far they are zoomed in.
*/
public static final int TAG_FOCAL_LENGTH = 0x920A;
public static final int TAG_USER_COMMENT = 0x9286;
public static final int TAG_SUBSECOND_TIME = 0x9290;
public static final int TAG_SUBSECOND_TIME_ORIGINAL = 0x9291;
public static final int TAG_SUBSECOND_TIME_DIGITIZED = 0x9292;
public static final int TAG_FLASHPIX_VERSION = 0xA000;
/**
* Defines Color Space. DCF image must use sRGB color space so value is
* always '1'. If the picture uses the other color space, value is
* '65535':Uncalibrated.
*/
public static final int TAG_COLOR_SPACE = 0xA001;
public static final int TAG_EXIF_IMAGE_WIDTH = 0xA002;
public static final int TAG_EXIF_IMAGE_HEIGHT = 0xA003;
public static final int TAG_RELATED_SOUND_FILE = 0xA004;
public static final int TAG_FOCAL_PLANE_X_RES = 0xA20E;
public static final int TAG_FOCAL_PLANE_Y_RES = 0xA20F;
/**
* Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit,
* '2' inch, '3' centimeter.
*
* Note: Some of Fujifilm's digicam(e.g.FX2700,FX2900,Finepix4700Z/40i etc)
* uses value '3' so it must be 'centimeter', but it seems that they use a
* '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has
* been changed to use value '2' but it doesn't match to actual value also.
*/
public static final int TAG_FOCAL_PLANE_UNIT = 0xA210;
public static final int TAG_EXPOSURE_INDEX = 0xA215;
public static final int TAG_SENSING_METHOD = 0xA217;
public static final int TAG_FILE_SOURCE = 0xA300;
public static final int TAG_SCENE_TYPE = 0xA301;
public static final int TAG_CFA_PATTERN = 0xA302;
 
// these tags new with Exif 2.2 (?) [A401 - A4
/**
* This tag indicates the use of special processing on image data, such as rendering
* geared to output. When special processing is performed, the reader is expected to
* disable or minimize any further processing.
* Tag = 41985 (A401.H)
* Type = SHORT
* Count = 1
* Default = 0
* 0 = Normal process
* 1 = Custom process
* Other = reserved
*/
public static final int TAG_CUSTOM_RENDERED = 0xA401;
 
/**
* This tag indicates the exposure mode set when the image was shot. In auto-bracketing
* mode, the camera shoots a series of frames of the same scene at different exposure settings.
* Tag = 41986 (A402.H)
* Type = SHORT
* Count = 1
* Default = none
* 0 = Auto exposure
* 1 = Manual exposure
* 2 = Auto bracket
* Other = reserved
*/
public static final int TAG_EXPOSURE_MODE = 0xA402;
 
/**
* This tag indicates the white balance mode set when the image was shot.
* Tag = 41987 (A403.H)
* Type = SHORT
* Count = 1
* Default = none
* 0 = Auto white balance
* 1 = Manual white balance
* Other = reserved
*/
public static final int TAG_WHITE_BALANCE_MODE = 0xA403;
 
/**
* This tag indicates the digital zoom ratio when the image was shot. If the
* numerator of the recorded value is 0, this indicates that digital zoom was
* not used.
* Tag = 41988 (A404.H)
* Type = RATIONAL
* Count = 1
* Default = none
*/
public static final int TAG_DIGITAL_ZOOM_RATIO = 0xA404;
 
/**
* This tag indicates the equivalent focal length assuming a 35mm film camera,
* in mm. A value of 0 means the focal length is unknown. Note that this tag
* differs from the FocalLength tag.
* Tag = 41989 (A405.H)
* Type = SHORT
* Count = 1
* Default = none
*/
public static final int TAG_35MM_FILM_EQUIV_FOCAL_LENGTH = 0xA405;
 
/**
* This tag indicates the type of scene that was shot. It can also be used to
* record the mode in which the image was shot. Note that this differs from
* the scene type (SceneType) tag.
* Tag = 41990 (A406.H)
* Type = SHORT
* Count = 1
* Default = 0
* 0 = Standard
* 1 = Landscape
* 2 = Portrait
* 3 = Night scene
* Other = reserved
*/
public static final int TAG_SCENE_CAPTURE_TYPE = 0xA406;
 
/**
* This tag indicates the degree of overall image gain adjustment.
* Tag = 41991 (A407.H)
* Type = SHORT
* Count = 1
* Default = none
* 0 = None
* 1 = Low gain up
* 2 = High gain up
* 3 = Low gain down
* 4 = High gain down
* Other = reserved
*/
public static final int TAG_GAIN_CONTROL = 0xA407;
 
/**
* This tag indicates the direction of contrast processing applied by the camera
* when the image was shot.
* Tag = 41992 (A408.H)
* Type = SHORT
* Count = 1
* Default = 0
* 0 = Normal
* 1 = Soft
* 2 = Hard
* Other = reserved
*/
public static final int TAG_CONTRAST = 0xA408;
 
/**
* This tag indicates the direction of saturation processing applied by the camera
* when the image was shot.
* Tag = 41993 (A409.H)
* Type = SHORT
* Count = 1
* Default = 0
* 0 = Normal
* 1 = Low saturation
* 2 = High saturation
* Other = reserved
*/
public static final int TAG_SATURATION = 0xA409;
 
/**
* This tag indicates the direction of sharpness processing applied by the camera
* when the image was shot.
* Tag = 41994 (A40A.H)
* Type = SHORT
* Count = 1
* Default = 0
* 0 = Normal
* 1 = Soft
* 2 = Hard
* Other = reserved
*/
public static final int TAG_SHARPNESS = 0xA40A;
 
// TODO support this tag (I haven't seen a camera's actual implementation of this yet)
 
/**
* This tag indicates information on the picture-taking conditions of a particular
* camera model. The tag is used only to indicate the picture-taking conditions in
* the reader.
* Tag = 41995 (A40B.H)
* Type = UNDEFINED
* Count = Any
* Default = none
*
* The information is recorded in the format shown below. The data is recorded
* in Unicode using SHORT type for the number of display rows and columns and
* UNDEFINED type for the camera settings. The Unicode (UCS-2) string including
* Signature is NULL terminated. The specifics of the Unicode string are as given
* in ISO/IEC 10464-1.
*
* Length Type Meaning
* ------+-----------+------------------
* 2 SHORT Display columns
* 2 SHORT Display rows
* Any UNDEFINED Camera setting-1
* Any UNDEFINED Camera setting-2
* : : :
* Any UNDEFINED Camera setting-n
*/
public static final int TAG_DEVICE_SETTING_DESCRIPTION = 0xA40B;
 
/**
* This tag indicates the distance to the subject.
* Tag = 41996 (A40C.H)
* Type = SHORT
* Count = 1
* Default = none
* 0 = unknown
* 1 = Macro
* 2 = Close view
* 3 = Distant view
* Other = reserved
*/
public static final int TAG_SUBJECT_DISTANCE_RANGE = 0xA40C;
 
/**
* The image title, as used by Windows XP.
*/
public static final int TAG_WIN_TITLE = 0x9C9B;
 
/**
* The image comment, as used by Windows XP.
*/
public static final int TAG_WIN_COMMENT = 0x9C9C;
 
/**
* The image author, as used by Windows XP (called Artist in the Windows shell).
*/
public static final int TAG_WIN_AUTHOR = 0x9C9D;
 
/**
* The image keywords, as used by Windows XP.
*/
public static final int TAG_WIN_KEYWORDS = 0x9C9E;
 
/**
* The image subject, as used by Windows XP.
*/
public static final int TAG_WIN_SUBJECT = 0x9C9F;
 
/**
* This tag indicates an identifier assigned uniquely to each image. It is
* recorded as an ASCII string equivalent to hexadecimal notation and 128-bit
* fixed length.
* Tag = 42016 (A420.H)
* Type = ASCII
* Count = 33
* Default = none
*/
public static final int TAG_IMAGE_UNIQUE_ID = 0xA420;
 
public static final int TAG_THUMBNAIL_IMAGE_WIDTH = 0x0100;
public static final int TAG_THUMBNAIL_IMAGE_HEIGHT = 0x0101;
public static final int TAG_THUMBNAIL_DATA = 0xF001;
 
/**
* 1 = Normal
* 2 = Reversed
*/
public static final int TAG_FILL_ORDER = 0x010A;
public static final int TAG_DOCUMENT_NAME = 0x010D;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_FILL_ORDER), "Fill Order");
tagNameMap.put(new Integer(TAG_DOCUMENT_NAME), "Document Name");
tagNameMap.put(new Integer(0x1000), "Related Image File Format");
tagNameMap.put(new Integer(0x1001), "Related Image Width");
tagNameMap.put(new Integer(0x1002), "Related Image Length");
tagNameMap.put(new Integer(0x0156), "Transfer Range");
tagNameMap.put(new Integer(0x0200), "JPEG Proc");
tagNameMap.put(new Integer(0x8769), "Exif Offset");
tagNameMap.put(new Integer(TAG_COMPRESSION_LEVEL), "Compressed Bits Per Pixel");
tagNameMap.put(new Integer(0x927C), "Maker Note");
tagNameMap.put(new Integer(0xA005), "Interoperability Offset");
 
tagNameMap.put(new Integer(TAG_NEW_SUBFILE_TYPE), "New Subfile Type");
tagNameMap.put(new Integer(TAG_SUBFILE_TYPE), "Subfile Type");
tagNameMap.put(new Integer(TAG_THUMBNAIL_IMAGE_WIDTH), "Thumbnail Image Width");
tagNameMap.put(new Integer(TAG_THUMBNAIL_IMAGE_HEIGHT), "Thumbnail Image Height");
tagNameMap.put(new Integer(TAG_BITS_PER_SAMPLE), "Bits Per Sample");
tagNameMap.put(new Integer(TAG_COMPRESSION), "Compression");
tagNameMap.put(new Integer(TAG_PHOTOMETRIC_INTERPRETATION), "Photometric Interpretation");
tagNameMap.put(new Integer(TAG_THRESHOLDING), "Thresholding");
tagNameMap.put(new Integer(TAG_IMAGE_DESCRIPTION), "Image Description");
tagNameMap.put(new Integer(TAG_MAKE), "Make");
tagNameMap.put(new Integer(TAG_MODEL), "Model");
tagNameMap.put(new Integer(TAG_STRIP_OFFSETS), "Strip Offsets");
tagNameMap.put(new Integer(TAG_ORIENTATION), "Orientation");
tagNameMap.put(new Integer(TAG_SAMPLES_PER_PIXEL), "Samples Per Pixel");
tagNameMap.put(new Integer(TAG_ROWS_PER_STRIP), "Rows Per Strip");
tagNameMap.put(new Integer(TAG_STRIP_BYTE_COUNTS), "Strip Byte Counts");
tagNameMap.put(new Integer(TAG_X_RESOLUTION), "X Resolution");
tagNameMap.put(new Integer(TAG_Y_RESOLUTION), "Y Resolution");
tagNameMap.put(new Integer(TAG_PAGE_NAME), "Page Name");
tagNameMap.put(new Integer(TAG_PLANAR_CONFIGURATION), "Planar Configuration");
tagNameMap.put(new Integer(TAG_RESOLUTION_UNIT), "Resolution Unit");
tagNameMap.put(new Integer(TAG_TRANSFER_FUNCTION), "Transfer Function");
tagNameMap.put(new Integer(TAG_SOFTWARE), "Software");
tagNameMap.put(new Integer(TAG_DATETIME), "Date/Time");
tagNameMap.put(new Integer(TAG_ARTIST), "Artist");
tagNameMap.put(new Integer(TAG_PREDICTOR), "Predictor");
tagNameMap.put(new Integer(TAG_WHITE_POINT), "White Point");
tagNameMap.put(new Integer(TAG_PRIMARY_CHROMATICITIES), "Primary Chromaticities");
tagNameMap.put(new Integer(TAG_TILE_WIDTH), "Tile Width");
tagNameMap.put(new Integer(TAG_TILE_LENGTH), "Tile Length");
tagNameMap.put(new Integer(TAG_TILE_OFFSETS), "Tile Offsets");
tagNameMap.put(new Integer(TAG_TILE_BYTE_COUNTS), "Tile Byte Counts");
tagNameMap.put(new Integer(TAG_SUB_IFDS), "Sub IFDs");
tagNameMap.put(new Integer(TAG_JPEG_TABLES), "JPEG Tables");
tagNameMap.put(new Integer(TAG_THUMBNAIL_OFFSET), "Thumbnail Offset");
tagNameMap.put(new Integer(TAG_THUMBNAIL_LENGTH), "Thumbnail Length");
tagNameMap.put(new Integer(TAG_THUMBNAIL_DATA), "Thumbnail Data");
tagNameMap.put(new Integer(TAG_YCBCR_COEFFICIENTS), "YCbCr Coefficients");
tagNameMap.put(new Integer(TAG_YCBCR_SUBSAMPLING), "YCbCr Sub-Sampling");
tagNameMap.put(new Integer(TAG_YCBCR_POSITIONING), "YCbCr Positioning");
tagNameMap.put(new Integer(TAG_REFERENCE_BLACK_WHITE), "Reference Black/White");
tagNameMap.put(new Integer(TAG_CFA_REPEAT_PATTERN_DIM), "CFA Repeat Pattern Dim");
tagNameMap.put(new Integer(TAG_CFA_PATTERN_2), "CFA Pattern");
tagNameMap.put(new Integer(TAG_BATTERY_LEVEL), "Battery Level");
tagNameMap.put(new Integer(TAG_COPYRIGHT), "Copyright");
tagNameMap.put(new Integer(TAG_EXPOSURE_TIME), "Exposure Time");
tagNameMap.put(new Integer(TAG_FNUMBER), "F-Number");
tagNameMap.put(new Integer(TAG_IPTC_NAA), "IPTC/NAA");
tagNameMap.put(new Integer(TAG_INTER_COLOR_PROFILE), "Inter Color Profile");
tagNameMap.put(new Integer(TAG_EXPOSURE_PROGRAM), "Exposure Program");
tagNameMap.put(new Integer(TAG_SPECTRAL_SENSITIVITY), "Spectral Sensitivity");
tagNameMap.put(new Integer(TAG_GPS_INFO), "GPS Info");
tagNameMap.put(new Integer(TAG_ISO_EQUIVALENT), "ISO Speed Ratings");
tagNameMap.put(new Integer(TAG_OECF), "OECF");
tagNameMap.put(new Integer(TAG_INTERLACE), "Interlace");
tagNameMap.put(new Integer(TAG_TIME_ZONE_OFFSET), "Time Zone Offset");
tagNameMap.put(new Integer(TAG_SELF_TIMER_MODE), "Self Timer Mode");
tagNameMap.put(new Integer(TAG_EXIF_VERSION), "Exif Version");
tagNameMap.put(new Integer(TAG_DATETIME_ORIGINAL), "Date/Time Original");
tagNameMap.put(new Integer(TAG_DATETIME_DIGITIZED), "Date/Time Digitized");
tagNameMap.put(new Integer(TAG_COMPONENTS_CONFIGURATION), "Components Configuration");
tagNameMap.put(new Integer(TAG_SHUTTER_SPEED), "Shutter Speed Value");
tagNameMap.put(new Integer(TAG_APERTURE), "Aperture Value");
tagNameMap.put(new Integer(TAG_BRIGHTNESS_VALUE), "Brightness Value");
tagNameMap.put(new Integer(TAG_EXPOSURE_BIAS), "Exposure Bias Value");
tagNameMap.put(new Integer(TAG_MAX_APERTURE), "Max Aperture Value");
tagNameMap.put(new Integer(TAG_SUBJECT_DISTANCE), "Subject Distance");
tagNameMap.put(new Integer(TAG_METERING_MODE), "Metering Mode");
tagNameMap.put(new Integer(TAG_WHITE_BALANCE), "Light Source");
tagNameMap.put(new Integer(TAG_FLASH), "Flash");
tagNameMap.put(new Integer(TAG_FOCAL_LENGTH), "Focal Length");
tagNameMap.put(new Integer(TAG_FLASH_ENERGY), "Flash Energy");
tagNameMap.put(new Integer(TAG_SPATIAL_FREQ_RESPONSE), "Spatial Frequency Response");
tagNameMap.put(new Integer(TAG_NOISE), "Noise");
tagNameMap.put(new Integer(TAG_IMAGE_NUMBER), "Image Number");
tagNameMap.put(new Integer(TAG_SECURITY_CLASSIFICATION), "Security Classification");
tagNameMap.put(new Integer(TAG_IMAGE_HISTORY), "Image History");
tagNameMap.put(new Integer(TAG_SUBJECT_LOCATION), "Subject Location");
tagNameMap.put(new Integer(TAG_EXPOSURE_INDEX), "Exposure Index");
tagNameMap.put(new Integer(TAG_TIFF_EP_STANDARD_ID), "TIFF/EP Standard ID");
tagNameMap.put(new Integer(TAG_USER_COMMENT), "User Comment");
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME), "Sub-Sec Time");
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME_ORIGINAL), "Sub-Sec Time Original");
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME_DIGITIZED), "Sub-Sec Time Digitized");
tagNameMap.put(new Integer(TAG_FLASHPIX_VERSION), "FlashPix Version");
tagNameMap.put(new Integer(TAG_COLOR_SPACE), "Color Space");
tagNameMap.put(new Integer(TAG_EXIF_IMAGE_WIDTH), "Exif Image Width");
tagNameMap.put(new Integer(TAG_EXIF_IMAGE_HEIGHT), "Exif Image Height");
tagNameMap.put(new Integer(TAG_RELATED_SOUND_FILE), "Related Sound File");
// 0x920B in TIFF/EP
tagNameMap.put(new Integer(TAG_FLASH_ENERGY_2), "Flash Energy");
// 0x920C in TIFF/EP
tagNameMap.put(new Integer(TAG_SPATIAL_FREQ_RESPONSE_2), "Spatial Frequency Response");
// 0x920E in TIFF/EP
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_X_RES), "Focal Plane X Resolution");
// 0x920F in TIFF/EP
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_Y_RES), "Focal Plane Y Resolution");
// 0x9210 in TIFF/EP
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_UNIT), "Focal Plane Resolution Unit");
// 0x9214 in TIFF/EP
tagNameMap.put(new Integer(TAG_SUBJECT_LOCATION_2), "Subject Location");
// 0x9215 in TIFF/EP
tagNameMap.put(new Integer(TAG_EXPOSURE_INDEX_2), "Exposure Index");
// 0x9217 in TIFF/EP
tagNameMap.put(new Integer(TAG_SENSING_METHOD), "Sensing Method");
tagNameMap.put(new Integer(TAG_FILE_SOURCE), "File Source");
tagNameMap.put(new Integer(TAG_SCENE_TYPE), "Scene Type");
tagNameMap.put(new Integer(TAG_CFA_PATTERN), "CFA Pattern");
 
tagNameMap.put(new Integer(TAG_CUSTOM_RENDERED), "Custom Rendered");
tagNameMap.put(new Integer(TAG_EXPOSURE_MODE), "Exposure Mode");
tagNameMap.put(new Integer(TAG_WHITE_BALANCE_MODE), "White Balance");
tagNameMap.put(new Integer(TAG_DIGITAL_ZOOM_RATIO), "Digital Zoom Ratio");
tagNameMap.put(new Integer(TAG_35MM_FILM_EQUIV_FOCAL_LENGTH), "Focal Length 35");
tagNameMap.put(new Integer(TAG_SCENE_CAPTURE_TYPE), "Scene Capture Type");
tagNameMap.put(new Integer(TAG_GAIN_CONTROL), "Gain Control");
tagNameMap.put(new Integer(TAG_CONTRAST), "Contrast");
tagNameMap.put(new Integer(TAG_SATURATION), "Saturation");
tagNameMap.put(new Integer(TAG_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_DEVICE_SETTING_DESCRIPTION), "Device Setting Description");
tagNameMap.put(new Integer(TAG_SUBJECT_DISTANCE_RANGE), "Subject Distance Range");
 
tagNameMap.put(new Integer(TAG_WIN_AUTHOR), "Windows XP Author");
tagNameMap.put(new Integer(TAG_WIN_COMMENT), "Windows XP Comment");
tagNameMap.put(new Integer(TAG_WIN_KEYWORDS), "Windows XP Keywords");
tagNameMap.put(new Integer(TAG_WIN_SUBJECT), "Windows XP Subject");
tagNameMap.put(new Integer(TAG_WIN_TITLE), "Windows XP Title");
 
tagNameMap.put(new Integer(TAG_MIN_SAMPLE_VALUE), "Minimum sample value");
tagNameMap.put(new Integer(TAG_MAX_SAMPLE_VALUE), "Maximum sample value");
}
 
public ExifDirectory()
{
this.setDescriptor(new ExifDescriptor(this));
}
 
public String getName()
{
return "Exif";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
 
public byte[] getThumbnailData() throws MetadataException
{
if (!containsThumbnail())
return null;
return this.getByteArray(ExifDirectory.TAG_THUMBNAIL_DATA);
}
 
public void writeThumbnail(String filename) throws MetadataException, IOException
{
byte[] data = getThumbnailData();
 
if (data==null)
throw new MetadataException("No thumbnail data exists.");
 
FileOutputStream stream = null;
try {
stream = new FileOutputStream(filename);
stream.write(data);
} finally {
if (stream!=null)
stream.close();
}
}
 
/*
// This thumbnail extraction code is not complete, and is included to assist anyone who feels like looking into
// it. Please share any progress with the original author, and hence the community. Thanks.
 
/**
*
* @return
* @throws MetadataException
* /
public Image getThumbnailImage() throws MetadataException
{
if (!containsThumbnail())
return null;
 
int compression = 0;
try {
compression = this.getInt(ExifDirectory.TAG_COMPRESSION);
} catch (Throwable e) {
this.addError("Unable to determine thumbnail type " + e.getMessage());
}
 
final byte[] thumbnailBytes = getThumbnailData();
 
if (compression == ExifDirectory.COMPRESSION_JPEG)
{
// JPEG Thumbnail
// operate directly on thumbnailBytes
// try {
// int offset = this.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET);
// int length = this.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH);
// byte[] result = new byte[length];
// for (int i = 0; i<result.length; i++) {
// result[i] = _data[tiffHeaderOffset + offset + i];
// }
// this.setByteArray(ExifDirectory.TAG_THUMBNAIL_DATA, result);
// } catch (Throwable e) {
// this.addError("Unable to extract thumbnail: " + e.getMessage());
// }
// TODO decode the JPEG bytes as an image
return null; //new Image();
}
else if (compression == ExifDirectory.COMPRESSION_NONE)
{
// uncompressed thumbnail (raw RGB data)
if (!this.containsTag(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION))
return null;
 
try
{
// If the image is RGB format, then convert it to a bitmap
final int photometricInterpretation = this.getInt(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION);
if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_RGB)
{
// RGB
Image image = createImageFromRawRgb(thumbnailBytes);
return image;
}
else if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_YCBCR)
{
// YCbCr
Image image = createImageFromRawYCbCr(thumbnailBytes);
return image;
}
else if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_MONOCHROME)
{
// Monochrome
// TODO
return null;
}
} catch (Throwable e) {
this.addError("Unable to extract thumbnail: " + e.getMessage());
}
}
return null;
}
 
/**
* Handle the YCbCr thumbnail encoding used by Ricoh RDC4200/4300, Fuji DS-7/300 and DX-5/7/9 cameras.
*
* At DX-5/7/9, YCbCrSubsampling(0x0212) has values of '2,1', PlanarConfiguration(0x011c) has a value '1'. So the
* data align of this image is below.
*
* Y(0,0),Y(1,0),Cb(0,0),Cr(0,0), Y(2,0),Y(3,0),Cb(2,0),Cr(3.0), Y(4,0),Y(5,0),Cb(4,0),Cr(4,0). . . .
*
* The numerics in parenthesis are pixel coordinates. DX series' YCbCrCoefficients(0x0211) has values '0.299/0.587/0.114',
* ReferenceBlackWhite(0x0214) has values '0,255,128,255,128,255'. Therefore to convert from Y/Cb/Cr to RGB is;
*
* B(0,0)=(Cb-128)*(2-0.114*2)+Y(0,0)
* R(0,0)=(Cr-128)*(2-0.299*2)+Y(0,0)
* G(0,0)=(Y(0,0)-0.114*B(0,0)-0.299*R(0,0))/0.587
*
* Horizontal subsampling is a value '2', so you can calculate B(1,0)/R(1,0)/G(1,0) by using the Y(1,0) and Cr(0,0)/Cb(0,0).
* Repeat this conversion by value of ImageWidth(0x0100) and ImageLength(0x0101).
*
* @param thumbnailBytes
* @return
* @throws com.drew.metadata.MetadataException
* /
private Image createImageFromRawYCbCr(byte[] thumbnailBytes) throws MetadataException
{
/*
Y = 0.257R + 0.504G + 0.098B + 16
Cb = -0.148R - 0.291G + 0.439B + 128
Cr = 0.439R - 0.368G - 0.071B + 128
 
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128)
R = 1.164(Y-16) + 1.596(Cr-128)
B = 1.164(Y-16) + 2.018(Cb-128)
 
R, G and B range from 0 to 255.
Y ranges from 16 to 235.
Cb and Cr range from 16 to 240.
 
http://www.faqs.org/faqs/graphics/colorspace-faq/
* /
 
int length = thumbnailBytes.length; // this.getInt(ExifDirectory.TAG_STRIP_BYTE_COUNTS);
final int imageWidth = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH);
final int imageHeight = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT);
// final int headerLength = 54;
// byte[] result = new byte[length + headerLength];
// // Add a windows BMP header described:
// // http://www.onicos.com/staff/iz/formats/bmp.html
// result[0] = 'B';
// result[1] = 'M'; // File Type identifier
// result[3] = (byte)(result.length / 256);
// result[2] = (byte)result.length;
// result[10] = (byte)headerLength;
// result[14] = 40; // MS Windows BMP header
// result[18] = (byte)imageWidth;
// result[22] = (byte)imageHeight;
// result[26] = 1; // 1 Plane
// result[28] = 24; // Colour depth
// result[34] = (byte)length;
// result[35] = (byte)(length / 256);
 
final BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
 
// order is YCbCr and image is upside down, bitmaps are BGR
//// for (int i = headerLength, dataOffset = length; i<result.length; i += 3, dataOffset -= 3)
// {
// final int y = thumbnailBytes[dataOffset - 2] & 0xFF;
// final int cb = thumbnailBytes[dataOffset - 1] & 0xFF;
// final int cr = thumbnailBytes[dataOffset] & 0xFF;
// if (y<16 || y>235 || cb<16 || cb>240 || cr<16 || cr>240)
// "".toString();
//
// int g = (int)(1.164*(y-16) - 0.391*(cb-128) - 0.813*(cr-128));
// int r = (int)(1.164*(y-16) + 1.596*(cr-128));
// int b = (int)(1.164*(y-16) + 2.018*(cb-128));
//
//// result[i] = (byte)b;
//// result[i + 1] = (byte)g;
//// result[i + 2] = (byte)r;
//
// // TODO compose the image here
// image.setRGB(1, 2, 3);
// }
 
return image;
}
 
/**
* Creates a thumbnail image in (Windows) BMP format from raw RGB data.
* @param thumbnailBytes
* @return
* @throws com.drew.metadata.MetadataException
* /
private Image createImageFromRawRgb(byte[] thumbnailBytes) throws MetadataException
{
final int length = thumbnailBytes.length; // this.getInt(ExifDirectory.TAG_STRIP_BYTE_COUNTS);
final int imageWidth = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH);
final int imageHeight = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT);
// final int headerlength = 54;
// final byte[] result = new byte[length + headerlength];
// // Add a windows BMP header described:
// // http://www.onicos.com/staff/iz/formats/bmp.html
// result[0] = 'B';
// result[1] = 'M'; // File Type identifier
// result[3] = (byte)(result.length / 256);
// result[2] = (byte)result.length;
// result[10] = (byte)headerlength;
// result[14] = 40; // MS Windows BMP header
// result[18] = (byte)imageWidth;
// result[22] = (byte)imageHeight;
// result[26] = 1; // 1 Plane
// result[28] = 24; // Colour depth
// result[34] = (byte)length;
// result[35] = (byte)(length / 256);
 
final BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB);
 
// order is RGB and image is upside down, bitmaps are BGR
// for (int i = headerlength, dataOffset = length; i<result.length; i += 3, dataOffset -= 3)
// {
// byte b = thumbnailBytes[dataOffset - 2];
// byte g = thumbnailBytes[dataOffset - 1];
// byte r = thumbnailBytes[dataOffset];
//
// // TODO compose the image here
// image.setRGB(1, 2, 3);
// }
 
return image;
}
*/
 
public boolean containsThumbnail()
{
return containsTag(ExifDirectory.TAG_THUMBNAIL_DATA);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifInteropDirectory.java
0,0 → 1,60
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Nov-2002 10:58:13 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class ExifInteropDirectory extends Directory
{
public static final int TAG_INTEROP_INDEX = 0x0001;
public static final int TAG_INTEROP_VERSION = 0x0002;
public static final int TAG_RELATED_IMAGE_FILE_FORMAT = 0x1000;
public static final int TAG_RELATED_IMAGE_WIDTH = 0x1001;
public static final int TAG_RELATED_IMAGE_LENGTH = 0x1002;
 
protected static final HashMap tagNameMap;
 
static
{
tagNameMap = new HashMap();
tagNameMap.put(new Integer(TAG_INTEROP_INDEX), "Interoperability Index");
tagNameMap.put(new Integer(TAG_INTEROP_VERSION), "Interoperability Version");
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_FILE_FORMAT), "Related Image File Format");
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_WIDTH), "Related Image Width");
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_LENGTH), "Related Image Length");
}
 
public ExifInteropDirectory()
{
this.setDescriptor(new ExifInteropDescriptor(this));
}
 
public String getName()
{
return "Interoperability";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KodakMakernoteDirectory.java
0,0 → 1,37
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* Describes tags specific to Kodak cameras.
*/
public class KodakMakernoteDirectory extends Directory
{
protected static final HashMap _tagNameMap = new HashMap();
public String getName()
{
return "Kodak Makernote";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/GpsDescriptor.java
0,0 → 1,201
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 22:27:52 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class GpsDescriptor extends TagDescriptor
{
public GpsDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case GpsDirectory.TAG_GPS_ALTITUDE:
return getGpsAltitudeDescription();
case GpsDirectory.TAG_GPS_ALTITUDE_REF:
return getGpsAltitudeRefDescription();
case GpsDirectory.TAG_GPS_STATUS:
return getGpsStatusDescription();
case GpsDirectory.TAG_GPS_MEASURE_MODE:
return getGpsMeasureModeDescription();
case GpsDirectory.TAG_GPS_SPEED_REF:
return getGpsSpeedRefDescription();
case GpsDirectory.TAG_GPS_TRACK_REF:
case GpsDirectory.TAG_GPS_IMG_DIRECTION_REF:
case GpsDirectory.TAG_GPS_DEST_BEARING_REF:
return getGpsDirectionReferenceDescription(tagType);
case GpsDirectory.TAG_GPS_TRACK:
case GpsDirectory.TAG_GPS_IMG_DIRECTION:
case GpsDirectory.TAG_GPS_DEST_BEARING:
return getGpsDirectionDescription(tagType);
case GpsDirectory.TAG_GPS_DEST_DISTANCE_REF:
return getGpsDestinationReferenceDescription();
case GpsDirectory.TAG_GPS_TIME_STAMP:
return getGpsTimeStampDescription();
// three rational numbers -- displayed in HH"MM"SS.ss
case GpsDirectory.TAG_GPS_LONGITUDE:
return getGpsLongitudeDescription();
case GpsDirectory.TAG_GPS_LATITUDE:
return getGpsLatitudeDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getGpsLatitudeDescription() throws MetadataException
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_LATITUDE)) return null;
return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LATITUDE);
}
 
public String getGpsLongitudeDescription() throws MetadataException
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)) return null;
return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LONGITUDE);
}
 
public String getHoursMinutesSecondsDescription(int tagType) throws MetadataException
{
Rational[] components = _directory.getRationalArray(tagType);
// TODO create an HoursMinutesSecods class ??
int deg = components[0].intValue();
float min = components[1].floatValue();
float sec = components[2].floatValue();
// carry fractions of minutes into seconds -- thanks Colin Briton
sec += (min % 1) * 60;
return String.valueOf(deg) + "\"" + String.valueOf((int)min) + "'" + String.valueOf(sec);
}
 
public String getGpsTimeStampDescription() throws MetadataException
{
// time in hour, min, sec
if (!_directory.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP)) return null;
int[] timeComponents = _directory.getIntArray(GpsDirectory.TAG_GPS_TIME_STAMP);
StringBuffer sbuffer = new StringBuffer();
sbuffer.append(timeComponents[0]);
sbuffer.append(":");
sbuffer.append(timeComponents[1]);
sbuffer.append(":");
sbuffer.append(timeComponents[2]);
sbuffer.append(" UTC");
return sbuffer.toString();
}
 
public String getGpsDestinationReferenceDescription()
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF)) return null;
String destRef = _directory.getString(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF).trim();
if ("K".equalsIgnoreCase(destRef)) {
return "kilometers";
} else if ("M".equalsIgnoreCase(destRef)) {
return "miles";
} else if ("N".equalsIgnoreCase(destRef)) {
return "knots";
} else {
return "Unknown (" + destRef + ")";
}
}
 
public String getGpsDirectionDescription(int tagType)
{
if (!_directory.containsTag(tagType)) return null;
String gpsDirection = _directory.getString(tagType).trim();
return gpsDirection + " degrees";
}
 
public String getGpsDirectionReferenceDescription(int tagType)
{
if (!_directory.containsTag(tagType)) return null;
String gpsDistRef = _directory.getString(tagType).trim();
if ("T".equalsIgnoreCase(gpsDistRef)) {
return "True direction";
} else if ("M".equalsIgnoreCase(gpsDistRef)) {
return "Magnetic direction";
} else {
return "Unknown (" + gpsDistRef + ")";
}
}
 
public String getGpsSpeedRefDescription()
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_SPEED_REF)) return null;
String gpsSpeedRef = _directory.getString(GpsDirectory.TAG_GPS_SPEED_REF).trim();
if ("K".equalsIgnoreCase(gpsSpeedRef)) {
return "kph";
} else if ("M".equalsIgnoreCase(gpsSpeedRef)) {
return "mph";
} else if ("N".equalsIgnoreCase(gpsSpeedRef)) {
return "knots";
} else {
return "Unknown (" + gpsSpeedRef + ")";
}
}
 
public String getGpsMeasureModeDescription()
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_MEASURE_MODE)) return null;
String gpsSpeedMeasureMode = _directory.getString(GpsDirectory.TAG_GPS_MEASURE_MODE).trim();
if ("2".equalsIgnoreCase(gpsSpeedMeasureMode)) {
return "2-dimensional measurement";
} else if ("3".equalsIgnoreCase(gpsSpeedMeasureMode)) {
return "3-dimensional measurement";
} else {
return "Unknown (" + gpsSpeedMeasureMode + ")";
}
}
 
public String getGpsStatusDescription()
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_STATUS)) return null;
String gpsStatus = _directory.getString(GpsDirectory.TAG_GPS_STATUS).trim();
if ("A".equalsIgnoreCase(gpsStatus)) {
return "Measurement in progess";
} else if ("V".equalsIgnoreCase(gpsStatus)) {
return "Measurement Interoperability";
} else {
return "Unknown (" + gpsStatus + ")";
}
}
 
public String getGpsAltitudeRefDescription() throws MetadataException
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF)) return null;
int alititudeRef = _directory.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
if (alititudeRef == 0) {
return "Sea level";
} else {
return "Unknown (" + alititudeRef + ")";
}
}
 
public String getGpsAltitudeDescription() throws MetadataException
{
if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE)) return null;
String alititude = _directory.getRational(GpsDirectory.TAG_GPS_ALTITUDE).toSimpleString(true);
return alititude + " metres";
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PentaxMakernoteDirectory.java
0,0 → 1,158
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* Directory for metadata specific to Pentax and Asahi cameras.
*/
public class PentaxMakernoteDirectory extends Directory
{
/**
* 0 = Auto
* 1 = Night-scene
* 2 = Manual
* 4 = Multiple
*/
public static final int TAG_PENTAX_CAPTURE_MODE = 0x0001;
 
/**
* 0 = Good
* 1 = Better
* 2 = Best
*/
public static final int TAG_PENTAX_QUALITY_LEVEL = 0x0002;
 
/**
* 2 = Custom
* 3 = Auto
*/
public static final int TAG_PENTAX_FOCUS_MODE = 0x0003;
 
/**
* 1 = Auto
* 2 = Flash on
* 4 = Flash off
* 6 = Red-eye Reduction
*/
public static final int TAG_PENTAX_FLASH_MODE = 0x0004;
 
/**
* 0 = Auto
* 1 = Daylight
* 2 = Shade
* 3 = Tungsten
* 4 = Fluorescent
* 5 = Manual
*/
public static final int TAG_PENTAX_WHITE_BALANCE = 0x0007;
 
/**
* (0 = Off)
*/
public static final int TAG_PENTAX_DIGITAL_ZOOM = 0x000A;
 
/**
* 0 = Normal
* 1 = Soft
* 2 = Hard
*/
public static final int TAG_PENTAX_SHARPNESS = 0x000B;
 
/**
* 0 = Normal
* 1 = Low
* 2 = High
*/
public static final int TAG_PENTAX_CONTRAST = 0x000C;
 
/**
* 0 = Normal
* 1 = Low
* 2 = High
*/
public static final int TAG_PENTAX_SATURATION = 0x000D;
 
/**
* 10 = ISO 100
* 16 = ISO 200
* 100 = ISO 100
* 200 = ISO 200
*/
public static final int TAG_PENTAX_ISO_SPEED = 0x0014;
 
/**
* 1 = Normal
* 2 = Black & White
* 3 = Sepia
*/
public static final int TAG_PENTAX_COLOUR = 0x0017;
 
/**
* See Print Image Matching for specification.
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html
*/
public static final int TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO = 0x0E00;
 
/**
* (String).
*/
public static final int TAG_PENTAX_TIME_ZONE = 0x1000;
 
/**
* (String).
*/
public static final int TAG_PENTAX_DAYLIGHT_SAVINGS = 0x1001;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_PENTAX_CAPTURE_MODE), "Capture Mode");
tagNameMap.put(new Integer(TAG_PENTAX_QUALITY_LEVEL), "Quality Level");
tagNameMap.put(new Integer(TAG_PENTAX_FOCUS_MODE), "Focus Mode");
tagNameMap.put(new Integer(TAG_PENTAX_FLASH_MODE), "Flash Mode");
tagNameMap.put(new Integer(TAG_PENTAX_WHITE_BALANCE), "White Balance");
tagNameMap.put(new Integer(TAG_PENTAX_DIGITAL_ZOOM), "Digital Zoom");
tagNameMap.put(new Integer(TAG_PENTAX_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_PENTAX_CONTRAST), "Contrast");
tagNameMap.put(new Integer(TAG_PENTAX_SATURATION), "Saturation");
tagNameMap.put(new Integer(TAG_PENTAX_ISO_SPEED), "ISO Speed");
tagNameMap.put(new Integer(TAG_PENTAX_COLOUR), "Colour");
tagNameMap.put(new Integer(TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
tagNameMap.put(new Integer(TAG_PENTAX_TIME_ZONE), "Time Zone");
tagNameMap.put(new Integer(TAG_PENTAX_DAYLIGHT_SAVINGS), "Daylight Savings");
}
 
public PentaxMakernoteDirectory()
{
this.setDescriptor(new PentaxMakernoteDescriptor(this));
}
 
public String getName()
{
return "Pentax Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifDescriptor.java
0,0 → 1,1121
/*
* ExifDescriptor.java
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 22:27:15 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.imaging.PhotographicConversions;
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
 
/**
* Contains all logic for the presentation of raw Exif data, as stored in ExifDirectory. Use
* this class to provide human-readable descriptions of tag values.
*/
public class ExifDescriptor extends TagDescriptor
{
/**
* Dictates whether rational values will be represented in decimal format in instances
* where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3).
*/
private boolean _allowDecimalRepresentationOfRationals = true;
 
private static final java.text.DecimalFormat SimpleDecimalFormatter = new DecimalFormat("0.#");
 
public ExifDescriptor(Directory directory)
{
super(directory);
}
 
// Note for the potential addition of brightness presentation in eV:
// Brightness of taken subject. To calculate Exposure(Ev) from BrigtnessValue(Bv),
// you must add SensitivityValue(Sv).
// Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125)
// ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
 
/**
* Returns a descriptive value of the the specified tag for this image.
* Where possible, known values will be substituted here in place of the raw
* tokens actually kept in the Exif segment. If no substitution is
* available, the value provided by getString(int) will be returned.
* @param tagType the tag to find a description for
* @return a description of the image's value for the specified tag, or
* <code>null</code> if the tag hasn't been defined.
*/
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case ExifDirectory.TAG_ORIENTATION:
return getOrientationDescription();
case ExifDirectory.TAG_NEW_SUBFILE_TYPE:
return getNewSubfileTypeDescription();
case ExifDirectory.TAG_SUBFILE_TYPE:
return getSubfileTypeDescription();
case ExifDirectory.TAG_THRESHOLDING:
return getThresholdingDescription();
case ExifDirectory.TAG_FILL_ORDER:
return getFillOrderDescription();
case ExifDirectory.TAG_RESOLUTION_UNIT:
return getResolutionDescription();
case ExifDirectory.TAG_YCBCR_POSITIONING:
return getYCbCrPositioningDescription();
case ExifDirectory.TAG_EXPOSURE_TIME:
return getExposureTimeDescription();
case ExifDirectory.TAG_SHUTTER_SPEED:
return getShutterSpeedDescription();
case ExifDirectory.TAG_FNUMBER:
return getFNumberDescription();
case ExifDirectory.TAG_X_RESOLUTION:
return getXResolutionDescription();
case ExifDirectory.TAG_Y_RESOLUTION:
return getYResolutionDescription();
case ExifDirectory.TAG_THUMBNAIL_OFFSET:
return getThumbnailOffsetDescription();
case ExifDirectory.TAG_THUMBNAIL_LENGTH:
return getThumbnailLengthDescription();
case ExifDirectory.TAG_COMPRESSION_LEVEL:
return getCompressionLevelDescription();
case ExifDirectory.TAG_SUBJECT_DISTANCE:
return getSubjectDistanceDescription();
case ExifDirectory.TAG_METERING_MODE:
return getMeteringModeDescription();
case ExifDirectory.TAG_WHITE_BALANCE:
return getWhiteBalanceDescription();
case ExifDirectory.TAG_FLASH:
return getFlashDescription();
case ExifDirectory.TAG_FOCAL_LENGTH:
return getFocalLengthDescription();
case ExifDirectory.TAG_COLOR_SPACE:
return getColorSpaceDescription();
case ExifDirectory.TAG_EXIF_IMAGE_WIDTH:
return getExifImageWidthDescription();
case ExifDirectory.TAG_EXIF_IMAGE_HEIGHT:
return getExifImageHeightDescription();
case ExifDirectory.TAG_FOCAL_PLANE_UNIT:
return getFocalPlaneResolutionUnitDescription();
case ExifDirectory.TAG_FOCAL_PLANE_X_RES:
return getFocalPlaneXResolutionDescription();
case ExifDirectory.TAG_FOCAL_PLANE_Y_RES:
return getFocalPlaneYResolutionDescription();
case ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH:
return getThumbnailImageWidthDescription();
case ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT:
return getThumbnailImageHeightDescription();
case ExifDirectory.TAG_BITS_PER_SAMPLE:
return getBitsPerSampleDescription();
case ExifDirectory.TAG_COMPRESSION:
return getCompressionDescription();
case ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION:
return getPhotometricInterpretationDescription();
case ExifDirectory.TAG_ROWS_PER_STRIP:
return getRowsPerStripDescription();
case ExifDirectory.TAG_STRIP_BYTE_COUNTS:
return getStripByteCountsDescription();
case ExifDirectory.TAG_SAMPLES_PER_PIXEL:
return getSamplesPerPixelDescription();
case ExifDirectory.TAG_PLANAR_CONFIGURATION:
return getPlanarConfigurationDescription();
case ExifDirectory.TAG_YCBCR_SUBSAMPLING:
return getYCbCrSubsamplingDescription();
case ExifDirectory.TAG_EXPOSURE_PROGRAM:
return getExposureProgramDescription();
case ExifDirectory.TAG_APERTURE:
return getApertureValueDescription();
case ExifDirectory.TAG_MAX_APERTURE:
return getMaxApertureValueDescription();
case ExifDirectory.TAG_SENSING_METHOD:
return getSensingMethodDescription();
case ExifDirectory.TAG_EXPOSURE_BIAS:
return getExposureBiasDescription();
case ExifDirectory.TAG_FILE_SOURCE:
return getFileSourceDescription();
case ExifDirectory.TAG_SCENE_TYPE:
return getSceneTypeDescription();
case ExifDirectory.TAG_COMPONENTS_CONFIGURATION:
return getComponentConfigurationDescription();
case ExifDirectory.TAG_EXIF_VERSION:
return getExifVersionDescription();
case ExifDirectory.TAG_FLASHPIX_VERSION:
return getFlashPixVersionDescription();
case ExifDirectory.TAG_REFERENCE_BLACK_WHITE:
return getReferenceBlackWhiteDescription();
case ExifDirectory.TAG_ISO_EQUIVALENT:
return getIsoEquivalentDescription();
case ExifDirectory.TAG_THUMBNAIL_DATA:
return getThumbnailDescription();
case ExifDirectory.TAG_USER_COMMENT:
return getUserCommentDescription();
case ExifDirectory.TAG_CUSTOM_RENDERED:
return getCustomRenderedDescription();
case ExifDirectory.TAG_EXPOSURE_MODE:
return getExposureModeDescription();
case ExifDirectory.TAG_WHITE_BALANCE_MODE:
return getWhiteBalanceModeDescription();
case ExifDirectory.TAG_DIGITAL_ZOOM_RATIO:
return getDigitalZoomRatioDescription();
case ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH:
return get35mmFilmEquivFocalLengthDescription();
case ExifDirectory.TAG_SCENE_CAPTURE_TYPE:
return getSceneCaptureTypeDescription();
case ExifDirectory.TAG_GAIN_CONTROL:
return getGainControlDescription();
case ExifDirectory.TAG_CONTRAST:
return getContrastDescription();
case ExifDirectory.TAG_SATURATION:
return getSaturationDescription();
case ExifDirectory.TAG_SHARPNESS:
return getSharpnessDescription();
case ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE:
return getSubjectDistanceRangeDescription();
 
case ExifDirectory.TAG_WIN_AUTHOR:
return getWindowsAuthorDescription();
case ExifDirectory.TAG_WIN_COMMENT:
return getWindowsCommentDescription();
case ExifDirectory.TAG_WIN_KEYWORDS:
return getWindowsKeywordsDescription();
case ExifDirectory.TAG_WIN_SUBJECT:
return getWindowsSubjectDescription();
case ExifDirectory.TAG_WIN_TITLE:
return getWindowsTitleDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getNewSubfileTypeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_NEW_SUBFILE_TYPE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_NEW_SUBFILE_TYPE)) {
case 1: return "Full-resolution image";
case 2: return "Reduced-resolution image";
case 3: return "Single page of multi-page reduced-resolution image";
case 4: return "Transparency mask";
case 5: return "Transparency mask of reduced-resolution image";
case 6: return "Transparency mask of multi-page image";
case 7: return "Transparency mask of reduced-resolution multi-page image";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_NEW_SUBFILE_TYPE) + ")";
}
}
 
public String getSubfileTypeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SUBFILE_TYPE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_SUBFILE_TYPE)) {
case 1: return "Full-resolution image";
case 2: return "Reduced-resolution image";
case 3: return "Single page of multi-page image";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SUBFILE_TYPE) + ")";
}
}
 
public String getThresholdingDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_THRESHOLDING)) return null;
switch (_directory.getInt(ExifDirectory.TAG_THRESHOLDING)) {
case 1: return "No dithering or halftoning";
case 2: return "Ordered dither or halftone";
case 3: return "Randomized dither";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_THRESHOLDING) + ")";
}
}
 
public String getFillOrderDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FILL_ORDER)) return null;
switch (_directory.getInt(ExifDirectory.TAG_FILL_ORDER)) {
case 1: return "Normal";
case 2: return "Reversed";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_FILL_ORDER) + ")";
}
}
 
public String getSubjectDistanceRangeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE)) {
case 0:
return "Unknown";
case 1:
return "Macro";
case 2:
return "Close view";
case 3:
return "Distant view";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE) + ")";
}
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SHARPNESS)) return null;
switch (_directory.getInt(ExifDirectory.TAG_SHARPNESS)) {
case 0:
return "None";
case 1:
return "Low";
case 2:
return "Hard";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SHARPNESS) + ")";
}
}
 
public String getSaturationDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SATURATION)) return null;
switch (_directory.getInt(ExifDirectory.TAG_SATURATION)) {
case 0:
return "None";
case 1:
return "Low saturation";
case 2:
return "High saturation";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SATURATION) + ")";
}
}
 
public String getContrastDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_CONTRAST)) return null;
switch (_directory.getInt(ExifDirectory.TAG_CONTRAST)) {
case 0:
return "None";
case 1:
return "Soft";
case 2:
return "Hard";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_CONTRAST) + ")";
}
}
 
public String getGainControlDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_GAIN_CONTROL)) return null;
switch (_directory.getInt(ExifDirectory.TAG_GAIN_CONTROL)) {
case 0:
return "None";
case 1:
return "Low gain up";
case 2:
return "Low gain down";
case 3:
return "High gain up";
case 4:
return "High gain down";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_GAIN_CONTROL) + ")";
}
}
 
public String getSceneCaptureTypeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SCENE_CAPTURE_TYPE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_SCENE_CAPTURE_TYPE)) {
case 0:
return "Standard";
case 1:
return "Landscape";
case 2:
return "Portrait";
case 3:
return "Night scene";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SCENE_CAPTURE_TYPE) + ")";
}
}
 
public String get35mmFilmEquivFocalLengthDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH)) return null;
int equivalentFocalLength = _directory.getInt(ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH);
 
if (equivalentFocalLength==0)
return "Unknown";
else
return SimpleDecimalFormatter.format(equivalentFocalLength) + "mm";
}
 
public String getDigitalZoomRatioDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_DIGITAL_ZOOM_RATIO)) return null;
Rational rational = _directory.getRational(ExifDirectory.TAG_DIGITAL_ZOOM_RATIO);
if (rational.getNumerator()==0)
return "Digital zoom not used.";
 
return SimpleDecimalFormatter.format(rational.doubleValue());
}
 
public String getWhiteBalanceModeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_WHITE_BALANCE_MODE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_WHITE_BALANCE_MODE)) {
case 0:
return "Auto white balance";
case 1:
return "Manual white balance";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_WHITE_BALANCE_MODE) + ")";
}
}
 
public String getExposureModeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_MODE)) return null;
switch (_directory.getInt(ExifDirectory.TAG_EXPOSURE_MODE)) {
case 0:
return "Auto exposure";
case 1:
return "Manual exposure";
case 2:
return "Auto bracket";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_EXPOSURE_MODE) + ")";
}
}
 
public String getCustomRenderedDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_CUSTOM_RENDERED)) return null;
switch (_directory.getInt(ExifDirectory.TAG_CUSTOM_RENDERED)) {
case 0:
return "Normal process";
case 1:
return "Custom process";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_CUSTOM_RENDERED) + ")";
}
}
 
public String getUserCommentDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_USER_COMMENT)) return null;
 
byte[] commentBytes = _directory.getByteArray(ExifDirectory.TAG_USER_COMMENT);
 
if (commentBytes.length==0)
return "";
 
final String[] encodingNames = new String[] { "ASCII", "UNICODE", "JIS" };
 
if (commentBytes.length>=10)
{
String encodingRegion = new String(commentBytes, 0, 10);
 
// try each encoding name
for (int i = 0; i<encodingNames.length; i++) {
String encodingName = encodingNames[i];
if (encodingRegion.startsWith(encodingName))
{
// remove the null characters (and any spaces) commonly present after the encoding name
for (int j = encodingName.length(); j<10; j++) {
byte b = commentBytes[j];
if (b!='\0' && b!=' ') {
if (encodingName.equals("UNICODE")) {
try {
return new String(commentBytes, j, commentBytes.length - j, "UTF-16LE").trim();
}
catch (UnsupportedEncodingException ex) {
return null;
}
}
return new String(commentBytes, j, commentBytes.length - j).trim();
}
}
return new String(commentBytes, 10, commentBytes.length - 10).trim();
}
}
}
 
// special handling fell through, return a plain string representation
return new String(commentBytes).trim();
}
 
public String getThumbnailDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA)) return null;
int[] thumbnailBytes = _directory.getIntArray(ExifDirectory.TAG_THUMBNAIL_DATA);
return "[" + thumbnailBytes.length + " bytes of thumbnail data]";
}
 
public String getIsoEquivalentDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_ISO_EQUIVALENT)) return null;
int isoEquiv = _directory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT);
if (isoEquiv < 50) {
isoEquiv *= 200;
}
return Integer.toString(isoEquiv);
}
 
public String getReferenceBlackWhiteDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_REFERENCE_BLACK_WHITE)) return null;
int[] ints = _directory.getIntArray(ExifDirectory.TAG_REFERENCE_BLACK_WHITE);
int blackR = ints[0];
int whiteR = ints[1];
int blackG = ints[2];
int whiteG = ints[3];
int blackB = ints[4];
int whiteB = ints[5];
String pos = "[" + blackR + "," + blackG + "," + blackB + "] " +
"[" + whiteR + "," + whiteG + "," + whiteB + "]";
return pos;
}
 
public String getExifVersionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_VERSION)) return null;
int[] ints = _directory.getIntArray(ExifDirectory.TAG_EXIF_VERSION);
return ExifDescriptor.convertBytesToVersionString(ints);
}
 
public String getFlashPixVersionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FLASHPIX_VERSION)) return null;
int[] ints = _directory.getIntArray(ExifDirectory.TAG_FLASHPIX_VERSION);
return ExifDescriptor.convertBytesToVersionString(ints);
}
 
public String getSceneTypeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SCENE_TYPE)) return null;
int sceneType = _directory.getInt(ExifDirectory.TAG_SCENE_TYPE);
if (sceneType == 1) {
return "Directly photographed image";
} else {
return "Unknown (" + sceneType + ")";
}
}
 
public String getFileSourceDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FILE_SOURCE)) return null;
int fileSource = _directory.getInt(ExifDirectory.TAG_FILE_SOURCE);
if (fileSource == 3) {
return "Digital Still Camera (DSC)";
} else {
return "Unknown (" + fileSource + ")";
}
}
 
public String getExposureBiasDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_BIAS)) return null;
Rational exposureBias = _directory.getRational(ExifDirectory.TAG_EXPOSURE_BIAS);
return exposureBias.toSimpleString(true) + " EV";
}
 
public String getMaxApertureValueDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_MAX_APERTURE)) return null;
double aperture = _directory.getDouble(ExifDirectory.TAG_MAX_APERTURE);
double fStop = PhotographicConversions.apertureToFStop(aperture);
return "F" + SimpleDecimalFormatter.format(fStop);
}
 
public String getApertureValueDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_APERTURE)) return null;
double aperture = _directory.getDouble(ExifDirectory.TAG_APERTURE);
double fStop = PhotographicConversions.apertureToFStop(aperture);
return "F" + SimpleDecimalFormatter.format(fStop);
}
 
public String getExposureProgramDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_PROGRAM)) return null;
// '1' means manual control, '2' program normal, '3' aperture priority,
// '4' shutter priority, '5' program creative (slow program),
// '6' program action(high-speed program), '7' portrait mode, '8' landscape mode.
switch (_directory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM)) {
case 1: return "Manual control";
case 2: return "Program normal";
case 3: return "Aperture priority";
case 4: return "Shutter priority";
case 5: return "Program creative (slow program)";
case 6: return "Program action (high-speed program)";
case 7: return "Portrait mode";
case 8: return "Landscape mode";
default:
return "Unknown program (" + _directory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM) + ")";
}
}
 
public String getYCbCrSubsamplingDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_YCBCR_SUBSAMPLING)) return null;
int[] positions = _directory.getIntArray(ExifDirectory.TAG_YCBCR_SUBSAMPLING);
if (positions[0] == 2 && positions[1] == 1) {
return "YCbCr4:2:2";
} else if (positions[0] == 2 && positions[1] == 2) {
return "YCbCr4:2:0";
} else {
return "(Unknown)";
}
}
 
public String getPlanarConfigurationDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_PLANAR_CONFIGURATION)) return null;
// When image format is no compression YCbCr, this value shows byte aligns of YCbCr
// data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling
// pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr
// plane format.
 
switch (_directory.getInt(ExifDirectory.TAG_PLANAR_CONFIGURATION)) {
case 1: return "Chunky (contiguous for each subsampling pixel)";
case 2: return "Separate (Y-plane/Cb-plane/Cr-plane format)";
default:
return "Unknown configuration";
}
}
 
public String getSamplesPerPixelDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_SAMPLES_PER_PIXEL)) return null;
return _directory.getString(ExifDirectory.TAG_SAMPLES_PER_PIXEL) + " samples/pixel";
}
 
public String getRowsPerStripDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_ROWS_PER_STRIP)) return null;
return _directory.getString(ExifDirectory.TAG_ROWS_PER_STRIP) + " rows/strip";
}
 
public String getStripByteCountsDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_STRIP_BYTE_COUNTS)) return null;
return _directory.getString(ExifDirectory.TAG_STRIP_BYTE_COUNTS) + " bytes";
}
 
public String getPhotometricInterpretationDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) return null;
// Shows the color space of the image data components
switch (_directory.getInt(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) {
case 0: return "WhiteIsZero";
case 1: return "BlackIsZero";
case 2: return "RGB";
case 3: return "RGB Palette";
case 4: return "Transparency Mask";
case 5: return "CMYK";
case 6: return "YCbCr";
case 8: return "CIELab";
case 9: return "ICCLab";
case 10: return "ITULab";
case 32803: return "Color Filter Array";
case 32844: return "Pixar LogL";
case 32845: return "Pixar LogLuv";
case 32892: return "Linear Raw";
default:
return "Unknown colour space";
}
}
 
public String getCompressionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_COMPRESSION)) return null;
switch (_directory.getInt(ExifDirectory.TAG_COMPRESSION)) {
case 1: return "Uncompressed";
case 2: return "CCITT 1D";
case 3: return "T4/Group 3 Fax";
case 4: return "T6/Group 4 Fax";
case 5: return "LZW";
case 6: return "JPEG (old-style)";
case 7: return "JPEG";
case 8: return "Adobe Deflate";
case 9: return "JBIG B&W";
case 10: return "JBIG Color";
case 32766: return "Next";
case 32771: return "CCIRLEW";
case 32773: return "PackBits";
case 32809: return "Thunderscan";
case 32895: return "IT8CTPAD";
case 32896: return "IT8LW";
case 32897: return "IT8MP";
case 32898: return "IT8BL";
case 32908: return "PixarFilm";
case 32909: return "PixarLog";
case 32946: return "Deflate";
case 32947: return "DCS";
case 32661: return "JBIG";
case 32676: return "SGILog";
case 32677: return "SGILog24";
case 32712: return "JPEG 2000";
case 32713: return "Nikon NEF Compressed";
default:
return "Unknown compression";
}
}
 
public String getBitsPerSampleDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_BITS_PER_SAMPLE)) return null;
return _directory.getString(ExifDirectory.TAG_BITS_PER_SAMPLE) + " bits/component/pixel";
}
 
public String getThumbnailImageWidthDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH)) return null;
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH) + " pixels";
}
 
public String getThumbnailImageHeightDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT)) return null;
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT) + " pixels";
}
 
public String getFocalPlaneXResolutionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_X_RES)) return null;
Rational rational = _directory.getRational(ExifDirectory.TAG_FOCAL_PLANE_X_RES);
return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals) + " " +
getFocalPlaneResolutionUnitDescription().toLowerCase();
}
 
public String getFocalPlaneYResolutionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_Y_RES)) return null;
Rational rational = _directory.getRational(ExifDirectory.TAG_FOCAL_PLANE_Y_RES);
return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals) + " " +
getFocalPlaneResolutionUnitDescription().toLowerCase();
}
 
public String getFocalPlaneResolutionUnitDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) return null;
// Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit,
// '2' inch, '3' centimeter.
switch (_directory.getInt(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) {
case 1:
return "(No unit)";
case 2:
return "Inches";
case 3:
return "cm";
default:
return "";
}
}
 
public String getExifImageWidthDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)) return null;
return _directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) + " pixels";
}
 
public String getExifImageHeightDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) return null;
return _directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT) + " pixels";
}
 
public String getColorSpaceDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_COLOR_SPACE)) return null;
int colorSpace = _directory.getInt(ExifDirectory.TAG_COLOR_SPACE);
if (colorSpace == 1) {
return "sRGB";
} else if (colorSpace == 65535) {
return "Undefined";
} else {
return "Unknown";
}
}
 
public String getFocalLengthDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_LENGTH)) return null;
java.text.DecimalFormat formatter = new DecimalFormat("0.0##");
Rational focalLength = _directory.getRational(ExifDirectory.TAG_FOCAL_LENGTH);
return formatter.format(focalLength.doubleValue()) + " mm";
}
 
public String getFlashDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FLASH)) return null;
 
/*
* This is a bitmask.
* 0 = flash fired
* 1 = return detected
* 2 = return able to be detected
* 3 = unknown
* 4 = auto used
* 5 = unknown
* 6 = red eye reduction used
*/
 
int val = _directory.getInt(ExifDirectory.TAG_FLASH);
 
StringBuffer sb = new StringBuffer();
 
if ((val & 0x1)!=0)
sb.append("Flash fired");
else
sb.append("Flash did not fire");
 
// check if we're able to detect a return, before we mention it
if ((val & 0x4)!=0)
{
if ((val & 0x2)!=0)
sb.append(", return detected");
else
sb.append(", return not detected");
}
 
if ((val & 0x10)!=0)
sb.append(", auto");
 
if ((val & 0x40)!=0)
sb.append(", red-eye reduction");
 
return sb.toString();
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_WHITE_BALANCE)) return null;
// '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash,
// '17' standard light A, '18' standard light B, '19' standard light C, '20' D55,
// '21' D65, '22' D75, '255' other.
switch (_directory.getInt(ExifDirectory.TAG_WHITE_BALANCE)) {
case 0:
return "Unknown";
case 1:
return "Daylight";
case 2:
return "Flourescent";
case 3:
return "Tungsten";
case 10:
return "Flash";
case 17:
return "Standard light";
case 18:
return "Standard light (B)";
case 19:
return "Standard light (C)";
case 20:
return "D55";
case 21:
return "D65";
case 22:
return "D75";
case 255:
return "(Other)";
default:
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_WHITE_BALANCE) + ")";
}
}
 
public String getMeteringModeDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_METERING_MODE)) return null;
// '0' means unknown, '1' average, '2' center weighted average, '3' spot
// '4' multi-spot, '5' multi-segment, '6' partial, '255' other
int meteringMode = _directory.getInt(ExifDirectory.TAG_METERING_MODE);
switch (meteringMode) {
case 0:
return "Unknown";
case 1:
return "Average";
case 2:
return "Center weighted average";
case 3:
return "Spot";
case 4:
return "Multi-spot";
case 5:
return "Multi-segment";
case 6:
return "Partial";
case 255:
return "(Other)";
default:
return "";
}
}
 
public String getSubjectDistanceDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SUBJECT_DISTANCE)) return null;
Rational distance = _directory.getRational(ExifDirectory.TAG_SUBJECT_DISTANCE);
java.text.DecimalFormat formatter = new DecimalFormat("0.0##");
return formatter.format(distance.doubleValue()) + " metres";
}
 
public String getCompressionLevelDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_COMPRESSION_LEVEL)) return null;
Rational compressionRatio = _directory.getRational(ExifDirectory.TAG_COMPRESSION_LEVEL);
String ratio = compressionRatio.toSimpleString(_allowDecimalRepresentationOfRationals);
if (compressionRatio.isInteger() && compressionRatio.intValue() == 1) {
return ratio + " bit/pixel";
} else {
return ratio + " bits/pixel";
}
}
 
public String getThumbnailLengthDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH)) return null;
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_LENGTH) + " bytes";
}
 
public String getThumbnailOffsetDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) return null;
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_OFFSET) + " bytes";
}
 
public String getYResolutionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_Y_RESOLUTION)) return null;
Rational resolution = _directory.getRational(ExifDirectory.TAG_Y_RESOLUTION);
return resolution.toSimpleString(_allowDecimalRepresentationOfRationals) +
" dots per " +
getResolutionDescription().toLowerCase();
}
 
public String getXResolutionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_X_RESOLUTION)) return null;
Rational resolution = _directory.getRational(ExifDirectory.TAG_X_RESOLUTION);
return resolution.toSimpleString(_allowDecimalRepresentationOfRationals) +
" dots per " +
getResolutionDescription().toLowerCase();
}
 
public String getExposureTimeDescription()
{
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_TIME)) return null;
return _directory.getString(ExifDirectory.TAG_EXPOSURE_TIME) + " sec";
}
 
public String getShutterSpeedDescription() throws MetadataException
{
// I believe this method to now be stable, but am leaving some alternative snippets of
// code in here, to assist anyone who's looking into this (given that I don't have a public CVS).
 
if (!_directory.containsTag(ExifDirectory.TAG_SHUTTER_SPEED)) return null;
// float apexValue = _directory.getFloat(ExifDirectory.TAG_SHUTTER_SPEED);
// int apexPower = (int)Math.pow(2.0, apexValue);
// return "1/" + apexPower + " sec";
// TODO test this method
// thanks to Mark Edwards for spotting and patching a bug in the calculation of this
// description (spotted bug using a Canon EOS 300D)
// thanks also to Gli Blr for spotting this bug
float apexValue = _directory.getFloat(ExifDirectory.TAG_SHUTTER_SPEED);
if (apexValue<=1) {
float apexPower = (float)(1/(Math.exp(apexValue*Math.log(2))));
long apexPower10 = Math.round((double)apexPower * 10.0);
float fApexPower = (float) apexPower10 / 10.0f;
return fApexPower + " sec";
} else {
int apexPower = (int)((Math.exp(apexValue*Math.log(2))));
return "1/" + apexPower + " sec";
}
 
/*
// This alternative implementation offered by Bill Richards
// TODO determine which is the correct / more-correct implementation
double apexValue = _directory.getDouble(ExifDirectory.TAG_SHUTTER_SPEED);
double apexPower = Math.pow(2.0, apexValue);
 
StringBuffer sb = new StringBuffer();
if (apexPower > 1)
apexPower = Math.floor(apexPower);
 
if (apexPower < 1) {
sb.append((int)Math.round(1/apexPower));
} else {
sb.append("1/");
sb.append((int)apexPower);
}
sb.append(" sec");
return sb.toString();
*/
 
}
 
public String getFNumberDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_FNUMBER)) return null;
Rational fNumber = _directory.getRational(ExifDirectory.TAG_FNUMBER);
return "F" + SimpleDecimalFormatter.format(fNumber.doubleValue());
}
 
public String getYCbCrPositioningDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_YCBCR_POSITIONING)) return null;
int yCbCrPosition = _directory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING);
switch (yCbCrPosition) {
case 1: return "Center of pixel array";
case 2: return "Datum point";
default:
return String.valueOf(yCbCrPosition);
}
}
 
public String getOrientationDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_ORIENTATION)) return null;
int orientation = _directory.getInt(ExifDirectory.TAG_ORIENTATION);
switch (orientation) {
case 1: return "Top, left side (Horizontal / normal)";
case 2: return "Top, right side (Mirror horizontal)";
case 3: return "Bottom, right side (Rotate 180)";
case 4: return "Bottom, left side (Mirror vertical)";
case 5: return "Left side, top (Mirror horizontal and rotate 270 CW)";
case 6: return "Right side, top (Rotate 90 CW)";
case 7: return "Right side, bottom (Mirror horizontal and rotate 90 CW)";
case 8: return "Left side, bottom (Rotate 270 CW)";
default:
return String.valueOf(orientation);
}
}
 
public String getResolutionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_RESOLUTION_UNIT)) return "";
// '1' means no-unit, '2' means inch, '3' means centimeter. Default value is '2'(inch)
int resolutionUnit = _directory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT);
switch (resolutionUnit) {
case 1: return "(No unit)";
case 2: return "Inch";
case 3: return "cm";
default:
return "";
}
}
 
public String getSensingMethodDescription() throws MetadataException
{
if (!_directory.containsTag(ExifDirectory.TAG_SENSING_METHOD)) return null;
// '1' Not defined, '2' One-chip color area sensor, '3' Two-chip color area sensor
// '4' Three-chip color area sensor, '5' Color sequential area sensor
// '7' Trilinear sensor '8' Color sequential linear sensor, 'Other' reserved
int sensingMethod = _directory.getInt(ExifDirectory.TAG_SENSING_METHOD);
switch (sensingMethod) {
case 1:
return "(Not defined)";
case 2:
return "One-chip color area sensor";
case 3:
return "Two-chip color area sensor";
case 4:
return "Three-chip color area sensor";
case 5:
return "Color sequential area sensor";
case 7:
return "Trilinear sensor";
case 8:
return "Color sequential linear sensor";
default:
return "";
}
}
 
public String getComponentConfigurationDescription() throws MetadataException
{
int[] components = _directory.getIntArray(ExifDirectory.TAG_COMPONENTS_CONFIGURATION);
String[] componentStrings = {"", "Y", "Cb", "Cr", "R", "G", "B"};
StringBuffer componentConfig = new StringBuffer();
for (int i = 0; i < Math.min(4, components.length); i++) {
int j = components[i];
if (j > 0 && j < componentStrings.length) {
componentConfig.append(componentStrings[j]);
}
}
return componentConfig.toString();
}
 
/**
* Takes a series of 4 bytes from the specified offset, and converts these to a
* well-known version number, where possible. For example, (hex) 30 32 31 30 == 2.10).
* @param components the four version values
* @return the version as a string of form 2.10
*/
public static String convertBytesToVersionString(int[] components)
{
StringBuffer version = new StringBuffer();
for (int i = 0; i < 4 && i < components.length; i++) {
if (i == 2) version.append('.');
String digit = String.valueOf((char)components[i]);
if (i == 0 && "0".equals(digit)) continue;
version.append(digit);
}
return version.toString();
}
 
/**
* The Windows specific tags uses plain Unicode
*/
private String getUnicodeDescription(int tag) throws MetadataException
{
if (!_directory.containsTag(tag)) return null;
byte[] commentBytes = _directory.getByteArray(tag);
try {
// decode the unicode string
// trim it, as i'm seeing a junk character on the end
return new String(commentBytes, "UTF-16LE").trim();
}
catch (UnsupportedEncodingException ex) {
return null;
}
}
 
public String getWindowsAuthorDescription() throws MetadataException
{
return getUnicodeDescription(ExifDirectory.TAG_WIN_AUTHOR);
}
 
public String getWindowsCommentDescription() throws MetadataException
{
return getUnicodeDescription(ExifDirectory.TAG_WIN_COMMENT);
}
 
public String getWindowsKeywordsDescription() throws MetadataException
{
return getUnicodeDescription(ExifDirectory.TAG_WIN_KEYWORDS);
}
 
public String getWindowsTitleDescription() throws MetadataException
{
return getUnicodeDescription(ExifDirectory.TAG_WIN_TITLE);
}
 
public String getWindowsSubjectDescription() throws MetadataException
{
return getUnicodeDescription(ExifDirectory.TAG_WIN_SUBJECT);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/SonyMakernoteDescriptor.java
0,0 → 1,36
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a SonyMakernoteDirectory.
* Thanks to David Carson for the initial version of this class.
*/
public class SonyMakernoteDescriptor extends TagDescriptor
{
public SonyMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
return _directory.getString(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType2MakernoteDirectory.java
0,0 → 1,544
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 3-Oct-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
 
import java.util.HashMap;
 
/**
* Contains values specific to Nikon cameras. Type-2 applies to the E990 and D-series cameras such as the E990, D1,
* D70 and D100.
*
* Thanks to Fabrizio Giudici for publishing his reverse-engineering of the D100 makernote data.
* http://www.timelesswanderings.net/equipment/D100/NEF.html
*
* Note that the camera implements image protection (locking images) via the file's 'readonly' attribute. Similarly
* image hiding uses the 'hidden' attribute (observed on the D70). Consequently, these values are not available here.
*
* Additional sample images have been observed, and their tag values recorded in javadoc comments for each tag's field.
* New tags have subsequently been added since Fabrizio's observations.
*
* In earlier models (such as the E990 and D1), this directory begins at the first byte of the makernote IFD. In
* later models, the IFD was given the standard prefix to indicate the camera models (most other manufacturers also
* provide this prefix to aid in software decoding).
*/
public class NikonType2MakernoteDirectory extends Directory
{
/**
* Values observed
* - 0200 (D70)
* - 0200 (D1X)
*/
public static final int TAG_NIKON_TYPE2_FIRMWARE_VERSION = 0x0001;
 
/**
* Values observed
* - 0 250
* - 0 400
*/
public static final int TAG_NIKON_TYPE2_ISO_1 = 0x0002;
 
/**
* Values observed
* - COLOR (seen in the D1X)
*/
public static final int TAG_NIKON_TYPE2_COLOR_MODE = 0x0003;
 
/**
* Values observed
* - FILE
* - RAW
* - NORMAL
* - FINE
*/
public static final int TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT = 0x0004;
 
/**
* The white balance as set in the camera.
*
* Values observed
* - AUTO
* - SUNNY (D70)
* - FLASH (D1X)
* (presumably also SHADOW / INCANDESCENT / FLUORESCENT / CLOUDY)
*/
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE = 0x0005;
 
/**
* The sharpening as set in the camera.
*
* Values observed
* - AUTO
* - NORMAL (D70)
* - NONE (D1X)
*/
public static final int TAG_NIKON_TYPE2_CAMERA_SHARPENING = 0x0006;
 
/**
* The auto-focus type used by the camera.
*
* Values observed
* - AF-S
* - AF-C
* - MANUAL
*/
public static final int TAG_NIKON_TYPE2_AF_TYPE = 0x0007;
 
/**
* Values observed
* - NORMAL
* - RED-EYE
*
* Note: when TAG_NIKON_TYPE2_AUTO_FLASH_MODE is blank, Nikon Browser displays "Flash Sync Mode: Not Attached"
*/
public static final int TAG_NIKON_TYPE2_FLASH_SYNC_MODE = 0x0008;
 
/**
* Values observed
* - Built-in,TTL
* - Optional,TTL (with speedlight SB800, flash sync mode as NORMAL. NikonBrowser reports Auto Flash Comp: 0 EV -- which tag is that?) (D70)
* - NEW_TTL (Nikon Browser interprets as "D-TTL")
* - (blank -- accompanied FlashSyncMode of NORMAL) (D70)
*/
public static final int TAG_NIKON_TYPE2_AUTO_FLASH_MODE = 0x0009;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_34 = 0x000A;
 
/**
* Values observed
* - 0
*/
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE = 0x000B;
 
/**
* The first two numbers are coefficients to multiply red and blue channels according to white balance as set in the
* camera. The meaning of the third and the fourth numbers is unknown.
*
* Values observed
* - 2.25882352 1.76078431 0.0 0.0
* - 10242/1 34305/1 0/1 0/1
* - 234765625/100000000 1140625/1000000 1/1 1/1
*/
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF = 0x000C;
 
/**
* Values observed
* - 0,1,6,0 (hex)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_1 = 0x000D;
 
/**
* Values observed
* - î
* - 0,1,c,0 (hex)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_2 = 0x000E;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_ISO_SELECTION = 0x000F;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_DATA_DUMP = 0x0010;
 
/**
* Values observed
* - 914
* - 1379 (D70)
* - 2781 (D1X)
* - 6942 (D100)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_3 = 0x0011;
 
/**
* Values observed
* - (no value -- blank)
*/
public static final int TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION = 0x0012;
 
/**
* Values observed
* - 0 250
* - 0 400
*/
public static final int TAG_NIKON_TYPE2_ISO_2 = 0x0013;
 
/**
* Values observed
* - 0 0 49163 53255
* - 0 0 3008 2000 (the image dimensions were 3008x2000) (D70)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_21 = 0x0016;
 
/**
* Values observed
* - (blank)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_22 = 0x0017;
 
/**
* Values observed
* - (blank)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_23 = 0x0018;
 
/**
* Values observed
* - 0
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_24 = 0x0019;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT = 0x0080;
 
/**
* The tone compensation as set in the camera.
*
* Values observed
* - AUTO
* - NORMAL (D1X, D100)
*/
public static final int TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION = 0x0081;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_ADAPTER = 0x0082;
 
/**
* Values observed
* - 6
* - 6 (D70)
* - 2 (D1X)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_4 = 0x0083;
 
/**
* A pair of focal/max-fstop values that describe the lens used.
*
* Values observed
* - 180.0,180.0,2.8,2.8 (D100)
* - 240/10 850/10 35/10 45/10
* - 18-70mm f/3.5-4.5 (D70)
* - 17-35mm f/2.8-2.8 (D1X)
* - 70-200mm f/2.8-2.8 (D70)
*
* Nikon Browser identifies the lens as "18-70mm F/3.5-4.5 G" which
* is identical to metadata extractor, except for the "G". This must
* be coming from another tag...
*/
public static final int TAG_NIKON_TYPE2_LENS = 0x0084;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE = 0x0085;
 
/**
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1.
*/
public static final int TAG_NIKON_TYPE2_DIGITAL_ZOOM = 0x0086;
 
/**
* Values observed
* - 0
* - 9
* - 3 (D1X)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_5 = 0x0087;
 
/**
* Values observed
* -
*/
public static final int TAG_NIKON_TYPE2_AF_FOCUS_POSITION = 0x0088;
 
/**
* Values observed
* - 0
* - 1
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_7 = 0x0089;
 
/**
* Values observed
* - 0
* - 0
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_20 = 0x008A;
 
/**
* Values observed
* - 48,1,c,0 (hex) (D100)
* - @
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_8 = 0x008B;
 
/**
* Unknown. Fabrizio believes this may be a lookup table for the user-defined curve.
*
* Values observed
* - (blank) (D1X)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_9 = 0x008C;
 
/**
* The color space as set in the camera.
*
* Values observed
* - MODE1
* - Mode I (sRGB) (D70)
* - MODE2 (D1X, D100)
*/
public static final int TAG_NIKON_TYPE2_CAMERA_COLOR_MODE = 0x008D;
 
/**
* Values observed
* - NATURAL
* - SPEEDLIGHT (D70, D1X)
*/
public static final int TAG_NIKON_TYPE2_LIGHT_SOURCE = 0x0090;
 
/**
* Values observed
* - 0100)
* - 0103 (D70)
* - 0100 (D1X)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_11 = 0x0091;
 
/**
* The hue adjustment as set in the camera.
*
* Values observed
* - 0
*/
public static final int TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT = 0x0092;
 
/**
* Values observed
* - OFF
*/
public static final int TAG_NIKON_TYPE2_NOISE_REDUCTION = 0x0095;
 
/**
* Values observed
* - 0100 '~e3
* - 0103
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_12 = 0x0097;
 
/**
* Values observed
* - 0100fht@7b,4x,D"Y
* - 01015
* - 0100w\cH+D$$h$î5Q (D1X)
* - 30,31,30,30,0,0,b,48,7c,7c,24,24,5,15,24,0,0,0,0,0 (hex) (D100)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_13 = 0x0098;
 
/**
* Values observed
* - 2014 662 (D1X)
* - 1517,1012 (D100)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_14 = 0x0099;
 
/**
* Values observed
* - 78/10 78/10
* - 78/10 78/10 (D70)
* - 59/10 59/5 (D1X)
* - 7.8,7.8 (D100)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_15 = 0x009A;
 
/**
* Values observed
* - NO= 00002539
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_25 = 0x00A0;
 
/**
* Values observed
* - 1564851
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_26 = 0x00A2;
 
/**
* Values observed
* - 0
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_27 = 0x00A3;
 
/**
* This appears to be a sequence number to indentify the exposure. This value seems to increment
* for consecutive exposures (observed on D70).
*
* Values observed
* - 5062
*/
public static final int TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER = 0x00A7;
 
/**
* Values observed
* - 0100 (D70)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_32 = 0x00A8;
 
/**
* Values observed
* - NORMAL (D70)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_33 = 0x00A9;
 
/**
* Nikon Browser suggests this value represents Saturation...
* Values observed
* - NORMAL (D70)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_29 = 0x00AA;
 
/**
* Values observed
* - AUTO (D70)
* - (blank) (D70)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_30 = 0x00AB;
 
/**
* Data about changes set by Nikon Capture Editor.
*
* Values observed
*/
public static final int TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA = 0x0E01;
 
/**
* Values observed
* - 1473
* - 7036 (D100)
*/
public static final int TAG_NIKON_TYPE2_UNKNOWN_16 = 0x0E10;
 
protected static final HashMap _tagNameMap = new HashMap();
 
static
{
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FIRMWARE_VERSION), "Firmware Version");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_1), "ISO");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT), "Quality & File Format");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE), "White Balance");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_SHARPENING), "Sharpening");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_TYPE), "AF Type");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE), "White Balance Fine");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF), "White Balance RB Coefficients");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_2), "ISO");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_SELECTION), "ISO Selection");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DATA_DUMP), "Data Dump");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT), "Image Adjustment");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION), "Tone Compensation");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ADAPTER), "Adapter");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LENS), "Lens");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE), "Manual Focus Distance");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DIGITAL_ZOOM), "Digital Zoom");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_COLOR_MODE), "Colour Mode");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT), "Camera Hue Adjustment");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_NOISE_REDUCTION), "Noise Reduction");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA), "Capture Editor Data");
 
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_1), "Unknown 01");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_2), "Unknown 02");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_3), "Unknown 03");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_4), "Unknown 04");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_5), "Unknown 05");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_FOCUS_POSITION), "AF Focus Position");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_7), "Unknown 07");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_8), "Unknown 08");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_9), "Unknown 09");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LIGHT_SOURCE), "Light source");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_11), "Unknown 11");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_12), "Unknown 12");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_13), "Unknown 13");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_14), "Unknown 14");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_15), "Unknown 15");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_16), "Unknown 16");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FLASH_SYNC_MODE), "Flash Sync Mode");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_MODE), "Auto Flash Mode");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION), "Auto Flash Compensation");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER), "Exposure Sequence Number");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_COLOR_MODE), "Color Mode");
 
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_20), "Unknown 20");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_21), "Unknown 21");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_22), "Unknown 22");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_23), "Unknown 23");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_24), "Unknown 24");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_25), "Unknown 25");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_26), "Unknown 26");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_27), "Unknown 27");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_29), "Unknown 29");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_30), "Unknown 30");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_32), "Unknown 32");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_33), "Unknown 33");
}
 
public NikonType2MakernoteDirectory()
{
this.setDescriptor(new NikonType2MakernoteDescriptor(this));
}
 
public Rational getAutoFlashCompensation() throws MetadataException
{
if (!containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION))
return null;
 
byte[] bytes = getByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION);
return CalculateFlashCompensationFromBytes(bytes);
}
 
public static Rational CalculateFlashCompensationFromBytes(byte[] bytes)
{
if (bytes.length==3)
{
byte denominator = bytes[2];
int numerator = (int)bytes[0] * bytes[1];
return new Rational(numerator, denominator);
}
return null;
}
 
public String getName()
{
return "Nikon Makernote";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KodakMakernoteDescriptor.java
0,0 → 1,36
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a KodakMakernoteDirectory.
* Thanks to David Carson for the initial version of this class.
*/
public class KodakMakernoteDescriptor extends TagDescriptor
{
public KodakMakernoteDescriptor(Directory directory)
{
super(directory);
}
public String getDescription(int tagType) throws MetadataException
{
return _directory.getString(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CanonMakernoteDescriptor.java
0,0 → 1,716
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class CanonMakernoteDescriptor extends TagDescriptor
{
public CanonMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY:
return getFlashActivityDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE:
return getFocusTypeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY:
return getQualityDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE:
return getMacroModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY:
return getSelfTimerDelayDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE:
return getFlashModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE:
return getContinuousDriveModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1:
return getFocusMode1Description();
case CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE:
return getImageSizeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE:
return getEasyShootingModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST:
return getContrastDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION:
return getSaturationDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS:
return getSharpnessDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_ISO:
return getIsoDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE:
return getMeteringModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED:
return getAfPointSelectedDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE:
return getExposureModeDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH:
return getLongFocalLengthDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH:
return getShortFocalLengthDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM:
return getFocalUnitsPerMillimetreDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS:
return getFlashDetailsDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2:
return getFocusMode2Description();
case CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE:
return getWhiteBalanceDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED:
return getAfPointUsedDescription();
case CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS:
return getFlashBiasDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION:
return getLongExposureNoiseReductionDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS:
return getShutterAutoExposureLockButtonDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP:
return getMirrorLockupDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL:
return getTvAndAvExposureLevelDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT:
return getAutoFocusAssistLightDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE:
return getShutterSpeedInAvModeDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING:
return getAutoExposureBrackettingSequenceAndAutoCancellationDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC:
return getShutterCurtainSyncDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP:
return getLensAutoFocusStopButtonDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION:
return getFillFlashReductionDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN:
return getMenuButtonReturnPositionDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION:
return getSetButtonFunctionWhenShootingDescription();
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING:
return getSensorCleaningDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getLongExposureNoiseReductionDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION);
switch (value) {
case 0: return "Off";
case 1: return "On";
default: return "Unknown (" + value + ")";
}
}
public String getShutterAutoExposureLockButtonDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS);
switch (value) {
case 0: return "AF/AE lock";
case 1: return "AE lock/AF";
case 2: return "AF/AF lock";
case 3: return "AE+release/AE+AF";
default: return "Unknown (" + value + ")";
}
}
public String getMirrorLockupDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP);
switch (value) {
case 0: return "Disabled";
case 1: return "Enabled";
default: return "Unknown (" + value + ")";
}
}
public String getTvAndAvExposureLevelDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL);
switch (value) {
case 0: return "1/2 stop";
case 1: return "1/3 stop";
default: return "Unknown (" + value + ")";
}
}
public String getAutoFocusAssistLightDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT);
switch (value) {
case 0: return "On (Auto)";
case 1: return "Off";
default: return "Unknown (" + value + ")";
}
}
public String getShutterSpeedInAvModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE);
switch (value) {
case 0: return "Automatic";
case 1: return "1/200 (fixed)";
default: return "Unknown (" + value + ")";
}
}
public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING);
switch (value) {
case 0: return "0,-,+ / Enabled";
case 1: return "0,-,+ / Disabled";
case 2: return "-,0,+ / Enabled";
case 3: return "-,0,+ / Disabled";
default: return "Unknown (" + value + ")";
}
}
public String getShutterCurtainSyncDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC);
switch (value) {
case 0: return "1st Curtain Sync";
case 1: return "2nd Curtain Sync";
default: return "Unknown (" + value + ")";
}
}
public String getLensAutoFocusStopButtonDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP);
switch (value) {
case 0: return "AF stop";
case 1: return "Operate AF";
case 2: return "Lock AE and start timer";
default: return "Unknown (" + value + ")";
}
}
public String getFillFlashReductionDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION);
switch (value) {
case 0: return "Enabled";
case 1: return "Disabled";
default: return "Unknown (" + value + ")";
}
}
public String getMenuButtonReturnPositionDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN);
switch (value) {
case 0: return "Top";
case 1: return "Previous (volatile)";
case 2: return "Previous";
default: return "Unknown (" + value + ")";
}
}
public String getSetButtonFunctionWhenShootingDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION);
switch (value) {
case 0: return "Not Assigned";
case 1: return "Change Quality";
case 2: return "Change ISO Speed";
case 3: return "Select Parameters";
default: return "Unknown (" + value + ")";
}
}
public String getSensorCleaningDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING);
switch (value) {
case 0: return "Disabled";
case 1: return "Enabled";
default: return "Unknown (" + value + ")";
}
}
 
public String getFlashBiasDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)) return null;
 
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS);
 
boolean isNegative = false;
if (value > 0xF000)
{
isNegative = true;
value = 0xFFFF - value;
value++;
}
 
// this tag is interesting in that the values returned are:
// 0, 0.375, 0.5, 0.626, 1
// not
// 0, 0.33, 0.5, 0.66, 1
 
return ((isNegative) ? "-" : "") + Float.toString(value / 32f) + " EV";
}
 
public String getAfPointUsedDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED);
if ((value & 0x7) == 0) {
return "Right";
} else if ((value & 0x7) == 1) {
return "Centre";
} else if ((value & 0x7) == 2) {
return "Left";
} else {
return "Unknown (" + value + ")";
}
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE);
switch (value) {
case 0:
return "Auto";
case 1:
return "Sunny";
case 2:
return "Cloudy";
case 3:
return "Tungsten";
case 4:
return "Flourescent";
case 5:
return "Flash";
case 6:
return "Custom";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusMode2Description() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2);
switch (value) {
case 0:
return "Single";
case 1:
return "Continuous";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashDetailsDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS);
if (((value << 14) & 1) > 0) {
return "External E-TTL";
}
if (((value << 13) & 1) > 0) {
return "Internal flash";
}
if (((value << 11) & 1) > 0) {
return "FP sync used";
}
if (((value << 4) & 1) > 0) {
return "FP sync enabled";
}
return "Unknown (" + value + ")";
}
 
public String getFocalUnitsPerMillimetreDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM)) return "";
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM);
if (value != 0) {
return Integer.toString(value);
} else {
return "";
}
}
 
public String getShortFocalLengthDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH);
String units = getFocalUnitsPerMillimetreDescription();
return Integer.toString(value) + " " + units;
}
 
public String getLongFocalLengthDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH);
String units = getFocalUnitsPerMillimetreDescription();
return Integer.toString(value) + " " + units;
}
 
public String getExposureModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE);
switch (value) {
case 0:
return "Easy shooting";
case 1:
return "Program";
case 2:
return "Tv-priority";
case 3:
return "Av-priority";
case 4:
return "Manual";
case 5:
return "A-DEP";
default:
return "Unknown (" + value + ")";
}
}
 
public String getAfPointSelectedDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED);
switch (value) {
case 0x3000:
return "None (MF)";
case 0x3001:
return "Auto selected";
case 0x3002:
return "Right";
case 0x3003:
return "Centre";
case 0x3004:
return "Left";
default:
return "Unknown (" + value + ")";
}
}
 
public String getMeteringModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE);
switch (value) {
case 3:
return "Evaluative";
case 4:
return "Partial";
case 5:
return "Centre weighted";
default:
return "Unknown (" + value + ")";
}
}
 
public String getIsoDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO);
switch (value) {
case 0:
return "Not specified (see ISOSpeedRatings tag)";
case 15:
return "Auto";
case 16:
return "50";
case 17:
return "100";
case 18:
return "200";
case 19:
return "400";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS);
switch (value) {
case 0xFFFF:
return "Low";
case 0x000:
return "Normal";
case 0x001:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSaturationDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION);
switch (value) {
case 0xFFFF:
return "Low";
case 0x000:
return "Normal";
case 0x001:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getContrastDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST);
switch (value) {
case 0xFFFF:
return "Low";
case 0x000:
return "Normal";
case 0x001:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getEasyShootingModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE);
switch (value) {
case 0:
return "Full auto";
case 1:
return "Manual";
case 2:
return "Landscape";
case 3:
return "Fast shutter";
case 4:
return "Slow shutter";
case 5:
return "Night";
case 6:
return "B&W";
case 7:
return "Sepia";
case 8:
return "Portrait";
case 9:
return "Sports";
case 10:
return "Macro / Closeup";
case 11:
return "Pan focus";
default:
return "Unknown (" + value + ")";
}
}
 
public String getImageSizeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE);
switch (value) {
case 0:
return "Large";
case 1:
return "Medium";
case 2:
return "Small";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusMode1Description() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1);
switch (value) {
case 0:
return "One-shot";
case 1:
return "AI Servo";
case 2:
return "AI Focus";
case 3:
return "Manual Focus";
case 4:
// TODO should check field 32 here (FOCUS_MODE_2)
return "Single";
case 5:
return "Continuous";
case 6:
return "Manual Focus";
default:
return "Unknown (" + value + ")";
}
}
 
public String getContinuousDriveModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE);
switch (value) {
case 0:
if (_directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY) == 0) {
return "Single shot";
} else {
return "Single shot with self-timer";
}
case 1:
return "Continuous";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE);
switch (value) {
case 0:
return "No flash fired";
case 1:
return "Auto";
case 2:
return "On";
case 3:
return "Red-eye reduction";
case 4:
return "Slow-synchro";
case 5:
return "Auto and red-eye reduction";
case 6:
return "On and red-eye reduction";
case 16:
// note: this value not set on Canon D30
return "Extenal flash";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSelfTimerDelayDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY);
if (value == 0) {
return "Self timer not used";
} else {
// TODO find an image that tests this calculation
return Double.toString((double)value * 0.1d) + " sec";
}
}
 
public String getMacroModeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE);
switch (value) {
case 1:
return "Macro";
case 2:
return "Normal";
default:
return "Unknown (" + value + ")";
}
}
 
public String getQualityDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY);
switch (value) {
case 2:
return "Normal";
case 3:
return "Fine";
case 5:
return "Superfine";
default:
return "Unknown (" + value + ")";
}
}
 
public String getDigitalZoomDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM);
switch (value) {
case 0:
return "No digital zoom";
case 1:
return "2x";
case 2:
return "4x";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusTypeDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE);
switch (value) {
case 0:
return "Manual";
case 1:
return "Auto";
case 3:
return "Close-up (Macro)";
case 8:
return "Locked (Pan Mode)";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashActivityDescription() throws MetadataException
{
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY)) return null;
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY);
switch (value) {
case 0:
return "Flash did not fire";
case 1:
return "Flash fired";
default:
return "Unknown (" + value + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PentaxMakernoteDescriptor.java
0,0 → 1,248
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in PentaxMakernoteDirectory.
*
* Some information about this makernote taken from here:
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pentax_mn.html
*/
public class PentaxMakernoteDescriptor extends TagDescriptor
{
public PentaxMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType)
{
case PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE:
return getCaptureModeDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL:
return getQualityLevelDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE:
return getFocusModeDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE:
return getFlashModeDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE:
return getWhiteBalanceDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS:
return getSharpnessDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST:
return getContrastDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_SATURATION:
return getSaturationDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED:
return getIsoSpeedDescription();
case PentaxMakernoteDirectory.TAG_PENTAX_COLOUR:
return getColourDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getColourDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR);
switch (value)
{
case 1: return "Normal";
case 2: return "Black & White";
case 3: return "Sepia";
default: return "Unknown (" + value + ")";
}
}
 
public String getIsoSpeedDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED);
switch (value)
{
// TODO there must be other values which aren't catered for here
case 10: return "ISO 100";
case 16: return "ISO 200";
case 100: return "ISO 100";
case 200: return "ISO 200";
default: return "Unknown (" + value + ")";
}
}
 
public String getSaturationDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION);
switch (value)
{
case 0: return "Normal";
case 1: return "Low";
case 2: return "High";
default: return "Unknown (" + value + ")";
}
}
 
public String getContrastDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST);
switch (value)
{
case 0: return "Normal";
case 1: return "Low";
case 2: return "High";
default: return "Unknown (" + value + ")";
}
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS);
switch (value)
{
case 0: return "Normal";
case 1: return "Soft";
case 2: return "Hard";
default: return "Unknown (" + value + ")";
}
}
 
public String getDigitalZoomDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM)) return null;
float value = _directory.getFloat(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM);
if (value==0)
return "Off";
return Float.toString(value);
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE);
switch (value)
{
case 0: return "Auto";
case 1: return "Daylight";
case 2: return "Shade";
case 3: return "Tungsten";
case 4: return "Fluorescent";
case 5: return "Manual";
default: return "Unknown (" + value + ")";
}
}
 
public String getFlashModeDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE);
switch (value)
{
case 1: return "Auto";
case 2: return "Flash On";
case 4: return "Flash Off";
case 6: return "Red-eye Reduction";
default: return "Unknown (" + value + ")";
}
}
 
public String getFocusModeDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE);
switch (value)
{
case 2: return "Custom";
case 3: return "Auto";
default: return "Unknown (" + value + ")";
}
}
 
public String getQualityLevelDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL);
switch (value)
{
case 0: return "Good";
case 1: return "Better";
case 2: return "Best";
default: return "Unknown (" + value + ")";
}
}
 
public String getCaptureModeDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE);
switch (value)
{
case 1: return "Auto";
case 2: return "Night-scene";
case 3: return "Manual";
case 4: return "Multiple";
default: return "Unknown (" + value + ")";
}
}
 
/*
public String getPrintImageMatchingInfoDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null;
byte[] bytes = _directory.getByteArray(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO);
return "(" + bytes.length + " bytes)";
}
 
public String getMacroModeDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE);
switch (value) {
case 1:
return "On";
case 2:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getRecordModeDescription() throws MetadataException
{
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null;
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE);
switch (value) {
case 1:
return "Normal";
case 2:
return "Portrait";
case 9:
return "Macro";
default:
return "Unknown (" + value + ")";
}
}
*/
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType1MakernoteDirectory.java
0,0 → 1,90
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment.
* Makernote data begins immediately (no header).
*/
public class CasioType1MakernoteDirectory extends Directory
{
public static final int TAG_CASIO_RECORDING_MODE = 0x0001;
public static final int TAG_CASIO_QUALITY = 0x0002;
public static final int TAG_CASIO_FOCUSING_MODE = 0x0003;
public static final int TAG_CASIO_FLASH_MODE = 0x0004;
public static final int TAG_CASIO_FLASH_INTENSITY = 0x0005;
public static final int TAG_CASIO_OBJECT_DISTANCE = 0x0006;
public static final int TAG_CASIO_WHITE_BALANCE = 0x0007;
public static final int TAG_CASIO_UNKNOWN_1 = 0x0008;
public static final int TAG_CASIO_UNKNOWN_2 = 0x0009;
public static final int TAG_CASIO_DIGITAL_ZOOM = 0x000A;
public static final int TAG_CASIO_SHARPNESS = 0x000B;
public static final int TAG_CASIO_CONTRAST = 0x000C;
public static final int TAG_CASIO_SATURATION = 0x000D;
public static final int TAG_CASIO_UNKNOWN_3 = 0x000E;
public static final int TAG_CASIO_UNKNOWN_4 = 0x000F;
public static final int TAG_CASIO_UNKNOWN_5 = 0x0010;
public static final int TAG_CASIO_UNKNOWN_6 = 0x0011;
public static final int TAG_CASIO_UNKNOWN_7 = 0x0012;
public static final int TAG_CASIO_UNKNOWN_8 = 0x0013;
public static final int TAG_CASIO_CCD_SENSITIVITY = 0x0014;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_CASIO_CCD_SENSITIVITY), "CCD Sensitivity");
tagNameMap.put(new Integer(TAG_CASIO_CONTRAST), "Contrast");
tagNameMap.put(new Integer(TAG_CASIO_DIGITAL_ZOOM), "Digital Zoom");
tagNameMap.put(new Integer(TAG_CASIO_FLASH_INTENSITY), "Flash Intensity");
tagNameMap.put(new Integer(TAG_CASIO_FLASH_MODE), "Flash Mode");
tagNameMap.put(new Integer(TAG_CASIO_FOCUSING_MODE), "Focussing Mode");
tagNameMap.put(new Integer(TAG_CASIO_OBJECT_DISTANCE), "Object Distance");
tagNameMap.put(new Integer(TAG_CASIO_QUALITY), "Quality");
tagNameMap.put(new Integer(TAG_CASIO_RECORDING_MODE), "Recording Mode");
tagNameMap.put(new Integer(TAG_CASIO_SATURATION), "Saturation");
tagNameMap.put(new Integer(TAG_CASIO_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_1), "Makernote Unknown 1");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_2), "Makernote Unknown 2");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_3), "Makernote Unknown 3");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_4), "Makernote Unknown 4");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_5), "Makernote Unknown 5");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_6), "Makernote Unknown 6");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_7), "Makernote Unknown 7");
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_8), "Makernote Unknown 8");
tagNameMap.put(new Integer(TAG_CASIO_WHITE_BALANCE), "White Balance");
}
 
public CasioType1MakernoteDirectory()
{
this.setDescriptor(new CasioType1MakernoteDescriptor(this));
}
 
public String getName()
{
return "Casio Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/OlympusMakernoteDescriptor.java
0,0 → 1,148
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in an OlympusMakernoteDirectory.
*/
public class OlympusMakernoteDescriptor extends TagDescriptor
{
public OlympusMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE:
return getSpecialModeDescription();
case OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY:
return getJpegQualityDescription();
case OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE:
return getMacroModeDescription();
case OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO:
return getDigiZoomRatioDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getDigiZoomRatioDescription() throws MetadataException
{
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO)) return null;
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO);
switch (value) {
case 0:
return "Normal";
case 2:
return "Digital 2x Zoom";
default:
return "Unknown (" + value + ")";
}
}
 
public String getMacroModeDescription() throws MetadataException
{
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE)) return null;
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE);
switch (value) {
case 0:
return "Normal (no macro)";
case 1:
return "Macro";
default:
return "Unknown (" + value + ")";
}
}
 
public String getJpegQualityDescription() throws MetadataException
{
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY)) return null;
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY);
switch (value) {
case 1:
return "SQ";
case 2:
return "HQ";
case 3:
return "SHQ";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSpecialModeDescription() throws MetadataException
{
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE)) return null;
int[] values = _directory.getIntArray(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE);
StringBuffer desc = new StringBuffer();
switch (values[0]) {
case 0:
desc.append("Normal picture taking mode");
break;
case 1:
desc.append("Unknown picture taking mode");
break;
case 2:
desc.append("Fast picture taking mode");
break;
case 3:
desc.append("Panorama picture taking mode");
break;
default:
desc.append("Unknown picture taking mode");
break;
}
desc.append(" - ");
switch (values[1]) {
case 0:
desc.append("Unknown sequence number");
break;
case 1:
desc.append("1st in a sequnce");
break;
case 2:
desc.append("2nd in a sequence");
break;
case 3:
desc.append("3rd in a sequence");
break;
default:
desc.append(values[1]);
desc.append("th in a sequence");
break;
}
switch (values[2]) {
case 1:
desc.append("Left to right panorama direction");
break;
case 2:
desc.append("Right to left panorama direction");
break;
case 3:
desc.append("Bottom to top panorama direction");
break;
case 4:
desc.append("Top to bottom panorama direction");
break;
}
return desc.toString();
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/DataFormat.java
0,0 → 1,76
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.MetadataException;
 
/**
* An enumeration of data formats used in the TIFF IFDs.
*/
public class DataFormat
{
public static final DataFormat BYTE = new DataFormat("BYTE", 1);
public static final DataFormat STRING = new DataFormat("STRING", 2);
public static final DataFormat USHORT = new DataFormat("USHORT", 3);
public static final DataFormat ULONG = new DataFormat("ULONG", 4);
public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5);
public static final DataFormat SBYTE = new DataFormat("SBYTE", 6);
public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7);
public static final DataFormat SSHORT = new DataFormat("SSHORT", 8);
public static final DataFormat SLONG = new DataFormat("SLONG", 9);
public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10);
public static final DataFormat SINGLE = new DataFormat("SINGLE", 11);
public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12);
 
private final String myName;
private final int value;
 
public static DataFormat fromValue(int value) throws MetadataException
{
switch (value)
{
case 1: return BYTE;
case 2: return STRING;
case 3: return USHORT;
case 4: return ULONG;
case 5: return URATIONAL;
case 6: return SBYTE;
case 7: return UNDEFINED;
case 8: return SSHORT;
case 9: return SLONG;
case 10: return SRATIONAL;
case 11: return SINGLE;
case 12: return DOUBLE;
}
 
throw new MetadataException("value '"+value+"' does not represent a known data format.");
}
 
private DataFormat(String name, int value)
{
myName = name;
this.value = value;
}
 
public int getValue()
{
return value;
}
 
public String toString()
{
return myName;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/SonyMakernoteDirectory.java
0,0 → 1,37
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* Describes tags specific to Sony cameras.
*/
public class SonyMakernoteDirectory extends Directory
{
protected static final HashMap _tagNameMap = new HashMap();
public String getName()
{
return "Sony Makernote";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType1MakernoteDescriptor.java
0,0 → 1,273
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class CasioType1MakernoteDescriptor extends TagDescriptor
{
public CasioType1MakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE:
return getRecordingModeDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_QUALITY:
return getQualityDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE:
return getFocusingModeDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE:
return getFlashModeDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY:
return getFlashIntensityDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE:
return getObjectDistanceDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE:
return getWhiteBalanceDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS:
return getSharpnessDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST:
return getContrastDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_SATURATION:
return getSaturationDescription();
case CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY:
return getCcdSensitivityDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getCcdSensitivityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY);
switch (value) {
// these four for QV3000
case 64:
return "Normal";
case 125:
return "+1.0";
case 250:
return "+2.0";
case 244:
return "+3.0";
// these two for QV8000/2000
case 80:
return "Normal (ISO 80 equivalent)";
case 100:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSaturationDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION);
switch (value) {
case 0:
return "Normal";
case 1:
return "Low";
case 2:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getContrastDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST);
switch (value) {
case 0:
return "Normal";
case 1:
return "Low";
case 2:
return "High";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS);
switch (value) {
case 0:
return "Normal";
case 1:
return "Soft";
case 2:
return "Hard";
default:
return "Unknown (" + value + ")";
}
}
 
public String getDigitalZoomDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM);
switch (value) {
case 0x10000:
return "No digital zoom";
case 0x10001:
return "2x digital zoom";
case 0x20000:
return "2x digital zoom";
case 0x40000:
return "4x digital zoom";
default:
return "Unknown (" + value + ")";
}
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE);
switch (value) {
case 1:
return "Auto";
case 2:
return "Tungsten";
case 3:
return "Daylight";
case 4:
return "Flourescent";
case 5:
return "Shade";
case 129:
return "Manual";
default:
return "Unknown (" + value + ")";
}
}
 
public String getObjectDistanceDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE);
return value + " mm";
}
 
public String getFlashIntensityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY);
switch (value) {
case 11:
return "Weak";
case 13:
return "Normal";
case 15:
return "Strong";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE);
switch (value) {
case 1:
return "Auto";
case 2:
return "On";
case 3:
return "Off";
case 4:
// this documented as additional value for off here:
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/casio_mn.html
return "Red eye reduction";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusingModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE);
switch (value) {
case 2:
return "Macro";
case 3:
return "Auto focus";
case 4:
return "Manual focus";
case 5:
return "Infinity";
default:
return "Unknown (" + value + ")";
}
}
 
public String getQualityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY);
switch (value) {
case 1:
return "Economy";
case 2:
return "Normal";
case 3:
return "Fine";
default:
return "Unknown (" + value + ")";
}
}
 
public String getRecordingModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE)) return null;
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE);
switch (value) {
case 1:
return "Single shutter";
case 2:
return "Panorama";
case 3:
return "Night scene";
case 4:
return "Portrait";
case 5:
return "Landscape";
default:
return "Unknown (" + value + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType2MakernoteDescriptor.java
0,0 → 1,430
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class CasioType2MakernoteDescriptor extends TagDescriptor
{
public CasioType2MakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS:
return getThumbnailDimensionsDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE:
return getThumbnailSizeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET:
return getThumbnailOffsetDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE:
return getQualityModeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE:
return getImageSizeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1:
return getFocusMode1Description();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY:
return getIsoSensitivityDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1:
return getWhiteBalance1Description();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH:
return getFocalLengthDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION:
return getSaturationDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST:
return getContrastDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS:
return getSharpnessDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO:
return getPrintImageMatchingInfoDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL:
return getCasioPreviewThumbnailDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS:
return getWhiteBalanceBiasDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2:
return getWhiteBalance2Description();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE:
return getObjectDistanceDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE:
return getFlashDistanceDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE:
return getRecordModeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER:
return getSelfTimerDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY:
return getQualityDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2:
return getFocusMode2Description();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE:
return getTimeZoneDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE:
return getBestShotModeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY:
return getCcdIsoSensitivityDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE:
return getColourModeDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT:
return getEnhancementDescription();
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER:
return getFilterDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getFilterDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER);
switch (value) {
case 0:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getEnhancementDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT);
switch (value) {
case 0:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getColourModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE);
switch (value) {
case 0:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getCcdIsoSensitivityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY);
switch (value) {
case 0:
return "Off";
case 1:
return "On";
default:
return "Unknown (" + value + ")";
}
}
 
public String getBestShotModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE);
switch (value) {
default:
return "Unknown (" + value + ")";
}
}
 
public String getTimeZoneDescription()
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE)) return null;
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE);
}
 
public String getFocusMode2Description() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2);
switch (value) {
case 1:
return "Fixation";
case 6:
return "Multi-Area Focus";
default:
return "Unknown (" + value + ")";
}
}
 
public String getQualityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY);
switch (value) {
case 3:
return "Fine";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSelfTimerDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER);
switch (value) {
case 1:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getRecordModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE);
switch (value) {
case 2:
return "Normal";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFlashDistanceDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE);
switch (value) {
case 0:
return "Off";
default:
return "Unknown (" + value + ")";
}
}
 
public String getObjectDistanceDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE);
return Integer.toString(value) + " mm";
}
 
public String getWhiteBalance2Description() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2);
switch (value) {
case 0:
return "Manual";
case 1:
return "Auto"; // unsure about this
case 4:
return "Flash"; // unsure about this
case 12:
return "Flash";
default:
return "Unknown (" + value + ")";
}
}
 
public String getWhiteBalanceBiasDescription()
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS)) return null;
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS);
}
 
public String getCasioPreviewThumbnailDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL)) return null;
final byte[] bytes = _directory.getByteArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL);
return "<" + bytes.length + " bytes of image data>";
}
 
public String getPrintImageMatchingInfoDescription()
{
// TODO research PIM specification http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO)) return null;
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO);
}
 
public String getSharpnessDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS);
switch (value) {
case 0:
return "-1";
case 1:
return "Normal";
case 2:
return "+1";
default:
return "Unknown (" + value + ")";
}
}
 
public String getContrastDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST);
switch (value) {
case 0:
return "-1";
case 1:
return "Normal";
case 2:
return "+1";
default:
return "Unknown (" + value + ")";
}
}
 
public String getSaturationDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION);
switch (value) {
case 0:
return "-1";
case 1:
return "Normal";
case 2:
return "+1";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocalLengthDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH)) return null;
double value = _directory.getDouble(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH);
return Double.toString(value / 10d) + " mm";
}
 
public String getWhiteBalance1Description() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1);
switch (value) {
case 0:
return "Auto";
case 1:
return "Daylight";
case 2:
return "Shade";
case 3:
return "Tungsten";
case 4:
return "Flourescent";
case 5:
return "Manual";
default:
return "Unknown (" + value + ")";
}
}
 
public String getIsoSensitivityDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY);
switch (value) {
case 3:
return "50";
case 4:
return "64";
case 6:
return "100";
case 9:
return "200";
default:
return "Unknown (" + value + ")";
}
}
 
public String getFocusMode1Description() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1);
switch (value) {
case 0:
return "Normal";
case 1:
return "Macro";
default:
return "Unknown (" + value + ")";
}
}
 
public String getImageSizeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE);
switch (value) {
case 0: return "640 x 480 pixels";
case 4: return "1600 x 1200 pixels";
case 5: return "2048 x 1536 pixels";
case 20: return "2288 x 1712 pixels";
case 21: return "2592 x 1944 pixels";
case 22: return "2304 x 1728 pixels";
case 36: return "3008 x 2008 pixels";
default: return "Unknown (" + value + ")";
}
}
 
public String getQualityModeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE);
switch (value) {
case 1:
return "Fine";
case 2:
return "Super Fine";
default:
return "Unknown (" + value + ")";
}
}
 
public String getThumbnailOffsetDescription()
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET)) return null;
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET);
}
 
public String getThumbnailSizeDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE)) return null;
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE);
return Integer.toString(value) + " bytes";
}
 
public String getThumbnailDimensionsDescription() throws MetadataException
{
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS)) return null;
int[] dimensions = _directory.getIntArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS);
if (dimensions.length!=2)
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS);
return dimensions[0] + " x " + dimensions[1] + " pixels";
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KyoceraMakernoteDirectory.java
0,0 → 1,53
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class KyoceraMakernoteDirectory extends Directory
{
public static final int TAG_KYOCERA_PROPRIETARY_THUMBNAIL = 0x0001;
public static final int TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO = 0x0E00;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_KYOCERA_PROPRIETARY_THUMBNAIL), "Proprietary Thumbnail Format Data");
tagNameMap.put(new Integer(TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
}
 
public KyoceraMakernoteDirectory()
{
this.setDescriptor(new KyoceraMakernoteDescriptor(this));
}
 
public String getName()
{
return "Kyocera/Contax Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CanonMakernoteDirectory.java
0,0 → 1,448
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* Describes tags specific to Canon cameras.
*
* Thanks to Bill Richards for his contribution to this makernote directory.
*
* Many tag definitions explained here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/canon_mn.html
*/
public class CanonMakernoteDirectory extends Directory
{
// CANON cameras have some funny bespoke fields that need further processing...
public static final int TAG_CANON_CAMERA_STATE_1 = 0x0001;
public static final int TAG_CANON_CAMERA_STATE_2 = 0x0004;
 
public static final int TAG_CANON_IMAGE_TYPE = 0x0006;
public static final int TAG_CANON_FIRMWARE_VERSION = 0x0007;
public static final int TAG_CANON_IMAGE_NUMBER = 0x0008;
public static final int TAG_CANON_OWNER_NAME = 0x0009;
/**
* To display serial number as on camera use: printf( "%04X%05d", highbyte, lowbyte )
* TODO handle this in CanonMakernoteDescriptor
*/
public static final int TAG_CANON_SERIAL_NUMBER = 0x000C;
public static final int TAG_CANON_UNKNOWN_1 = 0x000D;
public static final int TAG_CANON_CUSTOM_FUNCTIONS = 0x000F;
 
// These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment
/**
* 1 = Macro
* 2 = Normal
*/
public static final int TAG_CANON_STATE1_MACRO_MODE = 0xC101;
public static final int TAG_CANON_STATE1_SELF_TIMER_DELAY = 0xC102;
/**
* 2 = Normal
* 3 = Fine
* 5 = Superfine
*/
public static final int TAG_CANON_STATE1_QUALITY = 0xC103;
/**
* 0 = Flash Not Fired
* 1 = Auto
* 2 = On
* 3 = Red Eye Reduction
* 4 = Slow Synchro
* 5 = Auto + Red Eye Reduction
* 6 = On + Red Eye Reduction
* 16 = External Flash
*/
public static final int TAG_CANON_STATE1_FLASH_MODE = 0xC104;
/**
* 0 = Single Frame or Timer Mode
* 1 = Continuous
*/
public static final int TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE = 0xC105;
public static final int TAG_CANON_STATE1_UNKNOWN_2 = 0xC106;
/**
* 0 = One-Shot
* 1 = AI Servo
* 2 = AI Focus
* 3 = Manual Focus
* 4 = Single
* 5 = Continuous
* 6 = Manual Focus
*/
public static final int TAG_CANON_STATE1_FOCUS_MODE_1 = 0xC107;
public static final int TAG_CANON_STATE1_UNKNOWN_3 = 0xC108;
public static final int TAG_CANON_STATE1_UNKNOWN_4 = 0xC109;
/**
* 0 = Large
* 1 = Medium
* 2 = Small
*/
public static final int TAG_CANON_STATE1_IMAGE_SIZE = 0xC10A;
/**
* 0 = Full Auto
* 1 = Manual
* 2 = Landscape
* 3 = Fast Shutter
* 4 = Slow Shutter
* 5 = Night
* 6 = Black & White
* 7 = Sepia
* 8 = Portrait
* 9 = Sports
* 10 = Macro / Close-Up
* 11 = Pan Focus
*/
public static final int TAG_CANON_STATE1_EASY_SHOOTING_MODE = 0xC10B;
/**
* 0 = No Digital Zoom
* 1 = 2x
* 2 = 4x
*/
public static final int TAG_CANON_STATE1_DIGITAL_ZOOM = 0xC10C;
/**
* 0 = Normal
* 1 = High
* 65535 = Low
*/
public static final int TAG_CANON_STATE1_CONTRAST = 0xC10D;
/**
* 0 = Normal
* 1 = High
* 65535 = Low
*/
public static final int TAG_CANON_STATE1_SATURATION = 0xC10E;
/**
* 0 = Normal
* 1 = High
* 65535 = Low
*/
public static final int TAG_CANON_STATE1_SHARPNESS = 0xC10F;
/**
* 0 = Check ISOSpeedRatings EXIF tag for ISO Speed
* 15 = Auto ISO
* 16 = ISO 50
* 17 = ISO 100
* 18 = ISO 200
* 19 = ISO 400
*/
public static final int TAG_CANON_STATE1_ISO = 0xC110;
/**
* 3 = Evaluative
* 4 = Partial
* 5 = Centre Weighted
*/
public static final int TAG_CANON_STATE1_METERING_MODE = 0xC111;
/**
* 0 = Manual
* 1 = Auto
* 3 = Close-up (Macro)
* 8 = Locked (Pan Mode)
*/
public static final int TAG_CANON_STATE1_FOCUS_TYPE = 0xC112;
/**
* 12288 = None (Manual Focus)
* 12289 = Auto Selected
* 12290 = Right
* 12291 = Centre
* 12292 = Left
*/
public static final int TAG_CANON_STATE1_AF_POINT_SELECTED = 0xC113;
/**
* 0 = Easy Shooting (See Easy Shooting Mode)
* 1 = Program
* 2 = Tv-Priority
* 3 = Av-Priority
* 4 = Manual
* 5 = A-DEP
*/
public static final int TAG_CANON_STATE1_EXPOSURE_MODE = 0xC114;
public static final int TAG_CANON_STATE1_UNKNOWN_7 = 0xC115;
public static final int TAG_CANON_STATE1_UNKNOWN_8 = 0xC116;
public static final int TAG_CANON_STATE1_LONG_FOCAL_LENGTH = 0xC117;
public static final int TAG_CANON_STATE1_SHORT_FOCAL_LENGTH = 0xC118;
public static final int TAG_CANON_STATE1_FOCAL_UNITS_PER_MM = 0xC119;
public static final int TAG_CANON_STATE1_UNKNOWN_9 = 0xC11A;
public static final int TAG_CANON_STATE1_UNKNOWN_10 = 0xC11B;
/**
* 0 = Flash Did Not Fire
* 1 = Flash Fired
*/
public static final int TAG_CANON_STATE1_FLASH_ACTIVITY = 0xC11C;
public static final int TAG_CANON_STATE1_FLASH_DETAILS = 0xC11D;
public static final int TAG_CANON_STATE1_UNKNOWN_12 = 0xC11E;
public static final int TAG_CANON_STATE1_UNKNOWN_13 = 0xC11F;
/**
* 0 = Focus Mode: Single
* 1 = Focus Mode: Continuous
*/
public static final int TAG_CANON_STATE1_FOCUS_MODE_2 = 0xC120;
 
/**
* 0 = Auto
* 1 = Sunny
* 2 = Cloudy
* 3 = Tungsten
* 4 = Flourescent
* 5 = Flash
* 6 = Custom
*/
public static final int TAG_CANON_STATE2_WHITE_BALANCE = 0xC207;
public static final int TAG_CANON_STATE2_SEQUENCE_NUMBER = 0xC209;
public static final int TAG_CANON_STATE2_AF_POINT_USED = 0xC20E;
/**
* The value of this tag may be translated into a flash bias value, in EV.
*
* 0xffc0 = -2 EV
* 0xffcc = -1.67 EV
* 0xffd0 = -1.5 EV
* 0xffd4 = -1.33 EV
* 0xffe0 = -1 EV
* 0xffec = -0.67 EV
* 0xfff0 = -0.5 EV
* 0xfff4 = -0.33 EV
* 0x0000 = 0 EV
* 0x000c = 0.33 EV
* 0x0010 = 0.5 EV
* 0x0014 = 0.67 EV
* 0x0020 = 1 EV
* 0x002c = 1.33 EV
* 0x0030 = 1.5 EV
* 0x0034 = 1.67 EV
* 0x0040 = 2 EV
*/
public static final int TAG_CANON_STATE2_FLASH_BIAS = 0xC20F;
public static final int TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING = 0xC210;
public static final int TAG_CANON_STATE2_AEB_BRACKET_VALUE = 0xC211;
public static final int TAG_CANON_STATE2_SUBJECT_DISTANCE = 0xC213;
 
/**
* Long Exposure Noise Reduction
* 0 = Off
* 1 = On
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301;
 
/**
* Shutter/Auto Exposure-lock buttons
* 0 = AF/AE lock
* 1 = AE lock/AF
* 2 = AF/AF lock
* 3 = AE+release/AE+AF
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302;
 
/**
* Mirror lockup
* 0 = Disable
* 1 = Enable
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303;
 
/**
* Tv/Av and exposure level
* 0 = 1/2 stop
* 1 = 1/3 stop
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304;
 
/**
* AF-assist light
* 0 = On (Auto)
* 1 = Off
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305;
 
/**
* Shutter speed in Av mode
* 0 = Automatic
* 1 = 1/200 (fixed)
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306;
 
/**
* Auto-Exposure Bracketting sequence/auto cancellation
* 0 = 0,-,+ / Enabled
* 1 = 0,-,+ / Disabled
* 2 = -,0,+ / Enabled
* 3 = -,0,+ / Disabled
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307;
 
/**
* Shutter Curtain Sync
* 0 = 1st Curtain Sync
* 1 = 2nd Curtain Sync
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308;
 
/**
* Lens Auto-Focus stop button Function Switch
* 0 = AF stop
* 1 = Operate AF
* 2 = Lock AE and start timer
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309;
 
/**
* Auto reduction of fill flash
* 0 = Enable
* 1 = Disable
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A;
 
/**
* Menu button return position
* 0 = Top
* 1 = Previous (volatile)
* 2 = Previous
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B;
 
/**
* SET button function when shooting
* 0 = Not Assigned
* 1 = Change Quality
* 2 = Change ISO Speed
* 3 = Select Parameters
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C;
 
/**
* Sensor cleaning
* 0 = Disable
* 1 = Enable
*/
public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D;
 
// 9 A B C D E F 10 11 12 13
// 9 10 11 12 13 14 15 16 17 18 19
protected static final HashMap _tagNameMap = new HashMap();
 
static
{
_tagNameMap.put(new Integer(TAG_CANON_FIRMWARE_VERSION), "Firmware Version");
_tagNameMap.put(new Integer(TAG_CANON_IMAGE_NUMBER), "Image Number");
_tagNameMap.put(new Integer(TAG_CANON_IMAGE_TYPE), "Image Type");
_tagNameMap.put(new Integer(TAG_CANON_OWNER_NAME), "Owner Name");
_tagNameMap.put(new Integer(TAG_CANON_UNKNOWN_1), "Makernote Unknown 1");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTIONS), "Custom Functions");
_tagNameMap.put(new Integer(TAG_CANON_SERIAL_NUMBER), "Camera Serial Number");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_AF_POINT_SELECTED), "AF Point Selected");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE), "Continuous Drive Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTRAST), "Contrast");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_EASY_SHOOTING_MODE), "Easy Shooting Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_EXPOSURE_MODE), "Exposure Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_DETAILS), "Flash Details");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_MODE), "Flash Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCAL_UNITS_PER_MM), "Focal Units per mm");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_1), "Focus Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_2), "Focus Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_IMAGE_SIZE), "Image Size");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_ISO), "Iso");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_LONG_FOCAL_LENGTH), "Long Focal Length");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_MACRO_MODE), "Macro Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_METERING_MODE), "Metering Mode");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SATURATION), "Saturation");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SELF_TIMER_DELAY), "Self Timer Delay");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SHARPNESS), "Sharpness");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SHORT_FOCAL_LENGTH), "Short Focal Length");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_QUALITY), "Quality");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_2), "Unknown Camera State 2");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_3), "Unknown Camera State 3");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_4), "Unknown Camera State 4");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_DIGITAL_ZOOM), "Digital Zoom");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_TYPE), "Focus Type");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_7), "Unknown Camera State 7");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_8), "Unknown Camera State 8");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_9), "Unknown Camera State 9");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_10), "Unknown Camera State 10");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_ACTIVITY), "Flash Activity");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_12), "Unknown Camera State 12");
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_13), "Unknown Camera State 13");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_WHITE_BALANCE), "White Balance");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_SEQUENCE_NUMBER), "Sequence Number");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AF_POINT_USED), "AF Point Used");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_FLASH_BIAS), "Flash Bias");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING), "Auto Exposure Bracketing");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AEB_BRACKET_VALUE), "AEB Bracket Value");
_tagNameMap.put(new Integer(TAG_CANON_STATE2_SUBJECT_DISTANCE), "Subject Distance");
 
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION), "Long Exposure Noise Reduction");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS), "Shutter/Auto Exposure-lock Buttons");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP), "Mirror Lockup");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL), "Tv/Av And Exposure Level");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT), "AF-Assist Light");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE), "Shutter Speed in Av Mode");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING), "Auto-Exposure Bracketting Sequence/Auto Cancellation");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC), "Shutter Curtain Sync");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_STOP), "Lens Auto-Focus Stop Button Function Switch");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION), "Auto Reduction of Fill Flash");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN), "Menu Button Return Position");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION), "SET Button Function When Shooting");
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING), "Sensor Cleaning");
}
 
public CanonMakernoteDirectory()
{
this.setDescriptor(new CanonMakernoteDescriptor(this));
}
 
public String getName()
{
return "Canon Makernote";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
 
/**
* We need special handling for selected tags.
* @param tagType
* @param ints
*/
public void setIntArray(int tagType, int[] ints)
{
if (tagType == TAG_CANON_CAMERA_STATE_1) {
// this single tag has multiple values within
int subTagTypeBase = 0xC100;
// we intentionally skip the first array member
for (int i = 1; i < ints.length; i++) {
setInt(subTagTypeBase + i, ints[i]);
}
} else if (tagType == TAG_CANON_CAMERA_STATE_2) {
// this single tag has multiple values within
int subTagTypeBase = 0xC200;
// we intentionally skip the first array member
for (int i = 1; i < ints.length; i++) {
setInt(subTagTypeBase + i, ints[i]);
}
} if (tagType == TAG_CANON_CUSTOM_FUNCTIONS) {
// this single tag has multiple values within
int subTagTypeBase = 0xC300;
// we intentionally skip the first array member
for (int i = 1; i < ints.length; i++) {
setInt(subTagTypeBase + i + 1, ints[i] & 0x0F);
}
} else {
// no special handling...
super.setIntArray(tagType, ints);
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifInteropDescriptor.java
0,0 → 1,62
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 22:27:34 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class ExifInteropDescriptor extends TagDescriptor
{
public ExifInteropDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case ExifInteropDirectory.TAG_INTEROP_INDEX:
return getInteropIndexDescription();
case ExifInteropDirectory.TAG_INTEROP_VERSION:
return getInteropVersionDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getInteropVersionDescription() throws MetadataException
{
if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_VERSION)) return null;
int[] ints = _directory.getIntArray(ExifInteropDirectory.TAG_INTEROP_VERSION);
return ExifDescriptor.convertBytesToVersionString(ints);
}
 
public String getInteropIndexDescription()
{
if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_INDEX)) return null;
String interopIndex = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX).trim();
if ("R98".equalsIgnoreCase(interopIndex)) {
return "Recommended Exif Interoperability Rules (ExifR98)";
} else {
return "Unknown (" + interopIndex + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType1MakernoteDirectory.java
0,0 → 1,80
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* Contains values specific to Nikon cameras. Type-1 is for E-Series cameras prior to (not including) E990.
*
* There are 3 formats of Nikon's MakerNote. MakerNote of E700/E800/E900/E900S/E910/E950
* starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from
* offset 0x08. This is the same as Olympus except start string. Example of actual data
* structure is shown below.
* <pre><code>
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
* </code></pre>
*/
public class NikonType1MakernoteDirectory extends Directory
{
public static final int TAG_NIKON_TYPE1_UNKNOWN_1 = 0x0002;
public static final int TAG_NIKON_TYPE1_QUALITY = 0x0003;
public static final int TAG_NIKON_TYPE1_COLOR_MODE = 0x0004;
public static final int TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT = 0x0005;
public static final int TAG_NIKON_TYPE1_CCD_SENSITIVITY = 0x0006;
public static final int TAG_NIKON_TYPE1_WHITE_BALANCE = 0x0007;
public static final int TAG_NIKON_TYPE1_FOCUS = 0x0008;
public static final int TAG_NIKON_TYPE1_UNKNOWN_2 = 0x0009;
public static final int TAG_NIKON_TYPE1_DIGITAL_ZOOM = 0x000A;
public static final int TAG_NIKON_TYPE1_CONVERTER = 0x000B;
public static final int TAG_NIKON_TYPE1_UNKNOWN_3 = 0x0F00;
 
protected static final HashMap _tagNameMap = new HashMap();
 
static
{
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_CCD_SENSITIVITY), "CCD Sensitivity");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_COLOR_MODE), "Color Mode");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_DIGITAL_ZOOM), "Digital Zoom");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_CONVERTER), "Fisheye Converter");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_FOCUS), "Focus");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT), "Image Adjustment");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_QUALITY), "Quality");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_1), "Makernote Unknown 1");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_2), "Makernote Unknown 2");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_3), "Makernote Unknown 3");
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_WHITE_BALANCE), "White Balance");
}
 
public NikonType1MakernoteDirectory()
{
this.setDescriptor(new NikonType1MakernoteDescriptor(this));
}
 
public String getName()
{
return "Nikon Makernote";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withExif.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/noExif.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/windowsXpFields.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType2MakernoteTest1.java
0,0 → 1,149
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 3-Oct-2002 20:47:31 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifReader;
import com.drew.metadata.exif.NikonType2MakernoteDescriptor;
import com.drew.metadata.exif.NikonType2MakernoteDirectory;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class NikonType2MakernoteTest1 extends TestCase
{
private NikonType2MakernoteDirectory _nikonDirectory;
private NikonType2MakernoteDescriptor _descriptor;
 
public NikonType2MakernoteTest1(String s)
{
super(s);
}
 
protected void setUp() throws Exception
{
File metadataFile = new File("src/com/drew/metadata/exif/test/nikonMakernoteType2a.metadata");
Metadata metadata = new ExifReader(JpegSegmentData.FromFile(metadataFile)).extract();
 
_nikonDirectory = (NikonType2MakernoteDirectory)metadata.getDirectory(NikonType2MakernoteDirectory.class);
_descriptor = new NikonType2MakernoteDescriptor(_nikonDirectory);
}
 
/*
[Nikon Makernote] Firmware Version = 0200
[Nikon Makernote] ISO = 0 320
[Nikon Makernote] File Format = FINE
[Nikon Makernote] White Balance = FLASH
[Nikon Makernote] Sharpening = AUTO
[Nikon Makernote] AF Type = AF-C
[Nikon Makernote] Unknown 17 = NORMAL
[Nikon Makernote] Unknown 18 =
[Nikon Makernote] White Balance Fine = 0
[Nikon Makernote] Unknown 01 =
[Nikon Makernote] Unknown 02 =
[Nikon Makernote] Unknown 03 = 914
[Nikon Makernote] Unknown 19 =
[Nikon Makernote] ISO = 0 320
[Nikon Makernote] Tone Compensation = AUTO
[Nikon Makernote] Unknown 04 = 6
[Nikon Makernote] Lens Focal/Max-FStop pairs = 240/10 850/10 35/10 45/10
[Nikon Makernote] Unknown 05 = 0
[Nikon Makernote] Unknown 06 = 
[Nikon Makernote] Unknown 07 = 1
[Nikon Makernote] Unknown 20 = 0
[Nikon Makernote] Unknown 08 = @
[Nikon Makernote] Colour Mode = MODE1
[Nikon Makernote] Unknown 10 = NATURAL
[Nikon Makernote] Unknown 11 = 0100
-
[Nikon Makernote] Camera Hue = 0
[Nikon Makernote] Noise Reduction = OFF
[Nikon Makernote] Unknown 12 = 0100
 
[Nikon Makernote] Unknown 13 = 0100 {t@7b,4x,D"Y
[Nikon Makernote] Unknown 15 = 78/10 78/10
*/
public void testNikonMakernote_MatchesKnownValues() throws Exception
{
assertEquals("48 50 48 48", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION));
assertEquals("0 320", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1));
assertEquals("0 320", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_2));
assertEquals("FLASH ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_SHARPENING));
assertEquals("AF-C ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_TYPE));
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_SYNC_MODE));
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE));
assertEquals("914", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_3));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION));
assertEquals("6", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_4));
assertEquals("240/10 850/10 35/10 45/10", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS));
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_5));
assertEquals("1", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_7));
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_20));
assertEquals("MODE1 ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE));
assertEquals("NATURAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LIGHT_SOURCE));
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT));
assertEquals("OFF ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NOISE_REDUCTION));
assertEquals("78/10 78/10", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_15));
}
 
public void testGetLensDescription() throws MetadataException
{
assertEquals("24-85mm f/3.5-4.5", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS));
assertEquals("24-85mm f/3.5-4.5", _descriptor.getLensDescription());
}
 
public void testGetHueAdjustmentDescription() throws MetadataException
{
assertEquals("0 degrees", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT));
assertEquals("0 degrees", _descriptor.getHueAdjustmentDescription());
}
 
public void testGetColorModeDescription() throws Exception
{
assertEquals("Mode I (sRGB)", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE));
assertEquals("Mode I (sRGB)", _descriptor.getColorModeDescription());
}
 
public void testGetAutoFlashCompensationDescription() throws Exception
{
NikonType2MakernoteDirectory directory = new NikonType2MakernoteDirectory();
NikonType2MakernoteDescriptor descriptor = new NikonType2MakernoteDescriptor(directory);
 
// no entry exists
assertEquals("Unknown", descriptor.getAutoFlashCompensationDescription());
 
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x06, 0x01, 0x06 });
assertEquals("1 EV", descriptor.getAutoFlashCompensationDescription());
 
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x04, 0x01, 0x06 });
assertEquals("0.67 EV", descriptor.getAutoFlashCompensationDescription());
 
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x02, 0x01, 0x06 });
assertEquals("0.33 EV", descriptor.getAutoFlashCompensationDescription());
 
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { (byte)0xFE, 0x01, 0x06 });
assertEquals("-0.33 EV", descriptor.getAutoFlashCompensationDescription());
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType2MakernoteTest2.java
0,0 → 1,169
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.NikonType2MakernoteDirectory;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class NikonType2MakernoteTest2 extends TestCase
{
private NikonType2MakernoteDirectory _nikonDirectory;
private ExifDirectory _exifDirectory;
 
public NikonType2MakernoteTest2(String s)
{
super(s);
}
 
protected void setUp() throws Exception
{
File nikonJpeg = new File("src/com/drew/metadata/exif/test/nikonMakernoteType2b.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(nikonJpeg);
_nikonDirectory = (NikonType2MakernoteDirectory)metadata.getDirectory(NikonType2MakernoteDirectory.class);
_exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
}
 
/*
[Nikon Makernote] Makernote Unknown 1 =
[Nikon Makernote] ISO Setting = Unknown (0 0)
[Nikon Makernote] Color Mode = COLOR
[Nikon Makernote] Quality = NORMAL
[Nikon Makernote] White Balance = AUTO
[Nikon Makernote] Image Sharpening = AUTO
[Nikon Makernote] Focus Mode = AF-C
[Nikon Makernote] Flash Setting = NORMAL
[Nikon Makernote] Makernote Unknown 2 = 4416/500
[Nikon Makernote] ISO Selection = AUTO
[Nikon Makernote] Unknown tag (0x0011) = 1300
[Nikon Makernote] Image Adjustment = AUTO
[Nikon Makernote] Adapter = OFF
[Nikon Makernote] Focus Distance = 0
[Nikon Makernote] Digital Zoom = No digital zoom
[Nikon Makernote] AF Focus Position = Unknown ()
[Nikon Makernote] Unknown tag (0x008f) =
[Nikon Makernote] Unknown tag (0x0094) = 0
[Nikon Makernote] Unknown tag (0x0095) = FPNR
[Nikon Makernote] Unknown tag (0x0e00) = PrintIM
[Nikon Makernote] Unknown tag (0x0e10) = 1394
*/
public void testNikonMakernote_MatchesKnownValues() throws Exception
{
assertEquals("0 1 0 0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION));
assertEquals("0 0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1));
assertEquals("COLOR", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_MODE));
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_SHARPENING));
assertEquals("AF-C ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_TYPE));
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_SYNC_MODE));
// assertEquals(new Rational(4416,500), _nikonDirectory.getRational(NikonType3MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_2));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_SELECTION));
assertEquals(1300, _nikonDirectory.getInt(0x0011));
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT));
assertEquals("OFF ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ADAPTER));
assertEquals(0, _nikonDirectory.getInt(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE));
assertEquals(1, _nikonDirectory.getInt(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM));
assertEquals(" ", _nikonDirectory.getString(0x008f));
assertEquals(0, _nikonDirectory.getInt(0x0094));
assertEquals("FPNR", _nikonDirectory.getString(0x0095));
assertEquals("80 114 105 110 116 73 77 0 48 49 48 48 0 0 13 0 1 0 22 0 22 0 2 0 1 0 0 0 3 0 94 0 0 0 7 0 0 0 0 0 8 0 0 0 0 0 9 0 0 0 0 0 10 0 0 0 0 0 11 0 -90 0 0 0 12 0 0 0 0 0 13 0 0 0 0 0 14 0 -66 0 0 0 0 1 5 0 0 0 1 1 1 0 0 0 9 17 0 0 16 39 0 0 11 15 0 0 16 39 0 0 -105 5 0 0 16 39 0 0 -80 8 0 0 16 39 0 0 1 28 0 0 16 39 0 0 94 2 0 0 16 39 0 0 -117 0 0 0 16 39 0 0 -53 3 0 0 16 39 0 0 -27 27 0 0 16 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", _nikonDirectory.getString(0x0e00));
// assertEquals("PrintIM", _nikonDirectory.getString(0x0e00));
assertEquals(1394, _nikonDirectory.getInt(0x0e10));
}
 
/*
[Exif] Image Description =
[Exif] Make = NIKON
[Exif] Model = E995
[Exif] X Resolution = 72 dots per inch
[Exif] Y Resolution = 72 dots per inch
[Exif] Resolution Unit = Inch
[Exif] Software = E995v1.6
[Exif] Date/Time = 2002:08:29 17:31:40
[Exif] YCbCr Positioning = Center of pixel array
[Exif] Exposure Time = 2439024/100000000 sec
[Exif] F-Number = F2.6
[Exif] Exposure Program = Program normal
[Exif] ISO Speed Ratings = 100
[Exif] Exif Version = 2.10
[Exif] Date/Time Original = 2002:08:29 17:31:40
[Exif] Date/Time Digitized = 2002:08:29 17:31:40
[Exif] Components Configuration = YCbCr
[Exif] Exposure Bias Value = 0
[Exif] Max Aperture Value = F1
[Exif] Metering Mode = Multi-segment
[Exif] Light Source = Unknown
[Exif] Flash = Flash fired
[Exif] Focal Length = 8.2 mm
[Exif] User Comment =
[Exif] FlashPix Version = 1.00
[Exif] Color Space = sRGB
[Exif] Exif Image Width = 2048 pixels
[Exif] Exif Image Height = 1536 pixels
[Exif] File Source = Digital Still Camera (DSC)
[Exif] Scene Type = Directly photographed image
[Exif] Compression = JPEG compression
[Exif] Thumbnail Offset = 1494 bytes
[Exif] Thumbnail Length = 6077 bytes
[Exif] Thumbnail Data = [6077 bytes of thumbnail data]
*/
public void testExifDirectory_MatchesKnownValues() throws Exception
{
assertEquals(" ", _exifDirectory.getString(ExifDirectory.TAG_IMAGE_DESCRIPTION));
assertEquals("NIKON", _exifDirectory.getString(ExifDirectory.TAG_MAKE));
assertEquals("E995", _exifDirectory.getString(ExifDirectory.TAG_MODEL));
assertEquals(72, _exifDirectory.getDouble(ExifDirectory.TAG_X_RESOLUTION), 0.001);
assertEquals(72, _exifDirectory.getDouble(ExifDirectory.TAG_Y_RESOLUTION), 0.001);
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT));
assertEquals("E995v1.6", _exifDirectory.getString(ExifDirectory.TAG_SOFTWARE));
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING));
assertEquals(new Rational(2439024, 100000000), _exifDirectory.getRational(ExifDirectory.TAG_EXPOSURE_TIME));
assertEquals(2.6, _exifDirectory.getDouble(ExifDirectory.TAG_FNUMBER), 0.001);
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM));
assertEquals(100, _exifDirectory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT));
assertEquals("48 50 49 48", _exifDirectory.getString(ExifDirectory.TAG_EXIF_VERSION));
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED));
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL));
assertEquals("1 2 3 0", _exifDirectory.getString(ExifDirectory.TAG_COMPONENTS_CONFIGURATION));
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_BIAS));
assertEquals("0", _exifDirectory.getString(ExifDirectory.TAG_MAX_APERTURE));
assertEquals(5, _exifDirectory.getInt(ExifDirectory.TAG_METERING_MODE));
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_WHITE_BALANCE));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_FLASH));
assertEquals(8.2, _exifDirectory.getDouble(ExifDirectory.TAG_FOCAL_LENGTH), 0.001);
assertEquals("0 0 0 0 0 0 0 0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32", _exifDirectory.getString(ExifDirectory.TAG_USER_COMMENT));
assertEquals("48 49 48 48", _exifDirectory.getString(ExifDirectory.TAG_FLASHPIX_VERSION));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_COLOR_SPACE));
assertEquals(2048, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH));
assertEquals(1536, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT));
assertEquals(3, _exifDirectory.getInt(ExifDirectory.TAG_FILE_SOURCE));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_SCENE_TYPE));
assertEquals(6, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION));
assertEquals(1494, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET));
assertEquals(6077, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifDescriptorTest.java
0,0 → 1,150
/*
* ExifReaderTest.java
*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Oct-2002 19:15:16 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDescriptor;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.ExifReader;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
* JUnit test case for class ExifDescriptor.
* @author Drew Noakes http://drewnoakes.com
*/
public class ExifDescriptorTest extends TestCase
{
public ExifDescriptorTest(String s)
{
super(s);
}
 
public void testXResolutionDescription() throws Exception
{
ExifDirectory directory = new ExifDirectory();
directory.setRational(ExifDirectory.TAG_X_RESOLUTION, new Rational(72, 1));
// 2 is for 'Inch'
directory.setInt(ExifDirectory.TAG_RESOLUTION_UNIT, 2);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("72 dots per inch", descriptor.getDescription(ExifDirectory.TAG_X_RESOLUTION));
}
 
public void testYResolutionDescription() throws Exception
{
ExifDirectory directory = new ExifDirectory();
directory.setRational(ExifDirectory.TAG_Y_RESOLUTION, new Rational(50, 1));
// 3 is for 'cm'
directory.setInt(ExifDirectory.TAG_RESOLUTION_UNIT, 3);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("50 dots per cm", descriptor.getDescription(ExifDirectory.TAG_Y_RESOLUTION));
}
 
public void testUserCommentDescription_EmptyEncoding() throws Exception
{
byte[] commentBytes = "\0\0\0\0\0\0\0\0This is a comment".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("This is a comment", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUserCommentDescription_AsciiHeaderExtendedAsciiEncoding() throws Exception
{
byte[] commentBytes = "ASCII\0\0This is a comment with extended characters æøå ÆØÅ".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("This is a comment with extended characters æøå ÆØÅ", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUserCommentDescription_AsciiHeaderAsciiEncoding() throws Exception
{
byte[] commentBytes = "ASCII\0\0This is a comment".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("This is a comment", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUserCommentDescription_BlankAscii() throws Exception
{
byte[] commentBytes = "ASCII\0\0\0 ".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUserCommentDescription_ZeroLengthAscii1() throws Exception
{
// the 10-byte encoding region is only partially full
byte[] commentBytes = "ASCII\0\0\0".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("ASCII", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUserCommentDescription_ZeroLengthAscii2() throws Exception
{
// fill the 10-byte encoding region
byte[] commentBytes = "ASCII\0\0\0\0\0".getBytes();
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUnicodeComment_ActualBytes() throws Exception
{
byte[] commentBytes = new byte[] { 85, 78, 73, 67, 79, 68, 69, 0, 84, 0, 104, 0, 105, 0, 115, 0, 32, 0, 109, 0, 97, 0, 114, 0, 109, 0, 111, 0, 116, 0, 32, 0, 105, 0, 115, 0, 32, 0, 103, 0, 101, 0, 116, 0, 116, 0, 105, 0, 110, 0, 103, 0, 32, 0, 99, 0, 108, 0, 111, 0, 115, 0, 101, 0, 46, 0, 46, 0, 46, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0 };
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("This marmot is getting close...", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testUnicodeComment_Ascii() throws Exception
{
byte[] commentBytes = new byte[] { 65, 83, 67, 73, 73, 0, 0, 0, 73, 32, 97, 109, 32, 97, 32, 99, 111, 109, 109, 101, 110, 116, 46, 32, 89, 101, 121, 46, 0 };
ExifDirectory directory = new ExifDirectory();
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("I am a comment. Yey.", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT));
}
 
public void testWindowsXpFields() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/windowsXpFields.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
ExifDescriptor descriptor = new ExifDescriptor(directory);
assertEquals("Testing artist", descriptor.getDescription(ExifDirectory.TAG_WIN_AUTHOR));
assertEquals("Testing comments", descriptor.getDescription(ExifDirectory.TAG_WIN_COMMENT));
assertEquals("Testing keywords", descriptor.getDescription(ExifDirectory.TAG_WIN_KEYWORDS));
assertEquals("Testing subject", descriptor.getDescription(ExifDirectory.TAG_WIN_SUBJECT));
assertEquals("Testing title", descriptor.getDescription(ExifDirectory.TAG_WIN_TITLE));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/crash01.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/badExif.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/CanonMakernoteDescriptorTest.java
0,0 → 1,65
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif.test;
 
import com.drew.metadata.exif.CanonMakernoteDescriptor;
import com.drew.metadata.exif.CanonMakernoteDirectory;
import junit.framework.TestCase;
 
public class CanonMakernoteDescriptorTest extends TestCase
{
public CanonMakernoteDescriptorTest(String name)
{
super(name);
}
 
public void testGetFlashBiasDescription() throws Exception
{
CanonMakernoteDirectory directory = new CanonMakernoteDirectory();
CanonMakernoteDescriptor descriptor = new CanonMakernoteDescriptor(directory);
 
// set and check values
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0xFFC0);
assertEquals("-2.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0xffd4);
assertEquals("-1.375 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0000);
assertEquals("0.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x000c);
assertEquals("0.375 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0010);
assertEquals("0.5 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0014);
assertEquals("0.625 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0020);
assertEquals("1.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0030);
assertEquals("1.5 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0034);
assertEquals("1.625 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
 
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0040);
assertEquals("2.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/recursiveDirectories.metadata
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType1.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType1MakernoteTest.java
0,0 → 1,172
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.lang.Rational;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.NikonType1MakernoteDirectory;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class NikonType1MakernoteTest extends TestCase
{
private NikonType1MakernoteDirectory _nikonDirectory;
private ExifDirectory _exifDirectory;
 
public NikonType1MakernoteTest(String s)
{
super(s);
}
 
/*
[Interoperability] Interoperability Index = Recommended Exif Interoperability Rules (ExifR98)
[Interoperability] Interoperability Version = 1.00
[Jpeg] Data Precision = 8 bits
[Jpeg] Image Width = 600 pixels
[Jpeg] Image Height = 800 pixels
[Jpeg] Number of Components = 3
[Jpeg] Component 1 = Y component: Quantization table 0, Sampling factors 1 horiz/1 vert
[Jpeg] Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
[Jpeg] Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
*/
 
protected void setUp() throws Exception
{
File nikonJpeg = new File("src/com/drew/metadata/exif/test/nikonMakernoteType1.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(nikonJpeg);
_nikonDirectory = (NikonType1MakernoteDirectory)metadata.getDirectory(NikonType1MakernoteDirectory.class);
_exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
}
 
/*
[Nikon Makernote] Makernote Unknown 1 = 08.00
[Nikon Makernote] Quality = Unknown (12)
[Nikon Makernote] Color Mode = Color
[Nikon Makernote] Image Adjustment = Contrast +
[Nikon Makernote] CCD Sensitivity = ISO80
[Nikon Makernote] White Balance = Auto
[Nikon Makernote] Focus = 0
[Nikon Makernote] Makernote Unknown 2 =
[Nikon Makernote] Digital Zoom = No digital zoom
[Nikon Makernote] Fisheye Converter = None
[Nikon Makernote] Makernote Unknown 3 = 0 0 16777216 0 -1609193200 0 34833 6931 16178 4372 4372 -972290529 -921882880 15112 0 0 1151495 252903424 17 0 0 844038208 55184128 218129428 1476410198 370540566 -250604010 16711749 204629079 1729
*/
public void testNikonMakernote_MatchesKnownValues() throws Exception
{
assertTrue(_nikonDirectory.getTagCount() > 0);
assertEquals(8, _nikonDirectory.getDouble(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_1), 0.0001);
assertEquals(12, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY));
assertEquals(1, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE));
assertEquals(3, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT));
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY));
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE));
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS));
assertEquals("", _nikonDirectory.getString(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_2));
assertEquals(0, _nikonDirectory.getDouble(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM), 0.0001);
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER));
int[] unknown3 = _nikonDirectory.getIntArray(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_3);
int[] expected = new int[] { 0, 0, 16777216, 0, -1609193200, 0, 34833, 6931, 16178, 4372, 4372, -972290529, -921882880, 15112, 0, 0, 1151495, 252903424, 17, 0, 0, 844038208, 55184128, 218129428, 1476410198, 370540566, -250604010, 16711749, 204629079, 1729 };
assertEquals(expected.length, unknown3.length);
for (int i = 0; i<expected.length; i++) {
assertEquals(expected[i], unknown3[i]);
}
}
 
/*
[Exif] Image Description =
[Exif] Make = NIKON
[Exif] Model = E950
[Exif] Orientation = top, left side
[Exif] X Resolution = 300 dots per inch
[Exif] Y Resolution = 300 dots per inch
[Exif] Resolution Unit = Inch
[Exif] Software = v981-79
[Exif] Date/Time = 2001:04:06 11:51:40
[Exif] YCbCr Positioning = Datum point
[Exif] Exposure Time = 1/77 sec
[Exif] F-Number = F5.5
[Exif] Exposure Program = Program normal
[Exif] ISO Speed Ratings = 80
[Exif] Exif Version = 2.10
[Exif] Date/Time Original = 2001:04:06 11:51:40
[Exif] Date/Time Digitized = 2001:04:06 11:51:40
[Exif] Components Configuration = YCbCr
[Exif] Compressed Bits Per Pixel = 4 bits/pixel
[Exif] Exposure Bias Value = 0
[Exif] Max Aperture Value = F2.5
[Exif] Metering Mode = Multi-segment
[Exif] Light Source = Unknown
[Exif] Flash = No flash fired
[Exif] Focal Length = 12.8 mm
[Exif] User Comment =
[Exif] FlashPix Version = 1.00
[Exif] Color Space = sRGB
[Exif] Exif Image Width = 1600 pixels
[Exif] Exif Image Height = 1200 pixels
[Exif] File Source = Digital Still Camera (DSC)
[Exif] Scene Type = Directly photographed image
[Exif] Compression = JPEG compression
[Exif] Thumbnail Offset = 2036 bytes
[Exif] Thumbnail Length = 4662 bytes
[Exif] Thumbnail Data = [4662 bytes of thumbnail data]
*/
public void testExifDirectory_MatchesKnownValues() throws Exception
{
assertEquals(" ", _exifDirectory.getString(ExifDirectory.TAG_IMAGE_DESCRIPTION));
assertEquals("NIKON", _exifDirectory.getString(ExifDirectory.TAG_MAKE));
assertEquals("E950", _exifDirectory.getString(ExifDirectory.TAG_MODEL));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_ORIENTATION));
assertEquals(300, _exifDirectory.getDouble(ExifDirectory.TAG_X_RESOLUTION), 0.001);
assertEquals(300, _exifDirectory.getDouble(ExifDirectory.TAG_Y_RESOLUTION), 0.001);
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT));
assertEquals("v981-79", _exifDirectory.getString(ExifDirectory.TAG_SOFTWARE));
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME));
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING));
assertEquals(new Rational(1, 77), _exifDirectory.getRational(ExifDirectory.TAG_EXPOSURE_TIME));
assertEquals(5.5, _exifDirectory.getDouble(ExifDirectory.TAG_FNUMBER), 0.001);
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM));
assertEquals(80, _exifDirectory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT));
assertEquals("48 50 49 48", _exifDirectory.getString(ExifDirectory.TAG_EXIF_VERSION));
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED));
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL));
assertEquals("1 2 3 0", _exifDirectory.getString(ExifDirectory.TAG_COMPONENTS_CONFIGURATION));
assertEquals(4, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION_LEVEL));
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_BIAS));
// this 2.6 *apex*, which is F2.5
assertEquals(2.6, _exifDirectory.getDouble(ExifDirectory.TAG_MAX_APERTURE), 0.001);
assertEquals(5, _exifDirectory.getInt(ExifDirectory.TAG_METERING_MODE));
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_WHITE_BALANCE));
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_FLASH));
assertEquals(12.8, _exifDirectory.getDouble(ExifDirectory.TAG_FOCAL_LENGTH), 0.001);
assertEquals("0 0 0 0 0 0 0 0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32", _exifDirectory.getString(ExifDirectory.TAG_USER_COMMENT));
assertEquals("48 49 48 48", _exifDirectory.getString(ExifDirectory.TAG_FLASHPIX_VERSION));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_COLOR_SPACE));
assertEquals(1600, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH));
assertEquals(1200, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT));
assertEquals(3, _exifDirectory.getInt(ExifDirectory.TAG_FILE_SOURCE));
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_SCENE_TYPE));
assertEquals(6, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION));
assertEquals(2036, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET));
assertEquals(4662, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType2a.metadata
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType2b.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifReaderTest.java
0,0 → 1,183
/*
* ExifReaderTest.java
*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Oct-2002 19:15:16 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.ExifReader;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
* JUnit test case for class ExifReader.
* @author Drew Noakes http://drewnoakes.com
*/
public class ExifReaderTest extends TestCase
{
public ExifReaderTest(String s)
{
super(s);
}
 
public void testLoadFujiFilmJpeg() throws Exception
{
String jpegWithExif = "src/com/drew/metadata/exif/test/withExif.jpg";
Metadata metadata = new ExifReader(new File(jpegWithExif)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals("80", directory.getDescription(ExifDirectory.TAG_ISO_EQUIVALENT));
// TODO decide if this should still be returned -- it was being calculated upon setting of a related tag
// assertEquals("F9", directory.getDescription(ExifDirectory.TAG_APERTURE));
}
 
public void testLoadJpegWithoutExifData() throws Exception
{
String jpegNoExif = "src/com/drew/metadata/exif/test/noExif.jpg";
Metadata metadata = new ExifReader(new File(jpegNoExif)).extract();
assertTrue(!metadata.containsDirectory(ExifDirectory.class));
}
 
public void testLoadJpegWithBadExifData() throws Exception
{
// This test used to ensure an exception was thrown when loading a particular jpeg
// The intention has since changed, and the API should only throw exceptions in completely
// fatal situations. Now, the Metadata object returned has no new tags.
String jpegBadExif = "src/com/drew/metadata/exif/test/badExif.jpg"; // Exif data segment doesn't begin with 'Exif'
Metadata metadata = new ExifReader(new File(jpegBadExif)).extract();
assertEquals(0, metadata.getDirectory(ExifDirectory.class).getTagCount());
}
 
public void testCrashRegressionTest() throws Exception
{
// this image was created via a resize in ACDSee
// it seems to have a reference to an IFD starting outside the data segment
// i've noticed that ACDSee reports a Comment for this image, yet ExifReader doesn't report one
String fileName = "src/com/drew/metadata/exif/test/crash01.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
assertTrue(metadata.getDirectory(ExifDirectory.class).getTagCount() > 0);
}
 
public void testThumbnailOffset() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals(192, directory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET));
}
 
public void testThumbnailLength() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals(2970, directory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH));
}
 
public void testDateTime() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals("2002:11:27 18:00:35", directory.getString(ExifDirectory.TAG_DATETIME));
}
 
public void testXResolution() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
Rational rational = directory.getRational(ExifDirectory.TAG_X_RESOLUTION);
assertEquals(72, rational.getNumerator());
assertEquals(1, rational.getDenominator());
}
 
public void testYResolution() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
Rational rational = directory.getRational(ExifDirectory.TAG_Y_RESOLUTION);
assertEquals(72, rational.getNumerator());
assertEquals(1, rational.getDenominator());
}
 
public void testCompression() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg";
Metadata metadata = new ExifReader(new File(fileName)).extract();
Directory directory = metadata.getDirectory(ExifDirectory.class);
// 6 means JPEG compression
assertEquals(6, directory.getInt(ExifDirectory.TAG_COMPRESSION));
}
 
public void testStackOverflowOnRevisitationOfSameDirectory() throws Exception
{
// an error has been discovered in Exif data segments where a directory is referenced
// repeatedly. thanks to Alistair Dickie for providing the sample image used in this
// unit test.
File metadataFile = new File("src/com/drew/metadata/exif/test/recursiveDirectories.metadata");
Metadata metadata = new ExifReader(JpegSegmentData.FromFile(metadataFile)).extract();
metadata.getDirectory(ExifDirectory.class);
// String fileName = "src/com/drew/metadata/exif/test/recursiveDirectories.jpg";
// Metadata metadata = new ExifReader(new File(fileName)).extract();
// metadata.getDirectory(ExifDirectory.class);
}
 
 
/*
public void testUncompressedYCbCrThumbnail() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.jpg";
String thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.bmp";
Metadata metadata = new ExifReader(new File(fileName)).extract();
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
directory.writeThumbnail(thumnailFileName);
 
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.jpg";
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.bmp";
metadata = new ExifReader(new File(fileName)).extract();
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
directory.writeThumbnail(thumnailFileName);
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.jpg";
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.bmp";
metadata = new ExifReader(new File(fileName)).extract();
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
directory.writeThumbnail(thumnailFileName);
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.jpg";
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.bmp";
metadata = new ExifReader(new File(fileName)).extract();
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
directory.writeThumbnail(thumnailFileName);
}
 
public void testUncompressedRGBThumbnail() throws Exception
{
String fileName = "src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.jpg";
String thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.bmp";
Metadata metadata = new ExifReader(new File(fileName)).extract();
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
directory.writeThumbnail(thumnailFileName);
}
*/
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifDirectoryTest.java
0,0 → 1,87
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA.
*/
package com.drew.metadata.exif.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class ExifDirectoryTest extends TestCase
{
public ExifDirectoryTest(String s)
{
super(s);
}
 
public void testGetDirectoryName() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(ExifDirectory.class);
assertEquals("Exif", directory.getName());
}
 
public void testGetThumbnailData() throws Exception
{
File file = new File("src/com/drew/metadata/exif/test/withExif.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(file);
ExifDirectory exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
assertTrue(exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA));
byte[] thumbData = exifDirectory.getThumbnailData();
try {
// attempt to read the thumbnail -- it should be a legal Jpeg file
new JpegSegmentReader(thumbData);
} catch (JpegProcessingException e) {
fail("Unable to construct JpegSegmentReader from thumbnail data");
}
}
 
public void testWriteThumbnail() throws Exception
{
File file = new File("src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg");
Metadata metadata = JpegMetadataReader.readMetadata(file);
ExifDirectory exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class);
assertTrue(exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA));
 
File thumbnailFile = File.createTempFile("thumbnail", ".jpg");
try {
exifDirectory.writeThumbnail(thumbnailFile.getAbsolutePath());
assertTrue(new File(thumbnailFile.getAbsolutePath()).exists());
} finally {
thumbnailFile.delete();
}
}
 
public void testContainsThumbnail()
{
ExifDirectory exifDirectory = new ExifDirectory();
 
assertTrue(!exifDirectory.containsThumbnail());
 
exifDirectory.setObject(ExifDirectory.TAG_THUMBNAIL_DATA, "foo");
 
assertTrue(exifDirectory.containsThumbnail());
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/FujifilmMakernoteDirectory.java
0,0 → 1,85
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class FujifilmMakernoteDirectory extends Directory
{
public static final int TAG_FUJIFILM_MAKERNOTE_VERSION = 0x0000;
public static final int TAG_FUJIFILM_QUALITY = 0x1000;
public static final int TAG_FUJIFILM_SHARPNESS = 0x1001;
public static final int TAG_FUJIFILM_WHITE_BALANCE = 0x1002;
public static final int TAG_FUJIFILM_COLOR = 0x1003;
public static final int TAG_FUJIFILM_TONE = 0x1004;
public static final int TAG_FUJIFILM_FLASH_MODE = 0x1010;
public static final int TAG_FUJIFILM_FLASH_STRENGTH = 0x1011;
public static final int TAG_FUJIFILM_MACRO = 0x1020;
public static final int TAG_FUJIFILM_FOCUS_MODE = 0x1021;
public static final int TAG_FUJIFILM_SLOW_SYNCHRO = 0x1030;
public static final int TAG_FUJIFILM_PICTURE_MODE = 0x1031;
public static final int TAG_FUJIFILM_UNKNOWN_1 = 0x1032;
public static final int TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING = 0x1100;
public static final int TAG_FUJIFILM_UNKNOWN_2 = 0x1200;
public static final int TAG_FUJIFILM_BLUR_WARNING = 0x1300;
public static final int TAG_FUJIFILM_FOCUS_WARNING = 0x1301;
public static final int TAG_FUJIFILM_AE_WARNING = 0x1302;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_FUJIFILM_AE_WARNING), "AE Warning");
tagNameMap.put(new Integer(TAG_FUJIFILM_BLUR_WARNING), "Blur Warning");
tagNameMap.put(new Integer(TAG_FUJIFILM_COLOR), "Color");
tagNameMap.put(new Integer(TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING), "Continuous Taking Or Auto Bracketting");
tagNameMap.put(new Integer(TAG_FUJIFILM_FLASH_MODE), "Flash Mode");
tagNameMap.put(new Integer(TAG_FUJIFILM_FLASH_STRENGTH), "Flash Strength");
tagNameMap.put(new Integer(TAG_FUJIFILM_FOCUS_MODE), "Focus Mode");
tagNameMap.put(new Integer(TAG_FUJIFILM_FOCUS_WARNING), "Focus Warning");
tagNameMap.put(new Integer(TAG_FUJIFILM_MACRO), "Macro");
tagNameMap.put(new Integer(TAG_FUJIFILM_MAKERNOTE_VERSION), "Makernote Version");
tagNameMap.put(new Integer(TAG_FUJIFILM_PICTURE_MODE), "Picture Mode");
tagNameMap.put(new Integer(TAG_FUJIFILM_QUALITY), "Quality");
tagNameMap.put(new Integer(TAG_FUJIFILM_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_FUJIFILM_SLOW_SYNCHRO), "Slow Synchro");
tagNameMap.put(new Integer(TAG_FUJIFILM_TONE), "Tone");
tagNameMap.put(new Integer(TAG_FUJIFILM_UNKNOWN_1), "Makernote Unknown 1");
tagNameMap.put(new Integer(TAG_FUJIFILM_UNKNOWN_2), "Makernote Unknown 2");
tagNameMap.put(new Integer(TAG_FUJIFILM_WHITE_BALANCE), "White Balance");
}
 
public FujifilmMakernoteDirectory()
{
this.setDescriptor(new FujifilmMakernoteDescriptor(this));
}
 
public String getName()
{
return "FujiFilm Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KyoceraMakernoteDescriptor.java
0,0 → 1,63
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a KyoceraMakernoteDirectory.
*
* Some information about this makernote taken from here:
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html
*
* Most manufacturer's MakerNote counts the "offset to data" from the first byte
* of TIFF header (same as the other IFD), but Kyocera (along with Fujifilm) counts
* it from the first byte of MakerNote itself.
*/
public class KyoceraMakernoteDescriptor extends TagDescriptor
{
public KyoceraMakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO:
return getPrintImageMatchingInfoDescription();
case KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL:
return getProprietaryThumbnailDataDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getPrintImageMatchingInfoDescription() throws MetadataException
{
if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO)) return null;
byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO);
return "(" + bytes.length + " bytes)";
}
 
public String getProprietaryThumbnailDataDescription() throws MetadataException
{
if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL)) return null;
byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL);
return "(" + bytes.length + " bytes)";
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/OlympusMakernoteDirectory.java
0,0 → 1,360
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
* The Olympus makernote is used by many manufacturers, and as such contains some tags that appear specific to
* those manufacturers. Other users include Konica, Minolta and Epson.
*/
public class OlympusMakernoteDirectory extends Directory
{
/**
* Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_MAKERNOTE_VERSION = 0x0000;
 
/**
* Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_CAMERA_SETTINGS_1 = 0x0001;
 
/**
* Alternate Camera Settings Tag. Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_CAMERA_SETTINGS_2 = 0x0003;
 
/**
* Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE = 0x0040;
 
/**
* Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1 = 0x0081;
 
/**
* Alternate Thumbnail Offset. Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2 = 0x0088;
 
/**
* Length of thumbnail in bytes. Used by Konica / Minolta cameras.
*/
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH = 0x0089;
 
/**
* Used by Konica / Minolta cameras
* 0 = Natural Colour
* 1 = Black & White
* 2 = Vivid colour
* 3 = Solarization
* 4 = AdobeRGB
*/
public static final int TAG_OLYMPUS_COLOUR_MODE = 0x0101;
 
/**
* Used by Konica / Minolta cameras.
* 0 = Raw
* 1 = Super Fine
* 2 = Fine
* 3 = Standard
* 4 = Extra Fine
*/
public static final int TAG_OLYMPUS_IMAGE_QUALITY_1 = 0x0102;
 
/**
* Not 100% sure about this tag.
*
* Used by Konica / Minolta cameras.
* 0 = Raw
* 1 = Super Fine
* 2 = Fine
* 3 = Standard
* 4 = Extra Fine
*/
public static final int TAG_OLYMPUS_IMAGE_QUALITY_2 = 0x0103;
 
 
/**
* Three values:
* Value 1: 0=Normal, 2=Fast, 3=Panorama
* Value 2: Sequence Number Value 3:
* 1 = Panorama Direction: Left to Right
* 2 = Panorama Direction: Right to Left
* 3 = Panorama Direction: Bottom to Top
* 4 = Panorama Direction: Top to Bottom
*/
public static final int TAG_OLYMPUS_SPECIAL_MODE = 0x0200;
 
/**
* 1 = Standard Quality
* 2 = High Quality
* 3 = Super High Quality
*/
public static final int TAG_OLYMPUS_JPEG_QUALITY = 0x0201;
 
/**
* 0 = Normal (Not Macro)
* 1 = Macro
*/
public static final int TAG_OLYMPUS_MACRO_MODE = 0x0202;
 
/**
*
*/
public static final int TAG_OLYMPUS_UNKNOWN_1 = 0x0203;
 
/**
* Zoom Factor (0 or 1 = normal)
*/
public static final int TAG_OLYMPUS_DIGI_ZOOM_RATIO = 0x0204;
 
/**
*
*/
public static final int TAG_OLYMPUS_UNKNOWN_2 = 0x0205;
 
/**
*
*/
public static final int TAG_OLYMPUS_UNKNOWN_3 = 0x0206;
 
/**
*
*/
public static final int TAG_OLYMPUS_FIRMWARE_VERSION = 0x0207;
 
/**
*
*/
public static final int TAG_OLYMPUS_PICT_INFO = 0x0208;
 
/**
*
*/
public static final int TAG_OLYMPUS_CAMERA_ID = 0x0209;
 
/**
* Used by Epson cameras
* Units = pixels
*/
public static final int TAG_OLYMPUS_IMAGE_WIDTH = 0x020B;
 
/**
* Used by Epson cameras
* Units = pixels
*/
public static final int TAG_OLYMPUS_IMAGE_HEIGHT = 0x020C;
 
/**
* A string. Used by Epson cameras.
*/
public static final int TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL = 0x020D;
 
/**
* See the PIM specification here:
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html
*/
public static final int TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO = 0x0E00;
 
/**
*
*/
public static final int TAG_OLYMPUS_DATA_DUMP = 0x0F00;
 
/**
*
*/
public static final int TAG_OLYMPUS_FLASH_MODE = 0x1004;
 
/**
*
*/
public static final int TAG_OLYMPUS_BRACKET = 0x1006;
 
/**
*
*/
public static final int TAG_OLYMPUS_FOCUS_MODE = 0x100B;
 
/**
*
*/
public static final int TAG_OLYMPUS_FOCUS_DISTANCE = 0x100C;
 
/**
*
*/
public static final int TAG_OLYMPUS_ZOOM = 0x100D;
 
/**
*
*/
public static final int TAG_OLYMPUS_MACRO_FOCUS = 0x100E;
 
/**
*
*/
public static final int TAG_OLYMPUS_SHARPNESS = 0x100F;
 
/**
*
*/
public static final int TAG_OLYMPUS_COLOUR_MATRIX = 0x1011;
 
/**
*
*/
public static final int TAG_OLYMPUS_BLACK_LEVEL = 0x1012;
 
/**
*
*/
public static final int TAG_OLYMPUS_WHITE_BALANCE = 0x1015;
 
/**
*
*/
public static final int TAG_OLYMPUS_RED_BIAS = 0x1017;
 
/**
*
*/
public static final int TAG_OLYMPUS_BLUE_BIAS = 0x1018;
 
/**
*
*/
public static final int TAG_OLYMPUS_SERIAL_NUMBER = 0x101A;
 
/**
*
*/
public static final int TAG_OLYMPUS_FLASH_BIAS = 0x1023;
 
/**
*
*/
public static final int TAG_OLYMPUS_CONTRAST = 0x1029;
 
/**
*
*/
public static final int TAG_OLYMPUS_SHARPNESS_FACTOR = 0x102A;
 
/**
*
*/
public static final int TAG_OLYMPUS_COLOUR_CONTROL = 0x102B;
 
/**
*
*/
public static final int TAG_OLYMPUS_VALID_BITS = 0x102C;
 
/**
*
*/
public static final int TAG_OLYMPUS_CORING_FILTER = 0x102D;
 
/**
*
*/
public static final int TAG_OLYMPUS_FINAL_WIDTH = 0x102E;
 
/**
*
*/
public static final int TAG_OLYMPUS_FINAL_HEIGHT = 0x102F;
 
/**
*
*/
public static final int TAG_OLYMPUS_COMPRESSION_RATIO = 0x1034;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_OLYMPUS_SPECIAL_MODE), "Special Mode");
tagNameMap.put(new Integer(TAG_OLYMPUS_JPEG_QUALITY), "Jpeg Quality");
tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_MODE), "Macro");
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_1), "Makernote Unknown 1");
tagNameMap.put(new Integer(TAG_OLYMPUS_DIGI_ZOOM_RATIO), "DigiZoom Ratio");
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_2), "Makernote Unknown 2");
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_3), "Makernote Unknown 3");
tagNameMap.put(new Integer(TAG_OLYMPUS_FIRMWARE_VERSION), "Firmware Version");
tagNameMap.put(new Integer(TAG_OLYMPUS_PICT_INFO), "Pict Info");
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_ID), "Camera Id");
tagNameMap.put(new Integer(TAG_OLYMPUS_DATA_DUMP), "Data Dump");
tagNameMap.put(new Integer(TAG_OLYMPUS_MAKERNOTE_VERSION), "Makernote Version");
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_1), "Camera Settings");
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_2), "Camera Settings");
tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE), "Compressed Image Size");
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1), "Thumbnail Offset");
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2), "Thumbnail Offset");
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH), "Thumbnail Length");
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MODE), "Colour Mode");
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_1), "Image Quality");
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_2), "Image Quality");
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_HEIGHT), "Image Height");
tagNameMap.put(new Integer(TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL), "Original Manufacturer Model");
tagNameMap.put(new Integer(TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_MODE), "Flash Mode");
tagNameMap.put(new Integer(TAG_OLYMPUS_BRACKET), "Bracket");
tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_MODE), "Focus Mode");
tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_DISTANCE), "Focus Distance");
tagNameMap.put(new Integer(TAG_OLYMPUS_ZOOM), "Zoom");
tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_FOCUS), "Macro Focus");
tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS), "Sharpness");
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MATRIX), "Colour Matrix");
tagNameMap.put(new Integer(TAG_OLYMPUS_BLACK_LEVEL), "Black Level");
tagNameMap.put(new Integer(TAG_OLYMPUS_WHITE_BALANCE), "White Balance");
tagNameMap.put(new Integer(TAG_OLYMPUS_RED_BIAS), "Red Bias");
tagNameMap.put(new Integer(TAG_OLYMPUS_BLUE_BIAS), "Blue Bias");
tagNameMap.put(new Integer(TAG_OLYMPUS_SERIAL_NUMBER), "Serial Number");
tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_BIAS), "Flash Bias");
tagNameMap.put(new Integer(TAG_OLYMPUS_CONTRAST), "Contrast");
tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS_FACTOR), "Sharpness Factor");
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_CONTROL), "Colour Control");
tagNameMap.put(new Integer(TAG_OLYMPUS_VALID_BITS), "Valid Bits");
tagNameMap.put(new Integer(TAG_OLYMPUS_CORING_FILTER), "Coring Filter");
tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_WIDTH), "Final Width");
tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_HEIGHT), "Final Height");
tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSION_RATIO), "Compression Ratio");
}
 
public OlympusMakernoteDirectory()
{
this.setDescriptor(new OlympusMakernoteDescriptor(this));
}
 
public String getName()
{
return "Olympus Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PanasonicMakernoteDirectory.java
0,0 → 1,68
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA.
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class PanasonicMakernoteDirectory extends Directory
{
public static final int TAG_PANASONIC_QUALITY_MODE = 0x0001;
public static final int TAG_PANASONIC_VERSION = 0x0002;
/**
* 1 = On
* 2 = Off
*/
public static final int TAG_PANASONIC_MACRO_MODE = 0x001C;
/**
* 1 = Normal
* 2 = Portrait
* 9 = Macro
*/
public static final int TAG_PANASONIC_RECORD_MODE = 0x001F;
public static final int TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO = 0x0E00;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_PANASONIC_QUALITY_MODE), "Quality Mode");
tagNameMap.put(new Integer(TAG_PANASONIC_VERSION), "Version");
tagNameMap.put(new Integer(TAG_PANASONIC_MACRO_MODE), "Macro Mode");
tagNameMap.put(new Integer(TAG_PANASONIC_RECORD_MODE), "Record Mode");
tagNameMap.put(new Integer(TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info");
}
 
public PanasonicMakernoteDirectory()
{
this.setDescriptor(new PanasonicMakernoteDescriptor(this));
}
 
public String getName()
{
return "Panasonic Makernote";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType1MakernoteDescriptor.java
0,0 → 1,197
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a NikonType1MakernoteDirectory.
* Type-1 is for E-Series cameras prior to (not including) E990. For example: E700, E800, E900,
* E900S, E910, E950.
*
* MakerNote starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from
* offset 0x08. This is the same as Olympus except start string. Example of actual data
* structure is shown below.
* <pre><code>
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon...........
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................
* </code></pre>
*/
public class NikonType1MakernoteDescriptor extends TagDescriptor
{
public NikonType1MakernoteDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType) {
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY:
return getQualityDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE:
return getColorModeDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT:
return getImageAdjustmentDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY:
return getCcdSensitivityDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE:
return getWhiteBalanceDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS:
return getFocusDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER:
return getConverterDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getConverterDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER);
switch (value) {
case 0:
return "None";
case 1:
return "Fisheye converter";
default:
return "Unknown (" + value + ")";
}
}
 
public String getDigitalZoomDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM)) return null;
Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM);
if (value.getNumerator() == 0) {
return "No digital zoom";
}
return value.toSimpleString(true) + "x digital zoom";
}
 
public String getFocusDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS)) return null;
Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS);
if (value.getNumerator() == 1 && value.getDenominator() == 0) {
return "Infinite";
}
return value.toSimpleString(true);
}
 
public String getWhiteBalanceDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE);
switch (value) {
case 0:
return "Auto";
case 1:
return "Preset";
case 2:
return "Daylight";
case 3:
return "Incandescense";
case 4:
return "Flourescence";
case 5:
return "Cloudy";
case 6:
return "SpeedLight";
default:
return "Unknown (" + value + ")";
}
}
 
public String getCcdSensitivityDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY);
switch (value) {
case 0:
return "ISO80";
case 2:
return "ISO160";
case 4:
return "ISO320";
case 5:
return "ISO100";
default:
return "Unknown (" + value + ")";
}
}
 
public String getImageAdjustmentDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT);
switch (value) {
case 0:
return "Normal";
case 1:
return "Bright +";
case 2:
return "Bright -";
case 3:
return "Contrast +";
case 4:
return "Contrast -";
default:
return "Unknown (" + value + ")";
}
}
 
public String getColorModeDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE);
switch (value) {
case 1:
return "Color";
case 2:
return "Monochrome";
default:
return "Unknown (" + value + ")";
}
}
 
public String getQualityDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY)) return null;
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY);
switch (value) {
case 1:
return "VGA Basic";
case 2:
return "VGA Normal";
case 3:
return "VGA Fine";
case 4:
return "SXGA Basic";
case 5:
return "SXGA Normal";
case 6:
return "SXGA Fine";
default:
return "Unknown (" + value + ")";
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType2MakernoteDescriptor.java
0,0 → 1,169
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.exif;
 
import com.drew.lang.Rational;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
import java.text.DecimalFormat;
 
/**
* Provides human-readable string versions of the tags stored in a NikonType2MakernoteDirectory.
* Type-2 applies to the E990 and D-series cameras such as the D1, D70 and D100.
*/
public class NikonType2MakernoteDescriptor extends TagDescriptor
{
public NikonType2MakernoteDescriptor(Directory directory)
{
super(directory);
}
 
private NikonType2MakernoteDirectory getMakernoteDirectory()
{
return (NikonType2MakernoteDirectory)_directory;
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType)
{
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS:
return getLensDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT:
return getHueAdjustmentDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE:
return getColorModeDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION:
return getAutoFlashCompensationDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1:
return getIsoSettingDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM:
return getDigitalZoomDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION:
return getAutoFocusPositionDescription();
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION:
return getAutoFirmwareVersionDescription();
default:
return _directory.getString(tagType);
}
}
 
public String getAutoFocusPositionDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION)) return null;
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION);
if (values.length != 4 || values[0] != 0 || values[2] != 0 || values[3] != 0) {
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION) + ")";
}
switch (values[1]) {
case 0:
return "Centre";
case 1:
return "Top";
case 2:
return "Bottom";
case 3:
return "Left";
case 4:
return "Right";
default:
return "Unknown (" + values[1] + ")";
}
}
 
public String getDigitalZoomDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM)) return null;
Rational rational = _directory.getRational(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM);
if (rational.intValue() == 1) {
return "No digital zoom";
}
return rational.toSimpleString(true) + "x digital zoom";
}
 
public String getIsoSettingDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1)) return null;
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1);
if (values[0] != 0 || values[1] == 0) {
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1) + ")";
}
return "ISO " + values[1];
}
 
public String getAutoFlashCompensationDescription() throws MetadataException
{
Rational ev = getMakernoteDirectory().getAutoFlashCompensation();
 
if (ev==null)
return "Unknown";
 
DecimalFormat decimalFormat = new DecimalFormat("0.##");
return decimalFormat.format(ev.floatValue()) + " EV";
}
 
public String getLensDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS))
return null;
 
Rational[] lensValues = _directory.getRationalArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS);
 
if (lensValues.length!=4)
return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS);
 
StringBuffer description = new StringBuffer();
description.append(lensValues[0].intValue());
description.append('-');
description.append(lensValues[1].intValue());
description.append("mm f/");
description.append(lensValues[2].floatValue());
description.append('-');
description.append(lensValues[3].floatValue());
 
return description.toString();
}
 
public String getHueAdjustmentDescription()
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT))
return null;
 
return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT) + " degrees";
}
 
public String getColorModeDescription()
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE))
return null;
 
String raw = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE);
if (raw.startsWith("MODE1"))
return "Mode I (sRGB)";
 
return raw;
}
 
public String getAutoFirmwareVersionDescription() throws MetadataException
{
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION))
return null;
 
int[] ints = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION);
return ExifDescriptor.convertBytesToVersionString(ints);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifProcessingException.java
0,0 → 1,50
/*
* ExifProcessingException.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on 29 April 2002, 00:33
*/
package com.drew.metadata.exif;
 
import com.drew.metadata.MetadataException;
 
/**
* The exception type raised during reading of Exif data in the instance of
* unexpected data conditions.
* @author Drew Noakes http://drewnoakes.com
*/
public class ExifProcessingException extends MetadataException
{
/**
* Constructs an instance of <code>ExifProcessingException</code> with the
* specified detail message.
* @param message the detail message
*/
public ExifProcessingException(String message)
{
super(message);
}
 
/**
* Constructs an instance of <code>ExifProcessingException</code> with the
* specified detail message and inner exception.
* @param message the detail message
* @param cause an inner exception
*/
public ExifProcessingException(String message, Throwable cause)
{
super(message, cause);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/DefaultTagDescriptor.java
0,0 → 1,40
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 22-Nov-2002 16:45:19 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
/**
*
*/
public class DefaultTagDescriptor extends TagDescriptor
{
public DefaultTagDescriptor(Directory directory)
{
super(directory);
}
 
public String getTagName(int tagType)
{
String hex = Integer.toHexString(tagType).toUpperCase();
while (hex.length() < 4) hex = "0" + hex;
return "Unknown tag 0x" + hex;
}
 
public String getDescription(int tagType)
{
return _directory.getString(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/MetadataException.java
0,0 → 1,40
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 13-Nov-2002 18:10:23 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
import com.drew.lang.CompoundException;
 
/**
*
*/
public class MetadataException extends CompoundException
{
public MetadataException(String msg)
{
super(msg);
}
 
public MetadataException(Throwable exception)
{
super(exception);
}
 
public MetadataException(String msg, Throwable innerException)
{
super(msg, innerException);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/id3/test/TestTrack01-Artwork.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcDirectory.java
0,0 → 1,97
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Nov-2002 01:26:39 using IntelliJ IDEA.
*/
package com.drew.metadata.iptc;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
*/
public class IptcDirectory extends Directory
{
public static final int TAG_RECORD_VERSION = 0x0200;
public static final int TAG_CAPTION = 0x0278;
public static final int TAG_WRITER = 0x027a;
public static final int TAG_HEADLINE = 0x0269;
public static final int TAG_SPECIAL_INSTRUCTIONS = 0x0228;
public static final int TAG_BY_LINE = 0x0250;
public static final int TAG_BY_LINE_TITLE = 0x0255;
public static final int TAG_CREDIT = 0x026e;
public static final int TAG_SOURCE = 0x0273;
public static final int TAG_OBJECT_NAME = 0x0205;
public static final int TAG_DATE_CREATED = 0x0237;
public static final int TAG_CITY = 0x025a;
public static final int TAG_PROVINCE_OR_STATE = 0x025f;
public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION = 0x0265;
public static final int TAG_ORIGINAL_TRANSMISSION_REFERENCE = 0x0267;
public static final int TAG_CATEGORY = 0x020f;
public static final int TAG_SUPPLEMENTAL_CATEGORIES = 0x0214;
public static final int TAG_URGENCY = 0x0200 | 10;
public static final int TAG_KEYWORDS = 0x0200 | 25;
public static final int TAG_COPYRIGHT_NOTICE = 0x0274;
public static final int TAG_RELEASE_DATE = 0x0200 | 30;
public static final int TAG_RELEASE_TIME = 0x0200 | 35;
public static final int TAG_TIME_CREATED = 0x0200 | 60;
public static final int TAG_ORIGINATING_PROGRAM = 0x0200 | 65;
 
protected static final HashMap tagNameMap = new HashMap();
 
static
{
tagNameMap.put(new Integer(TAG_RECORD_VERSION), "Directory Version");
tagNameMap.put(new Integer(TAG_CAPTION), "Caption/Abstract");
tagNameMap.put(new Integer(TAG_WRITER), "Writer/Editor");
tagNameMap.put(new Integer(TAG_HEADLINE), "Headline");
tagNameMap.put(new Integer(TAG_SPECIAL_INSTRUCTIONS), "Special Instructions");
tagNameMap.put(new Integer(TAG_BY_LINE), "By-line");
tagNameMap.put(new Integer(TAG_BY_LINE_TITLE), "By-line Title");
tagNameMap.put(new Integer(TAG_CREDIT), "Credit");
tagNameMap.put(new Integer(TAG_SOURCE), "Source");
tagNameMap.put(new Integer(TAG_OBJECT_NAME), "Object Name");
tagNameMap.put(new Integer(TAG_DATE_CREATED), "Date Created");
tagNameMap.put(new Integer(TAG_CITY), "City");
tagNameMap.put(new Integer(TAG_PROVINCE_OR_STATE), "Province/State");
tagNameMap.put(new Integer(TAG_COUNTRY_OR_PRIMARY_LOCATION), "Country/Primary Location");
tagNameMap.put(new Integer(TAG_ORIGINAL_TRANSMISSION_REFERENCE), "Original Transmission Reference");
tagNameMap.put(new Integer(TAG_CATEGORY), "Category");
tagNameMap.put(new Integer(TAG_SUPPLEMENTAL_CATEGORIES), "Supplemental Category(s)");
tagNameMap.put(new Integer(TAG_URGENCY), "Urgency");
tagNameMap.put(new Integer(TAG_KEYWORDS), "Keywords");
tagNameMap.put(new Integer(TAG_COPYRIGHT_NOTICE), "Copyright Notice");
tagNameMap.put(new Integer(TAG_RELEASE_DATE), "Release Date");
tagNameMap.put(new Integer(TAG_RELEASE_TIME), "Release Time");
tagNameMap.put(new Integer(TAG_TIME_CREATED), "Time Created");
tagNameMap.put(new Integer(TAG_ORIGINATING_PROGRAM), "Originating Program");
}
 
public IptcDirectory()
{
this.setDescriptor(new IptcDescriptor(this));
}
 
public String getName()
{
return "Iptc";
}
 
protected HashMap getTagNameMap()
{
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcProcessingException.java
0,0 → 1,51
/*
* ExifProcessingException.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on 29 April 2002, 00:33
*/
 
package com.drew.metadata.iptc;
 
import com.drew.metadata.MetadataException;
 
/**
* The exception type raised during reading of Iptc data in the instance of
* unexpected data conditions.
* @author Drew Noakes http://drewnoakes.com
*/
public class IptcProcessingException extends MetadataException
{
/**
* Constructs an instance of <code>ExifProcessingException</code> with the
* specified detail message.
* @param message the detail message
*/
public IptcProcessingException(String message)
{
super(message);
}
 
/**
* Constructs an instance of <code>IptcProcessingException</code> with the
* specified detail message and inner exception.
* @param message the detail message
* @param cause an inner exception
*/
public IptcProcessingException(String message, Throwable cause)
{
super(message, cause);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcDescriptor.java
0,0 → 1,36
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 21-Nov-2002 17:58:19 using IntelliJ IDEA.
*/
package com.drew.metadata.iptc;
 
import com.drew.metadata.Directory;
import com.drew.metadata.TagDescriptor;
 
/**
*
*/
public class IptcDescriptor extends TagDescriptor
{
public IptcDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType)
{
return _directory.getString(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/withIptc.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/IptcReaderTest.java
0,0 → 1,69
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 22-Nov-2002 08:26:26 using IntelliJ IDEA.
*/
package com.drew.metadata.iptc.test;
 
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataReader;
import com.drew.metadata.iptc.IptcDirectory;
import com.drew.metadata.iptc.IptcReader;
import junit.framework.TestCase;
 
import java.io.File;
 
/**
*
*/
public class IptcReaderTest extends TestCase
{
public IptcReaderTest(String s)
{
super(s);
}
 
public void testDescription_City() throws Exception
{
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg");
MetadataReader reader = new IptcReader(iptcFile);
Metadata metadata = reader.extract();
assertTrue(metadata.containsDirectory(IptcDirectory.class));
Directory directory = metadata.getDirectory(IptcDirectory.class);
assertEquals("City", directory.getDescription(IptcDirectory.TAG_CITY));
}
 
public void testDescription_Caption() throws Exception
{
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg");
MetadataReader reader = new IptcReader(iptcFile);
Metadata metadata = reader.extract();
assertTrue(metadata.containsDirectory(IptcDirectory.class));
Directory directory = metadata.getDirectory(IptcDirectory.class);
assertEquals("Caption", directory.getDescription(IptcDirectory.TAG_CAPTION));
}
 
public void testDescription_Category() throws Exception
{
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg");
MetadataReader reader = new IptcReader(iptcFile);
Metadata metadata = reader.extract();
assertTrue(metadata.containsDirectory(IptcDirectory.class));
Directory directory = metadata.getDirectory(IptcDirectory.class);
assertEquals("Supl. Category2 Supl. Category1 Cat", directory.getDescription(IptcDirectory.TAG_CATEGORY));
}
 
// TODO Wrap more tests around the Iptc reader
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/withIptcPhotoshop6.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcReader.java
0,0 → 1,225
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 12-Nov-2002 19:00:03 using IntelliJ IDEA.
*/
package com.drew.metadata.iptc;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.MetadataReader;
 
import java.io.File;
import java.io.InputStream;
import java.util.Date;
 
/**
*
*/
public class IptcReader implements MetadataReader
{
/*
public static final int DIRECTORY_IPTC = 2;
 
public static final int ENVELOPE_RECORD = 1;
public static final int APPLICATION_RECORD_2 = 2;
public static final int APPLICATION_RECORD_3 = 3;
public static final int APPLICATION_RECORD_4 = 4;
public static final int APPLICATION_RECORD_5 = 5;
public static final int APPLICATION_RECORD_6 = 6;
public static final int PRE_DATA_RECORD = 7;
public static final int DATA_RECORD = 8;
public static final int POST_DATA_RECORD = 9;
*/
/**
* The Iptc data segment.
*/
private final byte[] _data;
 
/**
* Creates a new IptcReader for the specified Jpeg jpegFile.
*/
public IptcReader(File jpegFile) throws JpegProcessingException
{
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_APPD));
}
 
/** Creates an IptcReader for a JPEG stream.
*
* @param is JPEG stream. Stream will be closed.
*/
public IptcReader(InputStream is) throws JpegProcessingException
{
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));
}
 
public IptcReader(byte[] data)
{
_data = data;
}
 
/**
* Performs the Exif data extraction, returning a new instance of <code>Metadata</code>.
*/
public Metadata extract()
{
return extract(new Metadata());
}
 
/**
* Performs the Exif data extraction, adding found values to the specified
* instance of <code>Metadata</code>.
*/
public Metadata extract(Metadata metadata)
{
if (_data == null) {
return metadata;
}
 
Directory directory = metadata.getDirectory(IptcDirectory.class);
 
// find start of data
int offset = 0;
try {
while (offset < _data.length - 1 && get32Bits(offset) != 0x1c02) {
offset++;
}
} catch (MetadataException e) {
directory.addError("Couldn't find start of Iptc data (invalid segment)");
return metadata;
}
 
// for each tag
while (offset < _data.length) {
// identifies start of a tag
if (_data[offset] != 0x1c) {
break;
}
// we need at least five bytes left to read a tag
if ((offset + 5) >= _data.length) {
break;
}
 
offset++;
 
int directoryType;
int tagType;
int tagByteCount;
try {
directoryType = _data[offset++];
tagType = _data[offset++];
tagByteCount = get32Bits(offset);
} catch (MetadataException e) {
directory.addError("Iptc data segment ended mid-way through tag descriptor");
return metadata;
}
offset += 2;
if ((offset + tagByteCount) > _data.length) {
directory.addError("data for tag extends beyond end of iptc segment");
break;
}
 
processTag(directory, directoryType, tagType, offset, tagByteCount);
offset += tagByteCount;
}
 
return metadata;
}
 
/**
* Returns an int calculated from two bytes of data at the specified offset (MSB, LSB).
* @param offset position within the data buffer to read first byte
* @return the 32 bit int value, between 0x0000 and 0xFFFF
*/
private int get32Bits(int offset) throws MetadataException
{
if (offset >= _data.length) {
throw new MetadataException("Attempt to read bytes from outside Iptc data buffer");
}
return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255);
}
 
/**
* This method serves as marsheller of objects for dataset. It converts from IPTC
* octets to relevant java object.
*/
private void processTag(Directory directory, int directoryType, int tagType, int offset, int tagByteCount)
{
int tagIdentifier = tagType | (directoryType << 8);
 
switch (tagIdentifier) {
case IptcDirectory.TAG_RECORD_VERSION:
// short
short shortValue = (short)((_data[offset] << 8) | _data[offset + 1]);
directory.setInt(tagIdentifier, shortValue);
return;
case IptcDirectory.TAG_URGENCY:
// byte
directory.setInt(tagIdentifier, _data[offset]);
return;
case IptcDirectory.TAG_RELEASE_DATE:
case IptcDirectory.TAG_DATE_CREATED:
// Date object
if (tagByteCount >= 8) {
String dateStr = new String(_data, offset, tagByteCount);
try {
int year = Integer.parseInt(dateStr.substring(0, 4));
int month = Integer.parseInt(dateStr.substring(4, 6)) - 1;
int day = Integer.parseInt(dateStr.substring(6, 8));
Date date = (new java.util.GregorianCalendar(year, month, day)).getTime();
directory.setDate(tagIdentifier, date);
return;
} catch (NumberFormatException e) {
// fall through and we'll store whatever was there as a String
}
}
case IptcDirectory.TAG_RELEASE_TIME:
case IptcDirectory.TAG_TIME_CREATED:
// time...
default:
// fall through
}
// If no special handling by now, treat it as a string
String str;
if (tagByteCount < 1) {
str = "";
} else {
str = new String(_data, offset, tagByteCount);
}
if (directory.containsTag(tagIdentifier)) {
String[] oldStrings;
String[] newStrings;
try {
oldStrings = directory.getStringArray(tagIdentifier);
} catch (MetadataException e) {
oldStrings = null;
}
if (oldStrings == null) {
newStrings = new String[1];
} else {
newStrings = new String[oldStrings.length + 1];
for (int i = 0; i < oldStrings.length; i++) {
newStrings[i] = oldStrings[i];
}
}
newStrings[newStrings.length - 1] = str;
directory.setStringArray(tagIdentifier, newStrings);
} else {
directory.setString(tagIdentifier, str);
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/MetadataTest.java
0,0 → 1,176
/*
* MetadataTest.java
*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Oct-2002 18:35:12 using IntelliJ IDEA.
*/
package com.drew.metadata.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.lang.NullOutputStream;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifDirectory;
import com.drew.metadata.exif.GpsDirectory;
import com.drew.metadata.iptc.IptcDirectory;
import junit.framework.TestCase;
 
import java.io.*;
import java.util.Iterator;
 
/**
* JUnit test case for class Metadata.
* @author Drew Noakes http://drewnoakes.com
*/
public class MetadataTest extends TestCase
{
public MetadataTest(String s)
{
super(s);
}
 
public void testSetAndGetSingleTag() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(ExifDirectory.class);
directory.setInt(ExifDirectory.TAG_APERTURE, 1);
assertEquals(1, directory.getInt(ExifDirectory.TAG_APERTURE));
}
 
public void testSetSameTagMultpleTimes() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(ExifDirectory.class);
directory.setInt(ExifDirectory.TAG_APERTURE, 1);
directory.setInt(ExifDirectory.TAG_APERTURE, 2);
assertEquals("setting the tag with a different value should override old value",
2, directory.getInt(ExifDirectory.TAG_APERTURE));
}
 
public void testGetDirectory() throws Exception
{
Metadata metadata = new Metadata();
assertTrue(metadata.getDirectory(ExifDirectory.class) instanceof ExifDirectory);
}
 
public void testSetAndGetMultipleTagsInSingleDirectory() throws Exception
{
Metadata metadata = new Metadata();
Directory exifDir = metadata.getDirectory(ExifDirectory.class);
exifDir.setString(ExifDirectory.TAG_APERTURE, "Tag Value");
exifDir.setString(ExifDirectory.TAG_BATTERY_LEVEL, "Another tag");
assertEquals("Tag Value", exifDir.getString(ExifDirectory.TAG_APERTURE));
assertEquals("Another tag", exifDir.getString(ExifDirectory.TAG_BATTERY_LEVEL));
}
 
public void testSetAndGetMultipleTagsInMultilpeDirectories() throws Exception
{
Metadata metadata = new Metadata();
Directory exifDir = metadata.getDirectory(ExifDirectory.class);
Directory gpsDir = metadata.getDirectory(GpsDirectory.class);
exifDir.setString(ExifDirectory.TAG_APERTURE, "ExifAperture");
exifDir.setString(ExifDirectory.TAG_BATTERY_LEVEL, "ExifBatteryLevel");
gpsDir.setString(GpsDirectory.TAG_GPS_ALTITUDE, "GpsAltitude");
gpsDir.setString(GpsDirectory.TAG_GPS_DEST_BEARING, "GpsDestBearing");
assertEquals("ExifAperture", exifDir.getString(ExifDirectory.TAG_APERTURE));
assertEquals("ExifBatteryLevel", exifDir.getString(ExifDirectory.TAG_BATTERY_LEVEL));
assertEquals("GpsAltitude", gpsDir.getString(GpsDirectory.TAG_GPS_ALTITUDE));
assertEquals("GpsDestBearing", gpsDir.getString(GpsDirectory.TAG_GPS_DEST_BEARING));
}
 
/*
public void testCountTags() throws Exception
{
Metadata info = new Metadata();
assertEquals(0, info.countTags());
 
info.setString(ExifReader.DIRECTORY_EXIF_EXIF, ExifDirectory.TAG_APERTURE, "ExifAperture");
assertEquals(1, info.countTags());
info.setString(ExifReader.DIRECTORY_EXIF_EXIF, ExifDirectory.TAG_BATTERY_LEVEL, "ExifBatteryLevel");
assertEquals(2, info.countTags());
info.setString(ExifReader.DIRECTORY_EXIF_GPS, GpsDirectory.TAG_GPS_ALTITUDE, "GpsAltitude");
assertEquals(3, info.countTags());
info.setString(ExifReader.DIRECTORY_EXIF_GPS, GpsDirectory.TAG_GPS_DEST_BEARING, "GpsDestBearing");
assertEquals(4, info.countTags());
}
*/
 
public void testContainsTag() throws Exception
{
Metadata metadata = new Metadata();
Directory exifDir = metadata.getDirectory(ExifDirectory.class);
assertTrue(!exifDir.containsTag(ExifDirectory.TAG_APERTURE));
exifDir.setString(ExifDirectory.TAG_APERTURE, "Tag Value");
assertTrue(exifDir.containsTag(ExifDirectory.TAG_APERTURE));
}
 
public void testGetNonExistantTag() throws Exception
{
Metadata metadata = new Metadata();
Directory exifDir = metadata.getDirectory(ExifDirectory.class);
assertEquals(null, exifDir.getString(ExifDirectory.TAG_APERTURE));
}
 
public void testHasErrors() throws Exception
{
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg"));
assertTrue("exif error", metadata.getDirectory(ExifDirectory.class).hasErrors());
metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/withExif.jpg"));
assertTrue("no errors", !metadata.getDirectory(ExifDirectory.class).hasErrors());
}
 
public void testGetErrors() throws Exception
{
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg"));
Iterator errors = metadata.getDirectory(ExifDirectory.class).getErrors();
assertTrue(errors.hasNext());
String error = (String) errors.next();
assertEquals("Exif data segment must contain at least 14 bytes", error);
assertTrue(!errors.hasNext());
}
 
public void testGetErrorCount() throws Exception
{
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg"));
assertEquals(1, metadata.getDirectory(ExifDirectory.class).getErrorCount());
}
 
public void testMetadataSerializable() throws Exception
{
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/test/withIptcExifGps.jpg"));
new ObjectOutputStream(new NullOutputStream()).writeObject(metadata);
}
 
public void testSerializeAndRestore() throws Exception
{
Metadata metadataWrite = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/test/withIptcExifGps.jpg"));
Metadata metadataRead;
File ser = File.createTempFile("test", "ser");
try {
// write the ser object
new ObjectOutputStream(new FileOutputStream(ser)).writeObject(metadataWrite);
// read the ser object
metadataRead = (Metadata)new ObjectInputStream(new FileInputStream(ser)).readObject();
// make sure they're equivalent
// TODO should compare the two objects via iteration of directories and tags
assertTrue(metadataRead.containsDirectory(ExifDirectory.class));
assertTrue(metadataRead.containsDirectory(IptcDirectory.class));
} finally {
ser.delete();
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/withIptcExifGps.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/SpecialTests.java
0,0 → 1,121
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 07-May-2005 12:38:18 using IntelliJ IDEA.
*/
package com.drew.metadata.test;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentData;
import com.drew.imaging.jpeg.JpegSegmentReader;
import junit.framework.TestCase;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
 
/**
*
*/
public class SpecialTests extends TestCase
{
public void testExtractMetadataToASeparateFile() throws Exception
{
String filename = "src/com/drew/metadata/exif/test/nikonMakernoteType2";
JpegSegmentData segmentData = new JpegSegmentReader(new File(filename + ".jpg")).getSegmentData();
segmentData.removeSegment(JpegSegmentReader.SEGMENT_DHT);
segmentData.removeSegment(JpegSegmentReader.SEGMENT_DQT);
segmentData.removeSegment(JpegSegmentReader.SEGMENT_SOF0);
segmentData.removeSegment(JpegSegmentReader.SEGMENT_SOI);
ObjectOutputStream outputStream = null;
try
{
outputStream = new ObjectOutputStream(new FileOutputStream(new File(filename + ".metadata")));
outputStream.writeObject(segmentData);
}
finally
{
if (outputStream!=null)
outputStream.close();
}
}
 
public void testScanFoldersForImagesThatCauseFailures() throws Exception
{
// String directory = "G:/Recovered Images/AquariumC"; // 1446 files 883 MB (done)
// String directory = "G:/Recovered Images/AquariumF"; // 25,378 files 34.4 GB
// String directory = "G:/Recovered Images/DesktopC"; // 41,518 files 8.73 GB
// String directory = "G:/Recovered Images/DesktopF"; // 8,016 files 5.11 GB (done)
// String directory = "C:/Documents and Settings/Drew/My Documents/IntelliJ Projects/MetadataExtractor/src/";
// String directory = "C:/Documents and Settings/Drew/My Documents/IntelliJ Projects/MetadataExtractor/Sample Images";
String directory = "\\\\annie\\htdocs\\drewnoakes.com\\code\\exif\\exifImages";
processDirectory(directory);
System.out.println("Complete test successfully.");
}
 
private void processDirectory(String pathName)
{
File directory = new File(pathName);
String[] directoryItems = directory.list();
if (directoryItems==null)
return;
 
for (int i=0; i<directoryItems.length; i++) {
String subItem = directoryItems[i].toLowerCase();
File file = new File(directory, subItem);
if (!file.exists())
throw new RuntimeException("World gone nuts.");
 
if (file.isDirectory())
{
processDirectory(file.getAbsolutePath());
}
else if (subItem.endsWith(".jpg") || subItem.endsWith(".jpeg"))
{
// process this item
try
{
JpegSegmentReader segmentReader = new JpegSegmentReader(file);
try
{
JpegMetadataReader.extractMetadataFromJpegSegmentReader(segmentReader);
}
catch (Throwable t)
{
// general, uncaught exception during processing of metadata
System.err.println(file + "[BadMetadata]");
System.err.println(t);
System.err.println(t.getMessage());
t.printStackTrace(System.err);
}
}
catch (JpegProcessingException e)
{
System.err.println(file + "[BadSegments]");
// this is an error in the Jpeg segment structure. we're looking for bad handling of
// metadata segments. in this case, we didn't even get a segment.
}
catch (Throwable t)
{
// general, uncaught exception during processing of jpeg segments
System.err.println(file + "[FAILURE]");
System.err.println(t);
System.err.println(t.getMessage());
t.printStackTrace(System.err);
}
}
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/DirectoryTest.java
0,0 → 1,109
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 29-Nov-2002 08:40:07 using IntelliJ IDEA.
*/
package com.drew.metadata.test;
 
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import junit.framework.TestCase;
 
import java.util.GregorianCalendar;
 
/**
*
*/
public class DirectoryTest extends TestCase
{
public DirectoryTest(String s)
{
super(s);
}
 
public void testSetAndGetInt() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(MockDirectory.class);
int value = 321;
int tagType = 123;
directory.setInt(tagType, value);
assertEquals(value, directory.getInt(tagType));
assertEquals(Integer.toString(value), directory.getString(tagType));
}
 
public void testSetAndGetIntArray() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(MockDirectory.class);
int[] inputValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int tagType = 123;
directory.setIntArray(tagType, inputValues);
int[] outputValues = directory.getIntArray(tagType);
assertEquals(inputValues.length, outputValues.length);
for (int i = 0; i < inputValues.length; i++) {
int inputValue = inputValues[i];
int outputValue = outputValues[i];
assertEquals(inputValue, outputValue);
}
assertEquals(inputValues, directory.getIntArray(tagType));
StringBuffer outputString = new StringBuffer();
for (int i = 0; i < inputValues.length; i++) {
int inputValue = inputValues[i];
if (i > 0) {
outputString.append(' ');
}
outputString.append(inputValue);
}
assertEquals(outputString.toString(), directory.getString(tagType));
}
 
public void testSetStringAndGetDate() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(MockDirectory.class);
String date1 = "2002:01:30 24:59:59";
String date2 = "2002:01:30 24:59";
String date3 = "2002-01-30 24:59:59";
String date4 = "2002-01-30 24:59";
directory.setString(1, date1);
directory.setString(2, date2);
directory.setString(3, date3);
directory.setString(4, date4);
assertEquals(date1, directory.getString(1));
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 59).getTime(), directory.getDate(1));
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 0).getTime(), directory.getDate(2));
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 59).getTime(), directory.getDate(3));
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 0).getTime(), directory.getDate(4));
}
 
public void testSetIntArrayGetByteArray() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(MockDirectory.class);
int[] ints = {1, 2, 3, 4, 5};
directory.setIntArray(1, ints);
assertEquals(ints.length, directory.getByteArray(1).length);
assertEquals(1, directory.getByteArray(1)[0]);
}
 
public void testSetStringGetInt() throws Exception
{
Metadata metadata = new Metadata();
Directory directory = metadata.getDirectory(MockDirectory.class);
byte[] bytes = { 0x01, 0x02, 0x03 };
directory.setString(1, new String(bytes));
assertEquals(0x010203, directory.getInt(1));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/AllTests.java
0,0 → 1,75
/*
* AllTests.java
*
* Test suite class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Oct-2002 16:29:44 using IntelliJ IDEA.
* - First collection of basic unit tests, to compile against JUnit
* - Doesn't yet cover all classes
*/
package com.drew.metadata.test;
 
import com.drew.imaging.jpeg.test.JpegMetadataReaderTest;
import com.drew.imaging.jpeg.test.JpegSegmentDataTest;
import com.drew.imaging.jpeg.test.JpegSegmentReaderTest;
import com.drew.lang.test.CompoundExceptionTest;
import com.drew.lang.test.NullOutputStreamTest;
import com.drew.lang.test.RationalTest;
import com.drew.metadata.exif.test.*;
import com.drew.metadata.iptc.test.IptcReaderTest;
import com.drew.metadata.jpeg.test.JpegComponentTest;
import com.drew.metadata.jpeg.test.JpegDescriptorTest;
import com.drew.metadata.jpeg.test.JpegDirectoryTest;
import com.drew.metadata.jpeg.test.JpegReaderTest;
import junit.framework.Test;
import junit.framework.TestSuite;
 
/**
* The complete test suite for the metadata-extractor library.
* @author Drew Noakes http://drewnoakes.com
*/
public class AllTests extends TestSuite
{
public static Test suite()
{
TestSuite suite = new TestSuite();
 
suite.addTestSuite(DirectoryTest.class);
suite.addTestSuite(ExifDirectoryTest.class);
suite.addTestSuite(ExifReaderTest.class);
suite.addTestSuite(ExifDescriptorTest.class);
suite.addTestSuite(IptcReaderTest.class);
suite.addTestSuite(MetadataTest.class);
suite.addTestSuite(JpegReaderTest.class);
suite.addTestSuite(JpegSegmentDataTest.class);
suite.addTestSuite(JpegDirectoryTest.class);
suite.addTestSuite(JpegComponentTest.class);
suite.addTestSuite(JpegDescriptorTest.class);
suite.addTestSuite(NikonType1MakernoteTest.class);
suite.addTestSuite(NikonType2MakernoteTest1.class);
suite.addTestSuite(NikonType2MakernoteTest2.class);
suite.addTestSuite(CanonMakernoteDescriptorTest.class);
 
suite.addTestSuite(CompoundExceptionTest.class);
suite.addTestSuite(NullOutputStreamTest.class);
suite.addTestSuite(RationalTest.class);
 
suite.addTestSuite(JpegMetadataReaderTest.class);
suite.addTestSuite(JpegSegmentReaderTest.class);
 
return suite;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/test/MockDirectory.java
0,0 → 1,41
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 29-Nov-2002 09:07:43 using IntelliJ IDEA.
*/
package com.drew.metadata.test;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
public class MockDirectory extends Directory
{
private final HashMap _tagNameMap;
 
public MockDirectory()
{
this._tagNameMap = new HashMap();
}
 
public String getName()
{
return "";
}
 
protected HashMap getTagNameMap()
{
return _tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/Metadata.java
0,0 → 1,124
/*
* Metadata.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. Similarly, I release this Java version under the
* same license, though I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew.noakes@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on 28 April 2002, 17:40
* Modified 04 Aug 2002
* - Adjusted javadoc
* - Added
* Modified 29 Oct 2002 (v1.2)
* - Stored IFD directories in separate tag-spaces
* - iterator() now returns an Iterator over a list of TagValue objects
* - More get*Description() methods to detail GPS tags, among others
* - Put spaces between words of tag name for presentation reasons (they had no
* significance in compound form)
*/
package com.drew.metadata;
 
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
 
/**
* Result from an exif extraction operation, containing all tags, their
* values and support for retrieving them.
* @author Drew Noakes http://drewnoakes.com
*/
public final class Metadata implements Serializable
{
/**
*
*/
private final HashMap directoryMap;
 
/**
* List of Directory objects set against this object. Keeping a list handy makes
* creation of an Iterator and counting tags simple.
*/
private final ArrayList directoryList;
 
/**
* Creates a new instance of Metadata. Package private.
*/
public Metadata()
{
directoryMap = new HashMap();
directoryList = new ArrayList();
}
 
 
// OTHER METHODS
 
/**
* Creates an Iterator over the tag types set against this image, preserving the order
* in which they were set. Should the same tag have been set more than once, it's first
* position is maintained, even though the final value is used.
* @return an Iterator of tag types set for this image
*/
public Iterator getDirectoryIterator()
{
return directoryList.iterator();
}
 
/**
* Returns a count of unique directories in this metadata collection.
* @return the number of unique directory types set for this metadata collection
*/
public int getDirectoryCount()
{
return directoryList.size();
}
 
/**
* Returns a <code>Directory</code> of specified type. If this <code>Metadata</code> object already contains
* such a directory, it is returned. Otherwise a new instance of this directory will be created and stored within
* this Metadata object.
* @param type the type of the Directory implementation required.
* @return a directory of the specified type.
*/
public Directory getDirectory(Class type)
{
if (!Directory.class.isAssignableFrom(type)) {
throw new RuntimeException("Class type passed to getDirectory must be an implementation of com.drew.metadata.Directory");
}
// check if we've already issued this type of directory
if (directoryMap.containsKey(type)) {
return (Directory)directoryMap.get(type);
}
Object directory;
try {
directory = type.newInstance();
} catch (Exception e) {
throw new RuntimeException("Cannot instantiate provided Directory type: " + type.toString());
}
// store the directory in case it's requested later
directoryMap.put(type, directory);
directoryList.add(directory);
return (Directory)directory;
}
 
/**
* Indicates whether a given directory type has been created in this metadata
* repository. Directories are created by calling getDirectory(Class).
* @param type the Directory type
* @return true if the metadata directory has been created
*/
public boolean containsDirectory(Class type)
{
return directoryMap.containsKey(type);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/MetadataReader.java
0,0 → 1,27
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Nov-2002 11:21:43 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
/**
*
*/
public interface MetadataReader
{
public Metadata extract();
 
public Metadata extract(Metadata metadata);
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/Directory.java
0,0 → 1,689
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
import com.drew.lang.Rational;
 
import java.io.Serializable;
import java.lang.reflect.Array;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
 
/**
* Base class for all Metadata directory types with supporting methods for setting and
* getting tag values.
*/
public abstract class Directory implements Serializable
{
/**
* Map of values hashed by type identifiers.
*/
protected final HashMap _tagMap;
 
/**
* The descriptor used to interperet tag values.
*/
protected TagDescriptor _descriptor;
 
/**
* A convenient list holding tag values in the order in which they were stored.
* This is used for creation of an iterator, and for counting the number of
* defined tags.
*/
protected final List _definedTagList;
 
private List _errorList;
 
// ABSTRACT METHODS
 
/**
* Provides the name of the directory, for display purposes. E.g. <code>Exif</code>
* @return the name of the directory
*/
public abstract String getName();
 
/**
* Provides the map of tag names, hashed by tag type identifier.
* @return the map of tag names
*/
protected abstract HashMap getTagNameMap();
 
// CONSTRUCTORS
 
/**
* Creates a new Directory.
*/
public Directory()
{
_tagMap = new HashMap();
_definedTagList = new ArrayList();
}
 
// VARIOUS METHODS
 
/**
* Indicates whether the specified tag type has been set.
* @param tagType the tag type to check for
* @return true if a value exists for the specified tag type, false if not
*/
public boolean containsTag(int tagType)
{
return _tagMap.containsKey(new Integer(tagType));
}
 
/**
* Returns an Iterator of Tag instances that have been set in this Directory.
* @return an Iterator of Tag instances
*/
public Iterator getTagIterator()
{
return _definedTagList.iterator();
}
 
/**
* Returns the number of tags set in this Directory.
* @return the number of tags set in this Directory
*/
public int getTagCount()
{
return _definedTagList.size();
}
 
/**
* Sets the descriptor used to interperet tag values.
* @param descriptor the descriptor used to interperet tag values
*/
public void setDescriptor(TagDescriptor descriptor)
{
if (descriptor==null) {
throw new NullPointerException("cannot set a null descriptor");
}
_descriptor = descriptor;
}
 
public void addError(String message)
{
if (_errorList==null) {
_errorList = new ArrayList();
}
_errorList.add(message);
}
 
public boolean hasErrors()
{
return (_errorList!=null && _errorList.size()>0);
}
 
public Iterator getErrors()
{
return _errorList.iterator();
}
 
public int getErrorCount()
{
return _errorList.size();
}
 
// TAG SETTERS
 
/**
* Sets an int value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as an int
*/
public void setInt(int tagType, int value)
{
setObject(tagType, new Integer(value));
}
 
/**
* Sets a double value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a double
*/
public void setDouble(int tagType, double value)
{
setObject(tagType, new Double(value));
}
 
/**
* Sets a float value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a float
*/
public void setFloat(int tagType, float value)
{
setObject(tagType, new Float(value));
}
 
/**
* Sets an int value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a String
*/
public void setString(int tagType, String value)
{
setObject(tagType, value);
}
 
/**
* Sets an int value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a boolean
*/
public void setBoolean(int tagType, boolean value)
{
setObject(tagType, new Boolean(value));
}
 
/**
* Sets a long value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a long
*/
public void setLong(int tagType, long value)
{
setObject(tagType, new Long(value));
}
 
/**
* Sets a java.util.Date value for the specified tag.
* @param tagType the tag's value as an int
* @param value the value for the specified tag as a java.util.Date
*/
public void setDate(int tagType, java.util.Date value)
{
setObject(tagType, value);
}
 
/**
* Sets a Rational value for the specified tag.
* @param tagType the tag's value as an int
* @param rational rational number
*/
public void setRational(int tagType, Rational rational)
{
setObject(tagType, rational);
}
 
/**
* Sets a Rational array for the specified tag.
* @param tagType the tag identifier
* @param rationals the Rational array to store
*/
public void setRationalArray(int tagType, Rational[] rationals)
{
setObjectArray(tagType, rationals);
}
 
/**
* Sets an int array for the specified tag.
* @param tagType the tag identifier
* @param ints the int array to store
*/
public void setIntArray(int tagType, int[] ints)
{
setObjectArray(tagType, ints);
}
 
/**
* Sets a byte array for the specified tag.
* @param tagType the tag identifier
* @param bytes the byte array to store
*/
public void setByteArray(int tagType, byte[] bytes)
{
setObjectArray(tagType, bytes);
}
 
/**
* Sets a String array for the specified tag.
* @param tagType the tag identifier
* @param strings the String array to store
*/
public void setStringArray(int tagType, String[] strings)
{
setObjectArray(tagType, strings);
}
 
/**
* Private helper method, containing common functionality for all 'add'
* methods.
* @param tagType the tag's value as an int
* @param value the value for the specified tag
* @throws NullPointerException if value is <code>null</code>
*/
public void setObject(int tagType, Object value)
{
if (value==null) {
throw new NullPointerException("cannot set a null object");
}
 
Integer key = new Integer(tagType);
if (!_tagMap.containsKey(key)) {
_definedTagList.add(new Tag(tagType, this));
}
_tagMap.put(key, value);
}
 
/**
* Private helper method, containing common functionality for all 'add...Array'
* methods.
* @param tagType the tag's value as an int
* @param array the array of values for the specified tag
*/
public void setObjectArray(int tagType, Object array)
{
// for now, we don't do anything special -- this method might be a candidate for removal once the dust settles
setObject(tagType, array);
}
 
// TAG GETTERS
 
/**
* Returns the specified tag's value as an int, if possible.
*/
public int getInt(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof String) {
try {
return Integer.parseInt((String)o);
} catch (NumberFormatException nfe) {
// convert the char array to an int
String s = (String)o;
byte[] bytes = s.getBytes();
long val = 0;
for (int i = 0; i < bytes.length; i++) {
val = val << 8;
val += bytes[i];
}
return (int)val;
}
} else if (o instanceof Number) {
return ((Number)o).intValue();
} else if (o instanceof Rational[]) {
Rational[] rationals = (Rational[])o;
if (rationals.length==1)
return rationals[0].intValue();
} else if (o instanceof byte[]) {
byte[] bytes = (byte[])o;
if (bytes.length==1)
return bytes[0];
} else if (o instanceof int[]) {
int[] ints = (int[])o;
if (ints.length==1)
return ints[0];
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to int. It is of type '" + o.getClass() + "'.");
}
 
// TODO get Array methods need to return cloned data, to maintain this directory's integrity
 
/**
* Gets the specified tag's value as a String array, if possible. Only supported
* where the tag is set as String[], String, int[], byte[] or Rational[].
* @param tagType the tag identifier
* @return the tag's value as an array of Strings
* @throws MetadataException if the tag has not been set or cannot be represented
* as a String[]
*/
public String[] getStringArray(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof String[]) {
return (String[])o;
} else if (o instanceof String) {
String[] strings = {(String)o};
return strings;
} else if (o instanceof int[]) {
int[] ints = (int[])o;
String[] strings = new String[ints.length];
for (int i = 0; i<strings.length; i++) {
strings[i] = Integer.toString(ints[i]);
}
return strings;
} else if (o instanceof byte[]) {
byte[] bytes = (byte[])o;
String[] strings = new String[bytes.length];
for (int i = 0; i<strings.length; i++) {
strings[i] = Byte.toString(bytes[i]);
}
return strings;
} else if (o instanceof Rational[]) {
Rational[] rationals = (Rational[])o;
String[] strings = new String[rationals.length];
for (int i = 0; i<strings.length; i++) {
strings[i] = rationals[i].toSimpleString(false);
}
return strings;
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to an String array. It is of type '" + o.getClass() + "'.");
}
 
/**
* Gets the specified tag's value as an int array, if possible. Only supported
* where the tag is set as String, int[], byte[] or Rational[].
* @param tagType the tag identifier
* @return the tag's value as an int array
* @throws MetadataException if the tag has not been set, or cannot be converted to
* an int array
*/
public int[] getIntArray(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof Rational[]) {
Rational[] rationals = (Rational[])o;
int[] ints = new int[rationals.length];
for (int i = 0; i<ints.length; i++) {
ints[i] = rationals[i].intValue();
}
return ints;
} else if (o instanceof int[]) {
return (int[])o;
} else if (o instanceof byte[]) {
byte[] bytes = (byte[])o;
int[] ints = new int[bytes.length];
for (int i = 0; i<bytes.length; i++) {
byte b = bytes[i];
ints[i] = b;
}
return ints;
} else if (o instanceof String) {
String str = (String)o;
int[] ints = new int[str.length()];
for (int i = 0; i<str.length(); i++) {
ints[i] = str.charAt(i);
}
return ints;
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to an int array. It is of type '" + o.getClass() + "'.");
}
 
/**
* Gets the specified tag's value as an byte array, if possible. Only supported
* where the tag is set as String, int[], byte[] or Rational[].
* @param tagType the tag identifier
* @return the tag's value as a byte array
* @throws MetadataException if the tag has not been set, or cannot be converted to
* a byte array
*/
public byte[] getByteArray(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof Rational[]) {
Rational[] rationals = (Rational[])o;
byte[] bytes = new byte[rationals.length];
for (int i = 0; i<bytes.length; i++) {
bytes[i] = rationals[i].byteValue();
}
return bytes;
} else if (o instanceof byte[]) {
return (byte[])o;
} else if (o instanceof int[]) {
int[] ints = (int[])o;
byte[] bytes = new byte[ints.length];
for (int i = 0; i<ints.length; i++) {
bytes[i] = (byte)ints[i];
}
return bytes;
} else if (o instanceof String) {
String str = (String)o;
byte[] bytes = new byte[str.length()];
for (int i = 0; i<str.length(); i++) {
bytes[i] = (byte)str.charAt(i);
}
return bytes;
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a byte array. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a double, if possible.
*/
public double getDouble(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof String) {
try {
return Double.parseDouble((String)o);
} catch (NumberFormatException nfe) {
throw new MetadataException("unable to parse string " + o + " as a double", nfe);
}
} else if (o instanceof Number) {
return ((Number)o).doubleValue();
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a double. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a float, if possible.
*/
public float getFloat(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof String) {
try {
return Float.parseFloat((String)o);
} catch (NumberFormatException nfe) {
throw new MetadataException("unable to parse string " + o + " as a float", nfe);
}
} else if (o instanceof Number) {
return ((Number)o).floatValue();
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a float. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a long, if possible.
*/
public long getLong(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof String) {
try {
return Long.parseLong((String)o);
} catch (NumberFormatException nfe) {
throw new MetadataException("unable to parse string " + o + " as a long", nfe);
}
} else if (o instanceof Number) {
return ((Number)o).longValue();
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a long. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a boolean, if possible.
*/
public boolean getBoolean(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof Boolean) {
return ((Boolean)o).booleanValue();
} else if (o instanceof String) {
try {
return Boolean.getBoolean((String)o);
} catch (NumberFormatException nfe) {
throw new MetadataException("unable to parse string " + o + " as a boolean", nfe);
}
} else if (o instanceof Number) {
return (((Number)o).doubleValue()!=0);
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a boolean. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a java.util.Date, if possible.
*/
public java.util.Date getDate(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof java.util.Date) {
return (java.util.Date)o;
} else if (o instanceof String) {
// add new dateformat strings to make this method even smarter
// so far, this seems to cover all known date strings
// (for example, AM and PM strings are not supported...)
String datePatterns[] = {
"yyyy:MM:dd HH:mm:ss",
"yyyy:MM:dd HH:mm",
"yyyy-MM-dd HH:mm:ss",
"yyyy-MM-dd HH:mm"};
String dateString = (String)o;
for (int i = 0; i<datePatterns.length; i++) {
try {
DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]);
return parser.parse(dateString);
} catch (java.text.ParseException ex) {
// simply try the next pattern
}
}
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a java.util.Date. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a Rational, if possible.
*/
public Rational getRational(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof Rational) {
return (Rational)o;
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational. It is of type '" + o.getClass() + "'.");
}
 
public Rational[] getRationalArray(int tagType) throws MetadataException
{
Object o = getObject(tagType);
if (o==null) {
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first");
} else if (o instanceof Rational[]) {
return (Rational[])o;
}
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational array. It is of type '" + o.getClass() + "'.");
}
 
/**
* Returns the specified tag's value as a String. This value is the 'raw' value. A more presentable decoding
* of this value may be obtained from the corresponding Descriptor.
* @return the String reprensentation of the tag's value, or
* <code>null</code> if the tag hasn't been defined.
*/
public String getString(int tagType)
{
Object o = getObject(tagType);
if (o==null)
return null;
 
if (o instanceof Rational)
return ((Rational)o).toSimpleString(true);
 
if (o.getClass().isArray())
{
// handle arrays of objects and primitives
int arrayLength = Array.getLength(o);
// determine if this is an array of objects i.e. [Lcom.drew.blah
boolean isObjectArray = o.getClass().toString().startsWith("class [L");
StringBuffer sbuffer = new StringBuffer();
for (int i = 0; i<arrayLength; i++)
{
if (i!=0)
sbuffer.append(' ');
if (isObjectArray)
sbuffer.append(Array.get(o, i).toString());
else
sbuffer.append(Array.getInt(o, i));
}
return sbuffer.toString();
}
 
return o.toString();
}
 
/**
* Returns the object hashed for the particular tag type specified, if available.
* @param tagType the tag type identifier
* @return the tag's value as an Object if available, else null
*/
public Object getObject(int tagType)
{
return _tagMap.get(new Integer(tagType));
}
 
// OTHER METHODS
 
/**
* Returns the name of a specified tag as a String.
* @param tagType the tag type identifier
* @return the tag's name as a String
*/
public String getTagName(int tagType)
{
Integer key = new Integer(tagType);
HashMap nameMap = getTagNameMap();
if (!nameMap.containsKey(key)) {
String hex = Integer.toHexString(tagType);
while (hex.length()<4) {
hex = "0" + hex;
}
return "Unknown tag (0x" + hex + ")";
}
return (String)nameMap.get(key);
}
 
/**
* Provides a description of a tag's value using the descriptor set by
* <code>setDescriptor(Descriptor)</code>.
* @param tagType the tag type identifier
* @return the tag value's description as a String
* @throws MetadataException if a descriptor hasn't been set, or if an error
* occurs during calculation of the description within the Descriptor
*/
public String getDescription(int tagType) throws MetadataException
{
if (_descriptor==null) {
throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided");
}
 
return _descriptor.getDescription(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegComponent.java
0,0 → 1,81
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Oct 9, 17:04:07 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg;
 
import com.drew.metadata.MetadataException;
 
import java.io.Serializable;
 
/**
* Created by IntelliJ IDEA.
* User: dnoakes
* Date: 09-Oct-2003
* Time: 17:04:07
* To change this template use Options | File Templates.
*/
public class JpegComponent implements Serializable
{
private final int _componentId;
private final int _samplingFactorByte;
private final int _quantizationTableNumber;
 
public JpegComponent(int componentId, int samplingFactorByte, int quantizationTableNumber)
{
_componentId = componentId;
_samplingFactorByte = samplingFactorByte;
_quantizationTableNumber = quantizationTableNumber;
}
 
public int getComponentId()
{
return _componentId;
}
 
public String getComponentName() throws MetadataException
{
switch (_componentId)
{
case 1:
return "Y";
case 2:
return "Cb";
case 3:
return "Cr";
case 4:
return "I";
case 5:
return "Q";
}
 
throw new MetadataException("Unsupported component id: " + _componentId);
}
 
public int getQuantizationTableNumber()
{
return _quantizationTableNumber;
}
 
public int getHorizontalSamplingFactor()
{
return _samplingFactorByte & 0x0F;
}
 
public int getVerticalSamplingFactor()
{
return (_samplingFactorByte>>4) & 0x0F;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegReader.java
0,0 → 1,146
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Aug 2, 2003 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.MetadataReader;
 
import java.io.File;
import java.io.InputStream;
 
/**
*
* @author Darrell Silver http://www.darrellsilver.com and Drew Noakes
*/
public class JpegReader implements MetadataReader
{
/**
* The SOF0 data segment.
*/
private final byte[] _data;
 
/**
* Creates a new JpegReader for the specified Jpeg jpegFile.
*/
public JpegReader(File jpegFile) throws JpegProcessingException
{
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_SOF0));
}
 
/** Creates a JpegReader for a JPEG stream.
*
* @param is JPEG stream. Stream will be closed.
*/
public JpegReader(InputStream is) throws JpegProcessingException
{
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));
}
 
public JpegReader(byte[] data)
{
_data = data;
}
 
/**
* Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.
*/
public Metadata extract()
{
return extract(new Metadata());
}
 
/**
* Performs the Jpeg data extraction, adding found values to the specified
* instance of <code>Metadata</code>.
*/
public Metadata extract(Metadata metadata)
{
if (_data==null) {
return metadata;
}
 
JpegDirectory directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class);
 
try {
// data precision
int dataPrecision = get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION);
directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, dataPrecision);
 
// process height
int height = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height);
 
// process width
int width = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width);
 
// number of components
int numberOfComponents = get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);
directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, numberOfComponents);
 
// for each component, there are three bytes of data:
// 1 - Component ID: 1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q
// 2 - Sampling factors: bit 0-3 vertical, 4-7 horizontal
// 3 - Quantization table number
int offset = 6;
for (int i=0; i<numberOfComponents; i++)
{
int componentId = get16Bits(offset++);
int samplingFactorByte = get16Bits(offset++);
int quantizationTableNumber = get16Bits(offset++);
JpegComponent component = new JpegComponent(componentId, samplingFactorByte, quantizationTableNumber);
directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i, component);
}
 
} catch (MetadataException me) {
directory.addError("MetadataException: " + me);
}
 
return metadata;
}
 
/**
* Returns an int calculated from two bytes of data at the specified offset (MSB, LSB).
* @param offset position within the data buffer to read first byte
* @return the 32 bit int value, between 0x0000 and 0xFFFF
*/
private int get32Bits(int offset) throws MetadataException
{
if (offset+1>=_data.length) {
throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");
}
 
return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255);
}
 
/**
* Returns an int calculated from one byte of data at the specified offset.
* @param offset position within the data buffer to read byte
* @return the 16 bit int value, between 0x00 and 0xFF
*/
private int get16Bits(int offset) throws MetadataException
{
if (offset>=_data.length) {
throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer");
}
 
return (_data[offset] & 255);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegDirectory.java
0,0 → 1,111
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on Aug 2, 2003.
*/
package com.drew.metadata.jpeg;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
 
import java.util.HashMap;
 
/**
* Directory of tags and values for the SOF0 Jpeg segment. This segment holds basic metadata about the image.
* @author Darrell Silver http://www.darrellsilver.com and Drew Noakes
*/
public class JpegDirectory extends Directory {
 
/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */
public static final int TAG_JPEG_DATA_PRECISION = 0;
/** The image's height. Necessary for decoding the image, so it should always be there. */
public static final int TAG_JPEG_IMAGE_HEIGHT = 1;
/** The image's width. Necessary for decoding the image, so it should always be there. */
public static final int TAG_JPEG_IMAGE_WIDTH = 3;
/** Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK
* Each component TAG_COMPONENT_DATA_[1-4], has the following meaning:
* component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q),
* sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.),
* quantization table number (1 byte).
* <p>
* This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm
*/
public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5;
 
// NOTE! Component tag type int values must increment in steps of 1
 
/** the first of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
public static final int TAG_JPEG_COMPONENT_DATA_1 = 6;
/** the second of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
public static final int TAG_JPEG_COMPONENT_DATA_2 = 7;
/** the third of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
public static final int TAG_JPEG_COMPONENT_DATA_3 = 8;
/** the fourth of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/
public static final int TAG_JPEG_COMPONENT_DATA_4 = 9;
 
protected static final HashMap tagNameMap = new HashMap();
 
static {
tagNameMap.put(new Integer(TAG_JPEG_DATA_PRECISION), "Data Precision");
tagNameMap.put(new Integer(TAG_JPEG_IMAGE_WIDTH), "Image Width");
tagNameMap.put(new Integer(TAG_JPEG_IMAGE_HEIGHT), "Image Height");
tagNameMap.put(new Integer(TAG_JPEG_NUMBER_OF_COMPONENTS), "Number of Components");
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_1), "Component 1");
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_2), "Component 2");
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_3), "Component 3");
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_4), "Component 4");
}
 
public JpegDirectory() {
this.setDescriptor(new JpegDescriptor(this));
}
 
public String getName() {
return "Jpeg";
}
 
protected HashMap getTagNameMap() {
return tagNameMap;
}
 
/**
*
* @param componentNumber The zero-based index of the component. This number is normally between 0 and 3.
* Use getNumberOfComponents for bounds-checking.
* @return
*/
public JpegComponent getComponent(int componentNumber)
{
int tagType = JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + componentNumber;
 
JpegComponent component = (JpegComponent)getObject(tagType);
 
return component;
}
 
public int getImageWidth() throws MetadataException
{
return getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH);
}
 
public int getImageHeight() throws MetadataException
{
return getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT);
}
 
public int getNumberOfComponents() throws MetadataException
{
return getInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java
0,0 → 1,84
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataReader;
 
import java.io.File;
import java.io.InputStream;
 
/**
*
* @author Drew Noakes http://drewnoakes.com
*/
public class JpegCommentReader implements MetadataReader
{
/**
* The COM data segment.
*/
private final byte[] _data;
 
/**
* Creates a new JpegReader for the specified Jpeg jpegFile.
*/
public JpegCommentReader(File jpegFile) throws JpegProcessingException
{
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_COM));
}
 
/** Creates a JpegCommentReader for a JPEG stream.
*
* @param is JPEG stream. Stream will be closed.
*/
public JpegCommentReader(InputStream is) throws JpegProcessingException
{
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD));
}
 
public JpegCommentReader(byte[] data)
{
_data = data;
}
 
/**
* Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>.
*/
public Metadata extract()
{
return extract(new Metadata());
}
 
/**
* Performs the Jpeg data extraction, adding found values to the specified
* instance of <code>Metadata</code>.
*/
public Metadata extract(Metadata metadata)
{
if (_data==null) {
return metadata;
}
 
JpegCommentDirectory directory = (JpegCommentDirectory)metadata.getDirectory(JpegCommentDirectory.class);
 
directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, new String(_data));
 
return metadata;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java
0,0 → 1,49
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg;
 
import com.drew.metadata.Directory;
 
import java.util.HashMap;
 
/**
*
* @author Drew Noakes http://drewnoakes.com
*/
public class JpegCommentDirectory extends Directory {
 
/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */
public static final int TAG_JPEG_COMMENT = 0;
 
protected static final HashMap tagNameMap = new HashMap();
 
static {
tagNameMap.put(new Integer(TAG_JPEG_COMMENT), "Jpeg Comment");
}
 
public JpegCommentDirectory() {
this.setDescriptor(new JpegCommentDescriptor(this));
}
 
public String getName() {
return "JpegComment";
}
 
protected HashMap getTagNameMap() {
return tagNameMap;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegDescriptorTest.java
0,0 → 1,82
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes 09-Oct-2003 15:22:23 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg.test;
 
import com.drew.metadata.MetadataException;
import com.drew.metadata.jpeg.JpegComponent;
import com.drew.metadata.jpeg.JpegDescriptor;
import com.drew.metadata.jpeg.JpegDirectory;
import junit.framework.TestCase;
 
/**
*
*/
public class JpegDescriptorTest extends TestCase
{
private JpegDirectory _directory;
private JpegDescriptor _descriptor;
 
public JpegDescriptorTest(String s)
{
super(s);
}
 
public void setUp() throws Exception
{
_directory = new JpegDirectory();
_descriptor = new JpegDescriptor(_directory);
}
 
public void testGetComponentDataDescription_InvalidComponentNumber() throws Exception
{
try {
_descriptor.getComponentDataDescription(1);
fail("Excepted exception");
} catch (MetadataException e) {
// expect exception
}
}
 
public void testGetImageWidthDescription() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, 123);
assertEquals("123 pixels", _descriptor.getImageWidthDescription());
assertEquals("123 pixels", _directory.getDescription(JpegDirectory.TAG_JPEG_IMAGE_WIDTH));
}
 
public void testGetImageHeightDescription() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, 123);
assertEquals("123 pixels", _descriptor.getImageHeightDescription());
assertEquals("123 pixels", _directory.getDescription(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT));
}
 
public void testGetDataPrecisionDescription() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, 8);
assertEquals("8 bits", _descriptor.getDataPrecisionDescription());
assertEquals("8 bits", _directory.getDescription(JpegDirectory.TAG_JPEG_DATA_PRECISION));
}
 
public void testGetComponentDescription() throws MetadataException
{
JpegComponent component1 = new JpegComponent(1, 0x22, 0);
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1, component1);
assertEquals("Y component: Quantization table 0, Sampling factors 2 horiz/2 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1));
assertEquals("Y component: Quantization table 0, Sampling factors 2 horiz/2 vert", _descriptor.getComponentDataDescription(0));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegComponentTest.java
0,0 → 1,51
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg.test;
 
import com.drew.metadata.jpeg.JpegComponent;
import junit.framework.TestCase;
 
/**
*
*/
public class JpegComponentTest extends TestCase
{
public JpegComponentTest(String s)
{
super(s);
}
 
public void testGetComponentCharacter() throws Exception
{
JpegComponent component;
 
component = new JpegComponent(1,2,3);
assertEquals("Y", component.getComponentName());
 
component = new JpegComponent(2,2,3);
assertEquals("Cb", component.getComponentName());
 
component = new JpegComponent(3,2,3);
assertEquals("Cr", component.getComponentName());
 
component = new JpegComponent(4,2,3);
assertEquals("I", component.getComponentName());
 
component = new JpegComponent(5,2,3);
assertEquals("Q", component.getComponentName());
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegReaderTest.java
0,0 → 1,150
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg.test;
 
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Metadata;
import com.drew.metadata.jpeg.JpegComponent;
import com.drew.metadata.jpeg.JpegDirectory;
import com.drew.metadata.jpeg.JpegReader;
import junit.framework.TestCase;
 
import java.io.File;
import java.io.FileNotFoundException;
 
/**
*
*/
public class JpegReaderTest extends TestCase
{
private JpegDirectory _directory;
 
public JpegReaderTest(String s)
{
super(s);
}
 
public void setUp() throws JpegProcessingException, FileNotFoundException
{
// use a known testing image
File jpegFile = new File("src/com/drew/metadata/jpeg/test/simple.jpg");
JpegReader reader = new JpegReader(jpegFile);
Metadata metadata = reader.extract();
assertTrue(metadata.containsDirectory(JpegDirectory.class));
_directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class);
}
 
public void testExtract_Width() throws Exception
{
assertEquals(800, _directory.getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH));
}
 
public void testExtract_Height() throws Exception
{
assertEquals(600, _directory.getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT));
}
 
public void testExtract_DataPrecision() throws Exception
{
assertEquals(8, _directory.getInt(JpegDirectory.TAG_JPEG_DATA_PRECISION));
}
 
public void testExtract_NumberOfComponents() throws Exception
{
assertEquals(3, _directory.getInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS));
}
 
public void testComponentData1() throws Exception
{
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1);
assertEquals("Y", component.getComponentName());
assertEquals(1, component.getComponentId());
assertEquals(0, component.getQuantizationTableNumber());
assertEquals(2, component.getHorizontalSamplingFactor());
assertEquals(2, component.getVerticalSamplingFactor());
}
 
public void testComponentData2() throws Exception
{
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2);
assertEquals("Cb", component.getComponentName());
assertEquals(2, component.getComponentId());
assertEquals(1, component.getQuantizationTableNumber());
assertEquals(1, component.getHorizontalSamplingFactor());
assertEquals(1, component.getVerticalSamplingFactor());
assertEquals("Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2));
}
 
public void testComponentData3() throws Exception
{
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3);
assertEquals("Cr", component.getComponentName());
assertEquals(3, component.getComponentId());
assertEquals(1, component.getQuantizationTableNumber());
assertEquals(1, component.getHorizontalSamplingFactor());
assertEquals(1, component.getVerticalSamplingFactor());
assertEquals("Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3));
}
 
/*
// this test is part of an incomplete investigation into extracting audio from JPG files
public void testJpegWithAudio() throws Exception
{
// use a known testing image
File jpegFile = new File("src/com/drew/metadata/jpeg/test/audioPresent.jpg");
 
JpegSegmentReader jpegSegmentReader = new JpegSegmentReader(jpegFile);
byte[] segment1Bytes = jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP2);
System.out.println(segment1Bytes.length);
 
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1));
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP2).length);
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP3));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP4));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP5));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP6));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP7));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP8));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP9));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPA));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPB));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPC));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPE));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPF));
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_COM));
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_DHT).length);
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_DQT).length);
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_SOF0).length);
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_SOI));
 
// write the segment's data out to a wav file...
File audioFile = new File("src/com/drew/metadata/jpeg/test/audio.wav");
FileOutputStream os = null;
try
{
os = new FileOutputStream(audioFile);
os.write(segment1Bytes);
}
finally
{
if (os!=null)
os.close();
}
}
*/
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/simple.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegDirectoryTest.java
0,0 → 1,91
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg.test;
 
import com.drew.metadata.jpeg.JpegComponent;
import com.drew.metadata.jpeg.JpegDirectory;
import junit.framework.TestCase;
 
/**
*
*/
public class JpegDirectoryTest extends TestCase
{
private JpegDirectory _directory;
 
public JpegDirectoryTest(String s)
{
super(s);
}
 
public void setUp()
{
_directory = new JpegDirectory();
}
 
public void testSetAndGetValue() throws Exception
{
_directory.setInt(123, 8);
assertEquals(8, _directory.getInt(123));
}
 
public void testGetComponent_NotAdded()
{
assertNull(_directory.getComponent(1));
}
 
// NOTE tests for individual tag values exist in JpegReaderTest.java
 
public void testGetImageWidth() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, 123);
assertEquals(123, _directory.getImageWidth());
}
 
public void testGetImageHeight() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, 123);
assertEquals(123, _directory.getImageHeight());
}
 
 
public void testGetNumberOfComponents() throws Exception
{
_directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, 3);
assertEquals(3, _directory.getNumberOfComponents());
assertEquals("3", _directory.getDescription(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS));
}
 
public void testGetComponent() throws Exception
{
JpegComponent component1 = new JpegComponent(1, 2, 3);
JpegComponent component2 = new JpegComponent(1, 2, 3);
JpegComponent component3 = new JpegComponent(1, 2, 3);
JpegComponent component4 = new JpegComponent(1, 2, 3);
 
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1, component1);
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2, component2);
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3, component3);
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_4, component4);
 
// component numbers are zero-indexed for this method
assertSame(component1, _directory.getComponent(0));
assertSame(component2, _directory.getComponent(1));
assertSame(component3, _directory.getComponent(2));
assertSame(component4, _directory.getComponent(3));
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java
0,0 → 1,88
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.metadata.jpeg;
 
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.TagDescriptor;
 
/**
* Provides human-readable string versions of the tags stored in a JpegDirectory.
* Thanks to Darrell Silver (www.darrellsilver.com) for the initial version of this class.
*/
public class JpegDescriptor extends TagDescriptor
{
public JpegDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType) throws MetadataException
{
switch (tagType)
{
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_1:
return getComponentDataDescription(0);
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_2:
return getComponentDataDescription(1);
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_3:
return getComponentDataDescription(2);
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_4:
return getComponentDataDescription(3);
case JpegDirectory.TAG_JPEG_DATA_PRECISION:
return getDataPrecisionDescription();
case JpegDirectory.TAG_JPEG_IMAGE_HEIGHT:
return getImageHeightDescription();
case JpegDirectory.TAG_JPEG_IMAGE_WIDTH:
return getImageWidthDescription();
}
 
return _directory.getString(tagType);
}
 
public String getImageWidthDescription()
{
return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH) + " pixels";
}
 
public String getImageHeightDescription()
{
return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT) + " pixels";
}
 
public String getDataPrecisionDescription()
{
return _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION) + " bits";
}
 
public String getComponentDataDescription(int componentNumber) throws MetadataException
{
JpegComponent component = ((JpegDirectory)_directory).getComponent(componentNumber);
 
if (component==null)
throw new MetadataException("No Jpeg component exists with number " + componentNumber);
 
StringBuffer sb = new StringBuffer();
sb.append(component.getComponentName());
sb.append(" component: Quantization table ");
sb.append(component.getQuantizationTableNumber());
sb.append(", Sampling factors ");
sb.append(component.getHorizontalSamplingFactor());
sb.append(" horiz/");
sb.append(component.getVerticalSamplingFactor());
sb.append(" vert");
return sb.toString();
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java
0,0 → 1,37
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA.
*/
package com.drew.metadata.jpeg;
 
import com.drew.metadata.Directory;
import com.drew.metadata.TagDescriptor;
 
/**
*
* @author Drew Noakes http://drewnoakes.com
*/
public class JpegCommentDescriptor extends TagDescriptor
{
public JpegCommentDescriptor(Directory directory)
{
super(directory);
}
 
public String getDescription(int tagType)
{
return _directory.getString(tagType);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/metadata/SampleUsage.java
0,0 → 1,140
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 05-Nov-2002 18:57:14 using IntelliJ IDEA.
*/
package com.drew.metadata;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.drew.metadata.exif.ExifReader;
import com.drew.metadata.iptc.IptcReader;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGDecodeParam;
import com.sun.image.codec.jpeg.JPEGImageDecoder;
 
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Iterator;
 
/**
*
*/
public class SampleUsage
{
/**
* Constructor which executes multiple sample usages, each of which return the same output. This class showcases
* multiple usages of this metadata class library.
* @param fileName path to a jpeg file upon which to operate
*/
public SampleUsage(String fileName)
{
File jpegFile = new File(fileName);
 
// There are multiple ways to get a Metadata object
 
// Approach 1
// This approach reads all types of known Jpeg metadata (at present,
// Exif and Iptc) in a single call. In most cases, this is the most
// appropriate usage.
try {
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
printImageTags(1, metadata);
} catch (JpegProcessingException e) {
System.err.println("error 1a");
}
 
// Approach 2
// This approach shows using individual MetadataReader implementations
// to read a file. This is less efficient than approach 1, as the file
// is opened and read twice.
try {
Metadata metadata = new Metadata();
new ExifReader(jpegFile).extract(metadata);
new IptcReader(jpegFile).extract(metadata);
printImageTags(2, metadata);
} catch (JpegProcessingException jpe) {
System.err.println("error 2a");
}
 
// Approach 3
// As fast as approach 1 (this is what goes on inside the JpegMetadataReader's
// readMetadata() method), this code is handy if you want to look into other
// Jpeg segments too.
try {
JpegSegmentReader segmentReader = new JpegSegmentReader(jpegFile);
byte[] exifSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1);
byte[] iptcSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD);
Metadata metadata = new Metadata();
new ExifReader(exifSegment).extract(metadata);
new IptcReader(iptcSegment).extract(metadata);
printImageTags(3, metadata);
} catch (JpegProcessingException jpe) {
System.err.println("error 3a");
}
// Approach 4
// This approach is the slowest, because it decodes the Jpeg image. Of
// course you now have a decoded image to play with. In some instances
// this will be most appropriate.
try {
JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(new FileInputStream(jpegFile));
BufferedImage image = jpegDecoder.decodeAsBufferedImage();
// now you can use the image
JPEGDecodeParam decodeParam = jpegDecoder.getJPEGDecodeParam();
Metadata metadata = JpegMetadataReader.readMetadata(decodeParam);
printImageTags(4, metadata);
} catch (FileNotFoundException e) {
System.err.println("error 4a");
} catch (IOException e) {
System.err.println("error 4b");
}
}
 
private void printImageTags(int approachCount, Metadata metadata)
{
System.out.println();
System.out.println("*** APPROACH " + approachCount + " ***");
System.out.println();
// iterate over the exif data and print to System.out
Iterator directories = metadata.getDirectoryIterator();
while (directories.hasNext()) {
Directory directory = (Directory)directories.next();
Iterator tags = directory.getTagIterator();
while (tags.hasNext()) {
Tag tag = (Tag)tags.next();
System.out.println(tag);
}
if (directory.hasErrors()) {
Iterator errors = directory.getErrors();
while (errors.hasNext()) {
System.out.println("ERROR: " + errors.next());
}
}
}
}
 
/**
* Executes the sample usage program.
* @param args command line parameters
*/
public static void main(String[] args)
{
new SampleUsage("src/com/drew/metadata/test/withIptcExifGps.jpg");
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/CompoundException.java
0,0 → 1,89
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.lang;
 
import java.io.PrintStream;
import java.io.PrintWriter;
 
/**
* Represents a compound exception, as modelled in JDK 1.4, but
* unavailable in previous versions. This class allows support
* of these previous JDK versions.
*/
public class CompoundException extends Exception
{
private final Throwable _innnerException;
 
public CompoundException(String msg)
{
this(msg, null);
}
 
public CompoundException(Throwable exception)
{
this(null, exception);
}
 
public CompoundException(String msg, Throwable innerException)
{
super(msg);
_innnerException = innerException;
}
 
public Throwable getInnerException()
{
return _innnerException;
}
 
public String toString()
{
StringBuffer sbuffer = new StringBuffer();
sbuffer.append(super.toString());
if (_innnerException != null) {
sbuffer.append("\n");
sbuffer.append("--- inner exception ---");
sbuffer.append("\n");
sbuffer.append(_innnerException.toString());
}
return sbuffer.toString();
}
 
public void printStackTrace(PrintStream s)
{
super.printStackTrace(s);
if (_innnerException != null) {
s.println("--- inner exception ---");
_innnerException.printStackTrace(s);
}
}
 
public void printStackTrace(PrintWriter s)
{
super.printStackTrace(s);
if (_innnerException != null) {
s.println("--- inner exception ---");
_innnerException.printStackTrace(s);
}
}
 
public void printStackTrace()
{
super.printStackTrace();
if (_innnerException != null) {
System.err.println("--- inner exception ---");
_innnerException.printStackTrace();
}
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/NullOutputStream.java
0,0 → 1,33
/**
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Dec 15, 2002 3:30:59 PM using IntelliJ IDEA.
*/
package com.drew.lang;
 
import java.io.IOException;
import java.io.OutputStream;
 
public class NullOutputStream extends OutputStream
{
public NullOutputStream()
{
super();
}
 
public void write(int b) throws IOException
{
// do nothing
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/Rational.java
0,0 → 1,291
/*
* Rational.java
*
* This class is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. Similarly, I release this Java version under the
* same license, though I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew.noakes@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created on 6 May 2002, 18:06
* Updated 26 Aug 2002 by Drew
* - Added toSimpleString() method, which returns a simplified and hopefully more
* readable version of the Rational. i.e. 2/10 -> 1/5, and 10/2 -> 5
* Modified 29 Oct 2002 (v1.2)
* - Improved toSimpleString() to factor more complex rational numbers into
* a simpler form
* i.e.
* 10/15 -> 2/3
* - toSimpleString() now accepts a boolean flag, 'allowDecimals' which will
* display the rational number in decimal form if it fits within 5 digits
* i.e.
* 3/4 -> 0.75 when allowDecimal == true
*/
 
package com.drew.lang;
 
import java.io.Serializable;
 
/**
* Immutable class for holding a rational number without loss of precision. Provides
* a familiar representation via toString() in form <code>numerator/denominator</code>.
* <p>
* @author Drew Noakes http://drewnoakes.com
*/
public class Rational extends java.lang.Number implements Serializable
{
/**
* Holds the numerator.
*/
private final int numerator;
 
/**
* Holds the denominator.
*/
private final int denominator;
 
private int maxSimplificationCalculations = 1000;
 
/**
* Creates a new instance of Rational. Rational objects are immutable, so
* once you've set your numerator and denominator values here, you're stuck
* with them!
*/
public Rational(int numerator, int denominator)
{
this.numerator = numerator;
this.denominator = denominator;
}
 
/**
* Returns the value of the specified number as a <code>double</code>.
* This may involve rounding.
*
* @return the numeric value represented by this object after conversion
* to type <code>double</code>.
*/
public double doubleValue()
{
return (double)numerator / (double)denominator;
}
 
/**
* Returns the value of the specified number as a <code>float</code>.
* This may involve rounding.
*
* @return the numeric value represented by this object after conversion
* to type <code>float</code>.
*/
public float floatValue()
{
return (float)numerator / (float)denominator;
}
 
/**
* Returns the value of the specified number as a <code>byte</code>.
* This may involve rounding or truncation. This implementation simply
* casts the result of <code>doubleValue()</code> to <code>byte</code>.
*
* @return the numeric value represented by this object after conversion
* to type <code>byte</code>.
*/
public final byte byteValue()
{
return (byte)doubleValue();
}
 
/**
* Returns the value of the specified number as an <code>int</code>.
* This may involve rounding or truncation. This implementation simply
* casts the result of <code>doubleValue()</code> to <code>int</code>.
*
* @return the numeric value represented by this object after conversion
* to type <code>int</code>.
*/
public final int intValue()
{
return (int)doubleValue();
}
 
/**
* Returns the value of the specified number as a <code>long</code>.
* This may involve rounding or truncation. This implementation simply
* casts the result of <code>doubleValue()</code> to <code>long</code>.
*
* @return the numeric value represented by this object after conversion
* to type <code>long</code>.
*/
public final long longValue()
{
return (long)doubleValue();
}
 
/**
* Returns the value of the specified number as a <code>short</code>.
* This may involve rounding or truncation. This implementation simply
* casts the result of <code>doubleValue()</code> to <code>short</code>.
*
* @return the numeric value represented by this object after conversion
* to type <code>short</code>.
*/
public final short shortValue()
{
return (short)doubleValue();
}
 
 
/**
* Returns the denominator.
*/
public final int getDenominator()
{
return this.denominator;
}
 
/**
* Returns the numerator.
*/
public final int getNumerator()
{
return this.numerator;
}
 
/**
* Returns the reciprocal value of this obejct as a new Rational.
* @return the reciprocal in a new object
*/
public Rational getReciprocal()
{
return new Rational(this.denominator, this.numerator);
}
 
/**
* Checks if this rational number is an Integer, either positive or negative.
*/
public boolean isInteger()
{
if (denominator == 1 ||
(denominator != 0 && (numerator % denominator == 0)) ||
(denominator == 0 && numerator == 0)
) {
return true;
} else {
return false;
}
}
 
/**
* Returns a string representation of the object of form <code>numerator/denominator</code>.
* @return a string representation of the object.
*/
public String toString()
{
return numerator + "/" + denominator;
}
 
/**
* Returns the simplest represenation of this Rational's value possible.
*/
public String toSimpleString(boolean allowDecimal)
{
if (denominator == 0 && numerator != 0) {
return toString();
} else if (isInteger()) {
return Integer.toString(intValue());
} else if (numerator != 1 && denominator % numerator == 0) {
// common factor between denominator and numerator
int newDenominator = denominator / numerator;
return new Rational(1, newDenominator).toSimpleString(allowDecimal);
} else {
Rational simplifiedInstance = getSimplifiedInstance();
if (allowDecimal) {
String doubleString = Double.toString(simplifiedInstance.doubleValue());
if (doubleString.length() < 5) {
return doubleString;
}
}
return simplifiedInstance.toString();
}
}
 
/**
* Decides whether a brute-force simplification calculation should be avoided
* by comparing the maximum number of possible calculations with some threshold.
* @return true if the simplification should be performed, otherwise false
*/
private boolean tooComplexForSimplification()
{
double maxPossibleCalculations = (((double)(Math.min(denominator, numerator) - 1) / 5d) + 2);
return maxPossibleCalculations > maxSimplificationCalculations;
}
 
/**
* Compares two <code>Rational</code> instances, returning true if they are mathematically
* equivalent.
* @param obj the Rational to compare this instance to.
* @return true if instances are mathematically equivalent, otherwise false. Will also
* return false if <code>obj</code> is not an instance of <code>Rational</code>.
*/
public boolean equals(Object obj)
{
if (!(obj instanceof Rational)) {
return false;
}
Rational that = (Rational)obj;
return this.doubleValue() == that.doubleValue();
}
 
/**
* <p>
* Simplifies the Rational number.</p>
* <p>
* Prime number series: 1, 2, 3, 5, 7, 9, 11, 13, 17</p>
* <p>
* To reduce a rational, need to see if both numerator and denominator are divisible
* by a common factor. Using the prime number series in ascending order guarantees
* the minimun number of checks required.</p>
* <p>
* However, generating the prime number series seems to be a hefty task. Perhaps
* it's simpler to check if both d & n are divisible by all numbers from 2 ->
* (Math.min(denominator, numerator) / 2). In doing this, one can check for 2
* and 5 once, then ignore all even numbers, and all numbers ending in 0 or 5.
* This leaves four numbers from every ten to check.</p>
* <p>
* Therefore, the max number of pairs of modulus divisions required will be:</p>
* <code><pre>
* 4 Math.min(denominator, numerator) - 1
* -- * ------------------------------------ + 2
* 10 2
*
* Math.min(denominator, numerator) - 1
* = ------------------------------------ + 2
* 5
* </pre></code>
* @return a simplified instance, or if the Rational could not be simpliffied,
* returns itself (unchanged)
*/
public Rational getSimplifiedInstance()
{
if (tooComplexForSimplification()) {
return this;
}
for (int factor = 2; factor <= Math.min(denominator, numerator); factor++) {
if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) {
continue;
}
if (denominator % factor == 0 && numerator % factor == 0) {
// found a common factor
return new Rational(numerator / factor, denominator / factor);
}
}
return this;
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/test/NullOutputStreamTest.java
0,0 → 1,36
/**
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on Dec 15, 2002 3:30:02 PM using IntelliJ IDEA.
*/
package com.drew.lang.test;
 
import com.drew.lang.NullOutputStream;
import junit.framework.TestCase;
 
import java.io.OutputStream;
 
public class NullOutputStreamTest extends TestCase
{
public NullOutputStreamTest(String s)
{
super(s);
}
 
public void testCreateNullOutputStream() throws Exception
{
OutputStream out = new NullOutputStream();
out.write(1);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/test/RationalTest.java
0,0 → 1,96
/*
* RationalTest.java
*
* Test class written by Drew Noakes.
*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 26-Oct-2002 16:24:43 using IntelliJ IDEA.
*/
package com.drew.lang.test;
 
import com.drew.lang.Rational;
import junit.framework.TestCase;
 
/**
*
* @author Drew Noakes http://drewnoakes.com
*/
public class RationalTest extends TestCase
{
public RationalTest(String s)
{
super(s);
}
 
public void testCreateRational() throws Exception
{
Rational rational = new Rational(1, 3);
assertEquals(1, rational.getNumerator());
assertEquals(3, rational.getDenominator());
assertEquals(new Double(1d / 3d), new Double(rational.doubleValue()));
}
 
public void testToString() throws Exception
{
Rational rational = new Rational(1, 3);
assertEquals("1/3", rational.toString());
}
 
public void testToSimpleString() throws Exception
{
Rational third1 = new Rational(1, 3);
Rational third2 = new Rational(2, 6);
assertEquals("1/3", third1.toSimpleString(true));
assertEquals("1/3", third2.toSimpleString(true));
assertEquals(third1, third2);
 
Rational twoThirds = new Rational(10, 15);
assertEquals("2/3", twoThirds.toSimpleString(true));
 
Rational two = new Rational(10, 5);
assertTrue(two.isInteger());
assertEquals("2", two.toSimpleString(true));
assertEquals("2", two.toSimpleString(false));
 
Rational twoFifths = new Rational(4, 10);
assertEquals("0.4", twoFifths.toSimpleString(true));
assertEquals("2/5", twoFifths.toSimpleString(false));
 
Rational threeEigths = new Rational(3, 8);
assertEquals("3/8", threeEigths.toSimpleString(true));
 
Rational zero = new Rational(0, 8);
assertTrue(zero.isInteger());
assertEquals("0", zero.toSimpleString(true));
assertEquals("0", zero.toSimpleString(false));
 
zero = new Rational(0, 0);
assertTrue(zero.isInteger());
assertEquals("0", zero.toSimpleString(true));
assertEquals("0", zero.toSimpleString(false));
 
// not sure this is a nice presentation of rationals. won't implement it for now.
// Rational twoAndAHalf = new Rational(10,4);
// assertEquals("2 1/2", twoAndAHalf.toSimpleString());
}
 
public void testGetReciprocal() throws Exception
{
Rational rational = new Rational(1, 3);
Rational reciprocal = rational.getReciprocal();
assertEquals("new rational should be reciprocal", new Rational(3, 1), reciprocal);
assertEquals("origianl reciprocal should remain unchanged", new Rational(1, 3), rational);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/test/TestHelper.java
0,0 → 1,31
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*/
package com.drew.lang.test;
 
import junit.framework.TestCase;
 
/**
* Created by dnoakes on 07-May-2005 11:13:18 using IntelliJ IDEA.
*/
public class TestHelper
{
public static void assertEqualArrays(byte[] array1, byte[] array2)
{
TestCase.assertEquals("Equal array length", array1.length, array2.length);
 
for (int i = 0; i<array1.length; i++)
TestCase.assertEquals("Equal value at index " + i, array1[i], array2[i]);
}
}
/contrib/metadata-extractor/trunk/src/com/drew/lang/test/CompoundExceptionTest.java
0,0 → 1,74
/*
* This is public domain software - that is, you can do whatever you want
* with it, and include it software that is licensed under the GNU or the
* BSD license, or whatever other licence you choose, including proprietary
* closed source licenses. I do ask that you leave this header in tact.
*
* If you make modifications to this code that you think would benefit the
* wider community, please send me a copy and I'll post it on my site.
*
* If you make use of this code, I'd appreciate hearing about it.
* drew@drewnoakes.com
* Latest version of this software kept at
* http://drewnoakes.com/
*
* Created by dnoakes on 10-Dec-2002 12:22:38 using IntelliJ IDEA.
*/
package com.drew.lang.test;
 
import com.drew.lang.CompoundException;
import com.drew.lang.NullOutputStream;
import junit.framework.TestCase;
 
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
 
/**
*
*/
public class CompoundExceptionTest extends TestCase
{
public CompoundExceptionTest(String s)
{
super(s);
}
 
public void testUnnestedGetMessage() throws Exception
{
try {
throw new CompoundException("message");
} catch (CompoundException e) {
assertEquals("message", e.getMessage());
}
}
 
public void testNestedGetMessage() throws Exception
{
try {
try {
throw new IOException("io");
} catch (IOException e) {
throw new CompoundException("compound", e);
}
} catch (CompoundException e) {
assertEquals("compound", e.getMessage());
assertEquals("io", e.getInnerException().getMessage());
}
}
 
public void testNoInnerException() throws Exception
{
try {
throw new CompoundException("message", null);
} catch (CompoundException e) {
try {
PrintStream nullStream = new PrintStream(new NullOutputStream());
e.printStackTrace(nullStream);
e.printStackTrace(new PrintWriter(nullStream));
} catch (Exception e1) {
fail("Exception during printStackTrace for CompoundException with no inner exception");
}
}
}
}
/contrib/metadata-extractor/trunk/Libraries/junit.jar
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/contrib/metadata-extractor/trunk/build.xml
0,0 → 1,81
<?xml version="1.0"?>
 
<project name="metadata-extractor" default="test" basedir=".">
 
<description>metadata-extractor for java build file</description>
 
<property name="dist" location="Releases"/>
<property name="build" value="Build"/>
<property name="src" value="src"/>
<property name="javadoc" value="javadoc"/>
<property name="lib" value="Libraries"/>
<property name="verbose" value="true"/>
<property name="debug" value="off"/>
<property name="version" value="2.3.1"/>
<property name="classpath" value="${lib}/junit.jar"/>
 
<target name="clean" description="deletes and recreates the destination directory">
<delete verbose="${verbose}" dir="${build}"/>
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>
 
<target name="compile" description="compile the source">
<javac classpath="${classpath}"
srcdir="${src}"
destdir="${build}"
debug="${debug}"
verbose="${verbose}"/>
</target>
 
<target name="dist-binaries" depends="clean, compile, test" description="generate binary distribution">
<jar destfile="${dist}/metadata-extractor-${version}.jar" update="false">
<manifest>
<attribute name="Main-Class" value="com.drew.imaging.jpeg.JpegMetadataReader"/>
</manifest>
<fileset dir="${build}" excludes="**/test/*.class" />
</jar>
</target>
 
<target name="dist-source" depends="clean, compile, test" description="generate source distribution">
<jar destfile="${dist}/metadata-extractor-${version}-src.jar" update="false">
<fileset dir="."
includes="${src}/**/*.java, ${src}/**/*.jpg, ${src}/**/*.metadata, ${lib}/junit.jar, build.xml, ChangeLog.txt"/>
</jar>
</target>
 
<target name="test" depends="compile" description="run all junit tests">
<junit printsummary="yes" fork="yes" haltonfailure="yes">
<classpath>
<pathelement location="${build}"/>
<pathelement path="${java.class.path}"/>
</classpath>
<formatter type="plain"/>
<test name="com.drew.metadata.test.AllTests"/>
</junit>
</target>
 
<target name="javadoc" description="generate javadoc documentation">
<javadoc
destdir="${javadoc}"
defaultexcludes="yes"
author="true"
version="true"
use="true"
access="protected"
windowtitle="metadata-extractor javadoc"
failonerror="true">
 
<bottom><![CDATA[<i>Copyright &#169; 2006 Drew Noakes. All Rights Reserved.</i>]]></bottom>
 
<packageset dir="${src}" defaultexcludes="yes">
<include name="com/**"/>
<exclude name="com/**/test"/>
</packageset>
 
</javadoc>
</target>
 
<target name="all" depends="dist-source, dist-binaries, javadoc" description="prepare source and binary distributions, and javadoc"/>
 
</project>
/contrib/metadata-extractor/trunk/META-INF/MANIFEST.MF
0,0 → 1,4
Manifest-Version: 1.0
Ant-Version: Apache Ant 1.5.4
Created-By: 1.4.2_03-b02 (Sun Microsystems Inc.)