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();
}
}
}