Subversion Repositories general

Compare Revisions

No changes between revisions

Ignore whitespace Rev 1267 → Rev 1268

/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");
}
}
}
}