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