//contrib/metadata-extractor/trunk/ChangeLog.txt |
---|
0,0 → 1,182 |
v2.3.1 - 25 Feb 2006 |
------------------------------- |
- Fixed copy-and-paste errors in ExifDescriptor.java. Thanks to Ferret Renaud. |
v2.3.0 - 12 Jan 2006 |
------------------------------- |
- New tags from Exif 2.2 specification (A401-A420). |
- Fixed stack overflow exception in ExifReader for cyclic directory references. |
Thanks to John Sidney-Woollett for reporting this bug (reported for Fuji FinePix A101 and Canon 20D). |
- Fixed rounding error in the shutter speed description which was giving the wrong value most of the |
time (for example, 1/32 instead of 1/50). |
Thanks for Gli Blr and Mark Edwards for pointing out this error. |
- Fix thread safety bug in ExifReader. |
- Fixed OutOfMemoryError seen in certain Canon 20D images. |
Thanks to Henry Yeung for providing an image to reproduce this error. |
- Support for Windows XP Exif tags (Author, title, comments, etc). |
- Added more documentation, and removed commented/unused code. |
- Enhanced descriptor support for Exif tags. |
- Extract comments in non-ASCII encodings. |
- Improved camera model MakerNote support: |
- New models: |
- Epson (thanks to David Carlson for pointing me in the right direction with this) |
- Kyocera / Contax (very limited) |
- Minolta (it utilises the Olympus format) |
- Panasonic |
- Pentax / Asahi |
- Improved support for models: |
- Olympus |
- Canon (tested with newer Canon models, including the 20D) |
- Casio (for more modern models) |
- Source distribution filesize reduced by using .metadata files, rather than entire sample JPEG files. |
These .metadata files contain all non-image JPEG segments, making them suitable for unit tests whilst |
being much smaller on disk. |
v2.2.2 - 22 Nov 2003 |
------------------------------- |
- Fixed a bug where version strings were assumed to be comprised of exactly four parts, |
and cases were found where a different number existed |
v2.2.1 - 24 Oct 2003 |
------------------------------- |
- Fixed a bug where JpegDirectory had tag names for image width and height around |
the wrong way. Thanks to Sander Smith for pointing this out |
v2.2 - 18 Oct 2003 |
------------------------------- |
- Added support for extraction of Jpeg image information (from the SOF0 segment) |
Thanks to Darrell Silver for commencing the code for this extension |
- Added support for reading Jpeg comments |
- Additional Nikon camera makernote support for D1/D100 family models |
Thanks to Daniel Waeber for providing sample images and to Fabrizio Giudici for |
publishing his work in decoding this makernote data |
- Added convenient writing of thumbnails to files from ExifDirectory |
- Fixed a bug in date format strings, whereby times in the AM / PM were indistinguishable |
Thanks to Bill Boland for being the first person to point this out (this was a popular one!) |
- Fixed bug for multi-component tag values of certain types |
Thanks to Derek Wegner for identifying the bug and providing a solution |
- More unit tests (consequently, the source-code download is much larger) |
- First version with an Ant build script |
v2.1 - 12 Jan 2003 |
------------------------------- |
- Extract methods no longer throw exceptions, with error information stored |
in Metadata instances, using hasErrors() and getErrors() |
- Metadata and dependant classes now serializable for network transmission, |
and persistance in files & databases |
- Support for extracting metadata from InputStreams, such as network connections |
- Replaced code that depended upon JDK 1.4 |
v2.0 - 10 Dec 2002 |
------------------------------- |
Enormous changes to the class and package structure in this release prohibit a |
class-by-class breakdown of changes. The focus is no longer on Exif metadata |
alone, but now on general metadata extraction from multiple media types. |
Changes support: |
- easier future extensibility |
- Iptc metadata extraction |
- multiple directories of tags |
- descriptor class for interpreting values in a given directory |
- multiple media and metadata types |
- enhanced handling of exif makernote values |
- many more unit tests |
- numerous enhancements |
- minor bug fixes |
Simpler extensibility changes the focus from exif extraction alone and opens |
the scope to general metadata extraction. Future development will introduce |
new media and metadata support with little or no impact to existing classes. |
v1.2 - 6 Nov 2002 |
------------------------------- |
ExifExtractor.java |
- Proper traversing of Exif file structure and complete refactor & tidy of |
the codebase (a few unnoticed bugs removed) |
- Reads makernote data for 6 families of camera (5 makes) |
- Tags now stored in directories... use the IFD_* constants to refer to the |
image file directory you require (Exif, Interop, GPS and Makernote*) -- |
this avoids collisions where two tags share the same code |
- Correct extraction of multi-component values |
- No longer decodes image to extract Exif data -- this is much faster |
- Takes componentCount of unknown tags into account |
- Now understands GPS tags (thanks to Colin Briton for his help with this) |
- Returns null when no Exif data present, instead of throwing an exception |
- Some other bug fixes, pointed out by users around the world. Thanks! |
ExifLoader |
- Removed (unnecessary) |
ImageInfo.java |
- Stored IFD directories in separate tag-spaces |
- iterator() now returns an Iterator over a list of TagValue objects |
- More get*Description() methods to detail GPS tags, among others |
TagValue.java |
- New class to encapsualte information about a particular tag |
Rational.java |
- Improved toSimpleString() to factor more complex rational numbers into |
a simpler form |
i.e. |
10/15 -> 2/3 |
- toSimpleString() now accepts a boolean flag, 'allowDecimals' which will |
display the rational number in decimal form if it fits within 5 digits |
i.e. |
3/4 -> 0.75 when allowDecimal == true |
JpegSegmentReader |
- New class to extract APP1 segment (and others) from a Jpeg file -- this |
avoids decoding images just to get metadata |
tests\*.java |
- First collection of basic unit tests, to compile against JUnit |
- Doesn't yet cover all classes |
Website |
- A collection of JPEGs from various digital camera models, collected on |
the web and contributed by many users of ExifExtractor |
- Updated documentation |
v1.1.1 |
------------------------------- |
Rational.java |
- Added toSimpleString() method, which returns a simplified and hopefully |
more readable version of the Rational |
i.e. |
2/10 -> 1/5 |
10/2 -> 5 |
ExifExtractor.java |
- Removed unnecessary casting operations |
- Added a few more comments |
- Removed redundant and commented code (I'm using a CVS system now) |
ExifLoader.java |
- Added a much-needed close() call to a created input stream, allowing |
continued use of the File object passed to ExifLoader.getImageInfo(File) |
ImageInfo.java |
- Make use of new Rational method toSimpleString() for more elegant output - |
Use of DecimalFormatter to tidy output in selected get***Description() methods |
v1.1.0 - 28 Aug 2002 |
------------------------------- |
- Descriptive tag values, including units and text for enumerations |
- Decoupling from JDK 1.4-specific libraries (tested with JDK 1.3) |
- More complete list of tags, both as constants for direct lookup, and via the |
static lookup method |
v1.0 |
------------------------------- |
- Initial release |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/PhotographicConversions.java |
---|
0,0 → 1,51 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.imaging; |
/** |
* Contains helper methods that perform photographic conversions. |
*/ |
public class PhotographicConversions |
{ |
public final static double ROOT_TWO = Math.sqrt(2); |
private PhotographicConversions() |
{} |
/** |
* Converts an aperture value to its corresponding F-stop number. |
* @param aperture the aperture value to convert |
* @return the F-stop number of the specified aperture |
*/ |
public static double apertureToFStop(double aperture) |
{ |
double fStop = Math.pow(ROOT_TWO, aperture); |
return fStop; |
// Puzzle?! |
// jhead uses a different calculation as far as i can tell... this confuses me... |
// fStop = (float)Math.exp(aperture * Math.log(2) * 0.5)); |
} |
/** |
* Converts a shutter speed to an exposure time. |
* @param shutterSpeed the shutter speed to convert |
* @return the exposure time of the specified shutter speed |
*/ |
public static double shutterSpeedToExposureTime(double shutterSpeed) |
{ |
return (float)(1 / Math.exp(shutterSpeed * Math.log(2))); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegMetadataReader.java |
---|
0,0 → 1,172 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 18:51:36 using IntelliJ IDEA. |
*/ |
package com.drew.imaging.jpeg; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.Tag; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.ExifReader; |
import com.drew.metadata.iptc.IptcReader; |
import com.drew.metadata.jpeg.JpegCommentReader; |
import com.drew.metadata.jpeg.JpegReader; |
import com.sun.image.codec.jpeg.JPEGDecodeParam; |
import java.io.File; |
import java.io.IOException; |
import java.io.InputStream; |
import java.util.Iterator; |
/** |
* |
*/ |
public class JpegMetadataReader |
{ |
// public static Metadata readMetadata(IIOMetadata metadata) throws JpegProcessingException {} |
// public static Metadata readMetadata(ImageInputStream in) throws JpegProcessingException{} |
// public static Metadata readMetadata(IIOImage image) throws JpegProcessingException{} |
// public static Metadata readMetadata(ImageReader reader) throws JpegProcessingException{} |
public static Metadata readMetadata(InputStream in) throws JpegProcessingException |
{ |
JpegSegmentReader segmentReader = new JpegSegmentReader(in); |
return extractMetadataFromJpegSegmentReader(segmentReader); |
} |
public static Metadata readMetadata(File file) throws JpegProcessingException |
{ |
JpegSegmentReader segmentReader = new JpegSegmentReader(file); |
return extractMetadataFromJpegSegmentReader(segmentReader); |
} |
public static Metadata extractMetadataFromJpegSegmentReader(JpegSegmentReader segmentReader) |
{ |
final Metadata metadata = new Metadata(); |
try { |
byte[] exifSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1); |
new ExifReader(exifSegment).extract(metadata); |
} catch (JpegProcessingException e) { |
// in the interests of catching as much data as possible, continue |
// TODO lodge error message within exif directory? |
} |
try { |
byte[] iptcSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD); |
new IptcReader(iptcSegment).extract(metadata); |
} catch (JpegProcessingException e) { |
// TODO lodge error message within iptc directory? |
} |
try { |
byte[] jpegSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_SOF0); |
new JpegReader(jpegSegment).extract(metadata); |
} catch (JpegProcessingException e) { |
// TODO lodge error message within jpeg directory? |
} |
try { |
byte[] jpegCommentSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_COM); |
new JpegCommentReader(jpegCommentSegment).extract(metadata); |
} catch (JpegProcessingException e) { |
// TODO lodge error message within jpegcomment directory? |
} |
return metadata; |
} |
public static Metadata readMetadata(JPEGDecodeParam decodeParam) |
{ |
final Metadata metadata = new Metadata(); |
/* We should only really be seeing Exif in _data[0]... the 2D array exists |
* because markers can theoretically appear multiple times in the file. |
*/ |
// TODO test this method |
byte[][] exifSegment = decodeParam.getMarkerData(JPEGDecodeParam.APP1_MARKER); |
if (exifSegment != null && exifSegment[0].length>0) { |
new ExifReader(exifSegment[0]).extract(metadata); |
} |
// similarly, use only the first IPTC segment |
byte[][] iptcSegment = decodeParam.getMarkerData(JPEGDecodeParam.APPD_MARKER); |
if (iptcSegment != null && iptcSegment[0].length>0) { |
new IptcReader(iptcSegment[0]).extract(metadata); |
} |
// NOTE: Unable to utilise JpegReader for the SOF0 frame here, as the decodeParam doesn't contain the byte[] |
// similarly, use only the first Jpeg Comment segment |
byte[][] jpegCommentSegment = decodeParam.getMarkerData(JPEGDecodeParam.COMMENT_MARKER); |
if (jpegCommentSegment != null && jpegCommentSegment[0].length>0) { |
new JpegCommentReader(jpegCommentSegment[0]).extract(metadata); |
} |
return metadata; |
} |
private JpegMetadataReader() |
{ |
} |
public static void main(String[] args) throws MetadataException, IOException |
{ |
Metadata metadata = null; |
try { |
metadata = JpegMetadataReader.readMetadata(new File(args[0])); |
} catch (Exception e) { |
e.printStackTrace(System.err); |
System.exit(1); |
} |
// iterate over the exif data and print to System.out |
Iterator directories = metadata.getDirectoryIterator(); |
while (directories.hasNext()) { |
Directory directory = (Directory)directories.next(); |
Iterator tags = directory.getTagIterator(); |
while (tags.hasNext()) { |
Tag tag = (Tag)tags.next(); |
try { |
System.out.println("[" + directory.getName() + "] " + tag.getTagName() + " = " + tag.getDescription()); |
} catch (MetadataException e) { |
System.err.println(e.getMessage()); |
System.err.println(tag.getDirectoryName() + " " + tag.getTagName() + " (error)"); |
} |
} |
if (directory.hasErrors()) { |
Iterator errors = directory.getErrors(); |
while (errors.hasNext()) { |
System.out.println("ERROR: " + errors.next()); |
} |
} |
} |
if (args.length>1 && args[1].trim().equals("/thumb")) |
{ |
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
if (directory.containsThumbnail()) |
{ |
System.out.println("Writing thumbnail..."); |
directory.writeThumbnail(args[0].trim() + ".thumb.jpg"); |
} |
else |
{ |
System.out.println("No thumbnail data exists in this image"); |
} |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegSegmentReader.java |
---|
0,0 → 1,283 |
/* |
* JpegSegmentReader.java |
* |
* This class written by Drew Noakes, in accordance with the Jpeg specification. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 04-Nov-2002 00:54:00 using IntelliJ IDEA |
*/ |
package com.drew.imaging.jpeg; |
import java.io.*; |
/** |
* Performs read functions of Jpeg files, returning specific file segments. |
* TODO add a findAvailableSegments() method |
* TODO add more segment identifiers |
* TODO add a getSegmentDescription() method, returning for example 'App1 application data segment, commonly containing Exif data' |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class JpegSegmentReader |
{ |
// Jpeg data can be sourced from either a file, byte[] or InputStream |
/** Jpeg file */ |
private final File _file; |
/** Jpeg data as byte array */ |
private final byte[] _data; |
/** Jpeg data as an InputStream */ |
private final InputStream _stream; |
private JpegSegmentData _segmentData; |
/** |
* Private, because this segment crashes my algorithm, and searching for |
* it doesn't work (yet). |
*/ |
private static final byte SEGMENT_SOS = (byte)0xDA; |
/** |
* Private, because one wouldn't search for it. |
*/ |
private static final byte MARKER_EOI = (byte)0xD9; |
/** APP0 Jpeg segment identifier -- Jfif data. */ |
public static final byte SEGMENT_APP0 = (byte)0xE0; |
/** APP1 Jpeg segment identifier -- where Exif data is kept. */ |
public static final byte SEGMENT_APP1 = (byte)0xE1; |
/** APP2 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP2 = (byte)0xE2; |
/** APP3 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP3 = (byte)0xE3; |
/** APP4 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP4 = (byte)0xE4; |
/** APP5 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP5 = (byte)0xE5; |
/** APP6 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP6 = (byte)0xE6; |
/** APP7 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP7 = (byte)0xE7; |
/** APP8 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP8 = (byte)0xE8; |
/** APP9 Jpeg segment identifier. */ |
public static final byte SEGMENT_APP9 = (byte)0xE9; |
/** APPA Jpeg segment identifier -- can hold Unicode comments. */ |
public static final byte SEGMENT_APPA = (byte)0xEA; |
/** APPB Jpeg segment identifier. */ |
public static final byte SEGMENT_APPB = (byte)0xEB; |
/** APPC Jpeg segment identifier. */ |
public static final byte SEGMENT_APPC = (byte)0xEC; |
/** APPD Jpeg segment identifier -- IPTC data in here. */ |
public static final byte SEGMENT_APPD = (byte)0xED; |
/** APPE Jpeg segment identifier. */ |
public static final byte SEGMENT_APPE = (byte)0xEE; |
/** APPF Jpeg segment identifier. */ |
public static final byte SEGMENT_APPF = (byte)0xEF; |
/** Start Of Image segment identifier. */ |
public static final byte SEGMENT_SOI = (byte)0xD8; |
/** Define Quantization Table segment identifier. */ |
public static final byte SEGMENT_DQT = (byte)0xDB; |
/** Define Huffman Table segment identifier. */ |
public static final byte SEGMENT_DHT = (byte)0xC4; |
/** Start-of-Frame Zero segment identifier. */ |
public static final byte SEGMENT_SOF0 = (byte)0xC0; |
/** Jpeg comment segment identifier. */ |
public static final byte SEGMENT_COM = (byte)0xFE; |
/** |
* Creates a JpegSegmentReader for a specific file. |
* @param file the Jpeg file to read segments from |
*/ |
public JpegSegmentReader(File file) throws JpegProcessingException |
{ |
_file = file; |
_data = null; |
_stream = null; |
readSegments(); |
} |
/** |
* Creates a JpegSegmentReader for a byte array. |
* @param fileContents the byte array containing Jpeg data |
*/ |
public JpegSegmentReader(byte[] fileContents) throws JpegProcessingException |
{ |
_file = null; |
_data = fileContents; |
_stream = null; |
readSegments(); |
} |
public JpegSegmentReader(InputStream in) throws JpegProcessingException |
{ |
_stream = in; |
_file = null; |
_data = null; |
readSegments(); |
} |
public JpegSegmentReader(JpegSegmentData segmentData) |
{ |
_file = null; |
_data = null; |
_stream = null; |
_segmentData = segmentData; |
} |
/** |
* Reads the first instance of a given Jpeg segment, returning the contents as |
* a byte array. |
* @param segmentMarker the byte identifier for the desired segment |
* @return the byte array if found, else null |
* @throws JpegProcessingException for any problems processing the Jpeg data, |
* including inner IOExceptions |
*/ |
public byte[] readSegment(byte segmentMarker) throws JpegProcessingException |
{ |
return readSegment(segmentMarker, 0); |
} |
/** |
* Reads the first instance of a given Jpeg segment, returning the contents as |
* a byte array. |
* @param segmentMarker the byte identifier for the desired segment |
* @param occurrence the occurrence of the specified segment within the jpeg file |
* @return the byte array if found, else null |
*/ |
public byte[] readSegment(byte segmentMarker, int occurrence) |
{ |
return _segmentData.getSegment(segmentMarker, occurrence); |
} |
public final int getSegmentCount(byte segmentMarker) |
{ |
return _segmentData.getSegmentCount(segmentMarker); |
} |
public final JpegSegmentData getSegmentData() |
{ |
return _segmentData; |
} |
private void readSegments() throws JpegProcessingException |
{ |
_segmentData = new JpegSegmentData(); |
BufferedInputStream inStream = getJpegInputStream(); |
try { |
int offset = 0; |
// first two bytes should be jpeg magic number |
if (!isValidJpegHeaderBytes(inStream)) { |
throw new JpegProcessingException("not a jpeg file"); |
} |
offset += 2; |
do { |
// next byte is 0xFF |
byte segmentIdentifier = (byte)(inStream.read() & 0xFF); |
if ((segmentIdentifier & 0xFF) != 0xFF) { |
throw new JpegProcessingException("expected jpeg segment start identifier 0xFF at offset " + offset + ", not 0x" + Integer.toHexString(segmentIdentifier & 0xFF)); |
} |
offset++; |
// next byte is <segment-marker> |
byte thisSegmentMarker = (byte)(inStream.read() & 0xFF); |
offset++; |
// next 2-bytes are <segment-size>: [high-byte] [low-byte] |
byte[] segmentLengthBytes = new byte[2]; |
inStream.read(segmentLengthBytes, 0, 2); |
offset += 2; |
int segmentLength = ((segmentLengthBytes[0] << 8) & 0xFF00) | (segmentLengthBytes[1] & 0xFF); |
// segment length includes size bytes, so subtract two |
segmentLength -= 2; |
if (segmentLength > inStream.available()) |
throw new JpegProcessingException("segment size would extend beyond file stream length"); |
else if (segmentLength < 0) |
throw new JpegProcessingException("segment size would be less than zero"); |
byte[] segmentBytes = new byte[segmentLength]; |
inStream.read(segmentBytes, 0, segmentLength); |
offset += segmentLength; |
if ((thisSegmentMarker & 0xFF) == (SEGMENT_SOS & 0xFF)) { |
// The 'Start-Of-Scan' segment's length doesn't include the image data, instead would |
// have to search for the two bytes: 0xFF 0xD9 (EOI). |
// It comes last so simply return at this point |
return; |
} else if ((thisSegmentMarker & 0xFF) == (MARKER_EOI & 0xFF)) { |
// the 'End-Of-Image' segment -- this should never be found in this fashion |
return; |
} else { |
_segmentData.addSegment(thisSegmentMarker, segmentBytes); |
} |
// didn't find the one we're looking for, loop through to the next segment |
} while (true); |
} catch (IOException ioe) { |
//throw new JpegProcessingException("IOException processing Jpeg file", ioe); |
throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe); |
} finally { |
try { |
if (inStream != null) { |
inStream.close(); |
} |
} catch (IOException ioe) { |
//throw new JpegProcessingException("IOException processing Jpeg file", ioe); |
throw new JpegProcessingException("IOException processing Jpeg file: " + ioe.getMessage(), ioe); |
} |
} |
} |
/** |
* Private helper method to create a BufferedInputStream of Jpeg data from whichever |
* data source was specified upon construction of this instance. |
* @return a a BufferedInputStream of Jpeg data |
* @throws JpegProcessingException for any problems obtaining the stream |
*/ |
private BufferedInputStream getJpegInputStream() throws JpegProcessingException |
{ |
if (_stream!=null) { |
if (_stream instanceof BufferedInputStream) { |
return (BufferedInputStream) _stream; |
} else { |
return new BufferedInputStream(_stream); |
} |
} |
InputStream inputStream; |
if (_data == null) { |
try { |
inputStream = new FileInputStream(_file); |
} catch (FileNotFoundException e) { |
throw new JpegProcessingException("Jpeg file does not exist", e); |
} |
} else { |
inputStream = new ByteArrayInputStream(_data); |
} |
return new BufferedInputStream(inputStream); |
} |
/** |
* Helper method that validates the Jpeg file's magic number. |
* @param fileStream the InputStream to read bytes from, which must be positioned |
* at its start (i.e. no bytes read yet) |
* @return true if the magic number is Jpeg (0xFFD8) |
* @throws IOException for any problem in reading the file |
*/ |
private boolean isValidJpegHeaderBytes(InputStream fileStream) throws IOException |
{ |
byte[] header = new byte[2]; |
fileStream.read(header, 0, 2); |
return (header[0] & 0xFF) == 0xFF && (header[1] & 0xFF) == 0xD8; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegSegmentDataTest.java |
---|
0,0 → 1,158 |
/* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.imaging.jpeg.test; |
import com.drew.imaging.jpeg.JpegSegmentData; |
import com.drew.lang.test.TestHelper; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class JpegSegmentDataTest extends TestCase |
{ |
public JpegSegmentDataTest(String name) |
{ |
super(name); |
} |
public void testAddAndGetSegment() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes = new byte[] { 1,2,3 }; |
segmentData.addSegment(segmentMarker, segmentBytes); |
assertEquals(1, segmentData.getSegmentCount(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes, segmentData.getSegment(segmentMarker)); |
} |
public void testContainsSegment() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes = new byte[] { 1,2,3 }; |
assertTrue(!segmentData.containsSegment(segmentMarker)); |
segmentData.addSegment(segmentMarker, segmentBytes); |
assertTrue(segmentData.containsSegment(segmentMarker)); |
} |
public void testAddingMultipleSegments() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker1 = (byte)12; |
byte segmentMarker2 = (byte)21; |
byte[] segmentBytes1 = new byte[] { 1,2,3 }; |
byte[] segmentBytes2 = new byte[] { 3,2,1 }; |
segmentData.addSegment(segmentMarker1, segmentBytes1); |
segmentData.addSegment(segmentMarker2, segmentBytes2); |
assertEquals(1, segmentData.getSegmentCount(segmentMarker1)); |
assertEquals(1, segmentData.getSegmentCount(segmentMarker2)); |
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker1)); |
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker2)); |
} |
public void testSegmentWithMultipleOccurrences() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes1 = new byte[] { 1,2,3 }; |
byte[] segmentBytes2 = new byte[] { 3,2,1 }; |
segmentData.addSegment(segmentMarker, segmentBytes1); |
segmentData.addSegment(segmentMarker, segmentBytes2); |
assertEquals(2, segmentData.getSegmentCount(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0)); |
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker, 1)); |
} |
public void testRemoveSegmentOccurrence() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes1 = new byte[] { 1,2,3 }; |
byte[] segmentBytes2 = new byte[] { 3,2,1 }; |
segmentData.addSegment(segmentMarker, segmentBytes1); |
segmentData.addSegment(segmentMarker, segmentBytes2); |
assertEquals(2, segmentData.getSegmentCount(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0)); |
segmentData.removeSegmentOccurrence(segmentMarker, 0); |
TestHelper.assertEqualArrays(segmentBytes2, segmentData.getSegment(segmentMarker, 0)); |
} |
public void testRemoveSegment() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes1 = new byte[] { 1,2,3 }; |
byte[] segmentBytes2 = new byte[] { 3,2,1 }; |
segmentData.addSegment(segmentMarker, segmentBytes1); |
segmentData.addSegment(segmentMarker, segmentBytes2); |
assertEquals(2, segmentData.getSegmentCount(segmentMarker)); |
assertTrue(segmentData.containsSegment(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes1, segmentData.getSegment(segmentMarker, 0)); |
segmentData.removeSegment(segmentMarker); |
assertTrue(!segmentData.containsSegment(segmentMarker)); |
assertEquals(0, segmentData.getSegmentCount(segmentMarker)); |
} |
public void testToAndFromFile() throws Exception |
{ |
JpegSegmentData segmentData = new JpegSegmentData(); |
byte segmentMarker = (byte)12; |
byte[] segmentBytes = new byte[] { 1,2,3 }; |
segmentData.addSegment(segmentMarker, segmentBytes); |
assertTrue(segmentData.containsSegment(segmentMarker)); |
File tempFile = File.createTempFile("JpegSegmentDataTest", "tmp"); |
JpegSegmentData.ToFile(tempFile, segmentData); |
assertTrue(tempFile.exists()); |
assertTrue(tempFile.length() > 0); |
segmentData = JpegSegmentData.FromFile(tempFile); |
tempFile.delete(); |
assertTrue(!tempFile.exists()); |
assertNotNull(segmentData); |
assertTrue(segmentData.containsSegment(segmentMarker)); |
TestHelper.assertEqualArrays(segmentBytes, segmentData.getSegment(segmentMarker)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegMetadataReaderTest.java |
---|
0,0 → 1,60 |
/* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 18:52:05 using IntelliJ IDEA. |
*/ |
package com.drew.imaging.jpeg.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import junit.framework.TestCase; |
import java.io.BufferedInputStream; |
import java.io.File; |
import java.io.FileInputStream; |
import java.io.InputStream; |
/** |
* |
*/ |
public class JpegMetadataReaderTest extends TestCase |
{ |
public JpegMetadataReaderTest(String s) |
{ |
super(s); |
} |
public void testExtractMetadata() throws Exception |
{ |
File withExif = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
Metadata metadata = JpegMetadataReader.readMetadata(withExif); |
assertTrue(metadata.containsDirectory(ExifDirectory.class)); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals("80", directory.getString(ExifDirectory.TAG_ISO_EQUIVALENT)); |
} |
public void testExtractMetadataUsingInputStream() throws Exception |
{ |
File withExif = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
InputStream in = new BufferedInputStream(new FileInputStream((withExif))); |
Metadata metadata = JpegMetadataReader.readMetadata(in); |
assertTrue(metadata.containsDirectory(ExifDirectory.class)); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals("80", directory.getString(ExifDirectory.TAG_ISO_EQUIVALENT)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/withExifAndIptc.metadata |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/test/JpegSegmentReaderTest.java |
---|
0,0 → 1,157 |
/* |
* JpegSegmentReaderTest.java |
* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 04-Nov-2002 00:54:00 using IntelliJ IDEA |
*/ |
package com.drew.imaging.jpeg.test; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.exif.ExifReader; |
import com.drew.metadata.iptc.IptcReader; |
import junit.framework.TestCase; |
import java.io.File; |
import java.io.FileInputStream; |
import java.io.InputStream; |
/** |
* Contains JUnit tests for the JpegSegmentReader class. |
*/ |
public class JpegSegmentReaderTest extends TestCase |
{ |
public JpegSegmentReaderTest(String s) |
{ |
super(s); |
} |
public void testIsJpegWithJpegFile() throws Exception |
{ |
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
try { |
new JpegSegmentReader(jpeg); |
} catch (JpegProcessingException e) { |
fail("Error creating JpegSegmentReader"); |
} |
} |
public void testIsJpegWithNonJpegFile() throws Exception |
{ |
File nonJpeg = new File("src/com/drew/metadata/test/AllTests.java"); |
try { |
new JpegSegmentReader(nonJpeg); |
fail("shouldn't be able to construct JpegSegmentReader with non-jpeg file"); |
} catch (JpegProcessingException e) { |
// expect exception |
} |
} |
public void testReadApp1Segment() throws Exception |
{ |
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
JpegSegmentReader segmentReader = new JpegSegmentReader(jpeg); |
byte[] exifData = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1); |
assertTrue("exif data too short", exifData.length > 4); |
assertEquals("Exif", new String(exifData, 0, 4)); |
} |
public void testReadDQTSegment() throws Exception |
{ |
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
JpegSegmentReader segmentReader = new JpegSegmentReader(jpeg); |
byte[] quantizationTableData = segmentReader.readSegment(JpegSegmentReader.SEGMENT_DQT); |
assertTrue("shouldn't have zero length quantizationTableData", quantizationTableData.length > 0); |
assertTrue("quantizationTableData shouldn't start with 'Exif'", !"Exif".equals(new String(quantizationTableData, 0, 4))); |
} |
public void testReadJpegByteArray() throws Exception |
{ |
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
byte[] fileContents = new byte[(int)jpeg.length()]; |
new FileInputStream(jpeg).read(fileContents); |
new JpegSegmentReader(fileContents).readSegment(JpegSegmentReader.SEGMENT_APP1); |
} |
public void testCreateWithInputStream() throws Exception |
{ |
File jpeg = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
InputStream in = new FileInputStream(jpeg); |
JpegSegmentReader reader = null; |
try { |
reader = new JpegSegmentReader(in); |
} catch (JpegProcessingException e) { |
fail("Error constructing JpegSegmentReader using InputStream"); |
} |
// this will never happen, as fail() is guaranteed to throw an AssertionException |
if (reader==null) |
return; |
byte[] exifData = reader.readSegment(JpegSegmentReader.SEGMENT_APP1); |
assertEquals("Exif", new String(exifData, 0, 4)); |
} |
public void testReadSecondSegmentInstanace() throws Exception |
{ |
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg"); |
JpegSegmentReader reader = new JpegSegmentReader(jpeg); |
byte[] exifData0 = reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 0); |
byte[] exifData1 = reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 1); |
assertEquals("Exif", new String(exifData0, 0, 4)); |
assertEquals("http", new String(exifData1, 0, 4)); |
} |
public void testReadNonExistantSegmentInstance() throws Exception |
{ |
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg"); |
JpegSegmentReader reader = new JpegSegmentReader(jpeg); |
assertNull("third exif segment shouldn't exist", reader.readSegment(JpegSegmentReader.SEGMENT_APP1, 3)); |
} |
public void testGetSegmentCount() throws Exception |
{ |
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg"); |
JpegSegmentReader reader = new JpegSegmentReader(jpeg); |
assertEquals(2, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP1)); |
assertEquals(1, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP2)); |
assertEquals(0, reader.getSegmentCount(JpegSegmentReader.SEGMENT_APP3)); |
} |
public void testCreateWithFileAndReadMultipleSegments() throws Exception |
{ |
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg"); |
JpegSegmentReader reader = new JpegSegmentReader(jpeg); |
validateMultipleSegmentRead(reader); |
} |
public void testCreateWithInputStreamAndReadMultipleSegments() throws Exception |
{ |
File jpeg = new File("src/com/drew/imaging/jpeg/test/withExifAndIptc.jpg"); |
InputStream in = new FileInputStream(jpeg); |
JpegSegmentReader reader = new JpegSegmentReader(in); |
validateMultipleSegmentRead(reader); |
} |
private void validateMultipleSegmentRead(JpegSegmentReader reader) throws JpegProcessingException |
{ |
byte[] iptcData = reader.readSegment(JpegSegmentReader.SEGMENT_APPD); |
byte[] exifData = reader.readSegment(JpegSegmentReader.SEGMENT_APP1); |
assertTrue("exif data too short", exifData.length > 4); |
new ExifReader(exifData).extract(); |
new IptcReader(iptcData).extract(); |
assertEquals("Exif", new String(exifData, 0, 4)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegProcessingException.java |
---|
0,0 → 1,44 |
/* |
* JpegProcessingException.java |
* |
* This class is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 04-Nov-2002 19:31:29 using IntelliJ IDEA. |
*/ |
package com.drew.imaging.jpeg; |
import com.drew.lang.CompoundException; |
/** |
* An exception class thrown upon unexpected and fatal conditions while processing |
* a Jpeg file. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class JpegProcessingException extends CompoundException |
{ |
public JpegProcessingException(String message) |
{ |
super(message); |
} |
public JpegProcessingException(String message, Throwable cause) |
{ |
super(message, cause); |
} |
public JpegProcessingException(Throwable cause) |
{ |
super(cause); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/imaging/jpeg/JpegSegmentData.java |
---|
0,0 → 1,132 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.imaging.jpeg; |
import java.io.*; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.List; |
/** |
* Holds a collection of Jpeg data segments. This need not necessarily be all segments |
* within the Jpeg. For example, it may be convenient to port about only the non-image |
* segments when analysing (or serializing) metadata. |
*/ |
public class JpegSegmentData implements Serializable |
{ |
static final long serialVersionUID = 7110175216435025451L; |
/** A map of byte[], keyed by the segment marker */ |
private final HashMap _segmentDataMap; |
public JpegSegmentData() |
{ |
_segmentDataMap = new HashMap(10); |
} |
public void addSegment(byte segmentMarker, byte[] segmentBytes) |
{ |
List segmentList = getOrCreateSegmentList(segmentMarker); |
segmentList.add(segmentBytes); |
} |
public byte[] getSegment(byte segmentMarker) |
{ |
return getSegment(segmentMarker, 0); |
} |
public byte[] getSegment(byte segmentMarker, int occurrence) |
{ |
final List segmentList = getSegmentList(segmentMarker); |
if (segmentList==null || segmentList.size()<=occurrence) |
return null; |
else |
return (byte[]) segmentList.get(occurrence); |
} |
public int getSegmentCount(byte segmentMarker) |
{ |
final List segmentList = getSegmentList(segmentMarker); |
if (segmentList==null) |
return 0; |
else |
return segmentList.size(); |
} |
public void removeSegmentOccurrence(byte segmentMarker, int occurrence) |
{ |
final List segmentList = (List)_segmentDataMap.get(new Byte(segmentMarker)); |
segmentList.remove(occurrence); |
} |
public void removeSegment(byte segmentMarker) |
{ |
_segmentDataMap.remove(new Byte(segmentMarker)); |
} |
private List getSegmentList(byte segmentMarker) |
{ |
return (List)_segmentDataMap.get(new Byte(segmentMarker)); |
} |
private List getOrCreateSegmentList(byte segmentMarker) |
{ |
List segmentList; |
Byte key = new Byte(segmentMarker); |
if (_segmentDataMap.containsKey(key)) { |
segmentList = (List)_segmentDataMap.get(key); |
} else { |
segmentList = new ArrayList(); |
_segmentDataMap.put(key, segmentList); |
} |
return segmentList; |
} |
public boolean containsSegment(byte segmentMarker) |
{ |
return _segmentDataMap.containsKey(new Byte(segmentMarker)); |
} |
public static void ToFile(File file, JpegSegmentData segmentData) throws IOException |
{ |
ObjectOutputStream outputStream = null; |
try |
{ |
outputStream = new ObjectOutputStream(new FileOutputStream(file)); |
outputStream.writeObject(segmentData); |
} |
finally |
{ |
if (outputStream!=null) |
outputStream.close(); |
} |
} |
public static JpegSegmentData FromFile(File file) throws IOException, ClassNotFoundException |
{ |
ObjectInputStream inputStream = null; |
try |
{ |
inputStream = new ObjectInputStream(new FileInputStream(file)); |
return (JpegSegmentData)inputStream.readObject(); |
} |
finally |
{ |
if (inputStream!=null) |
inputStream.close(); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/TagDescriptor.java |
---|
0,0 → 1,46 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata; |
import java.io.Serializable; |
/** |
* Abstract base class for all tag descriptor classes. Implementations are responsible for |
* providing the human-readable string represenation of tag values stored in a directory. |
* The directory is provided to the tag descriptor via its constructor. |
*/ |
public abstract class TagDescriptor implements Serializable |
{ |
protected final Directory _directory; |
public TagDescriptor(Directory directory) |
{ |
_directory = directory; |
} |
/** |
* Returns a descriptive value of the the specified tag for this image. |
* Where possible, known values will be substituted here in place of the raw |
* tokens actually kept in the Exif segment. If no substitution is |
* available, the value provided by getString(int) will be returned. |
* <p> |
* This and getString(int) are the only 'get' methods that won't throw an |
* exception. |
* @param tagType the tag to find a description for |
* @return a description of the image's value for the specified tag, or |
* <code>null</code> if the tag hasn't been defined. |
*/ |
public abstract String getDescription(int tagType) throws MetadataException; |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/Tag.java |
---|
0,0 → 1,101 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Nov-2002 18:29:12 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
import java.io.Serializable; |
/** |
* |
*/ |
public class Tag implements Serializable |
{ |
private final int _tagType; |
private final Directory _directory; |
public Tag(int tagType, Directory directory) |
{ |
_tagType = tagType; |
_directory = directory; |
} |
/** |
* Gets the tag type as an int |
* @return the tag type as an int |
*/ |
public int getTagType() |
{ |
return _tagType; |
} |
/** |
* Gets the tag type in hex notation as a String with padded leading |
* zeroes if necessary (i.e. <code>0x100E</code>). |
* @return the tag type as a string in hexadecimal notation |
*/ |
public String getTagTypeHex() |
{ |
String hex = Integer.toHexString(_tagType); |
while (hex.length() < 4) hex = "0" + hex; |
return "0x" + hex; |
} |
/** |
* Get a description of the tag's value, considering enumerated values |
* and units. |
* @return a description of the tag's value |
*/ |
public String getDescription() throws MetadataException |
{ |
return _directory.getDescription(_tagType); |
} |
/** |
* Get the name of the tag, such as <code>Aperture</code>, or |
* <code>InteropVersion</code>. |
* @return the tag's name |
*/ |
public String getTagName() |
{ |
return _directory.getTagName(_tagType); |
} |
/** |
* Get the name of the directory in which the tag exists, such as |
* <code>Exif</code>, <code>GPS</code> or <code>Interoperability</code>. |
* @return name of the directory in which this tag exists |
*/ |
public String getDirectoryName() |
{ |
return _directory.getName(); |
} |
/** |
* A basic representation of the tag's type and value in format: |
* <code>FNumber - F2.8</code>. |
* @return the tag's type and value |
*/ |
public String toString() |
{ |
String description; |
try { |
description = getDescription(); |
} catch (MetadataException e) { |
description = _directory.getString(getTagType()) + " (unable to formulate description)"; |
} |
return "[" + _directory.getName() + "] " + getTagName() + " - " + description; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/FujifilmMakernoteDescriptor.java |
---|
0,0 → 1,311 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Fujifilm's digicam added the MakerNote tag from the Year2000's model (e.g.Finepix1400, |
* Finepix4700). It uses IFD format and start from ASCII character 'FUJIFILM', and next 4 |
* bytes(value 0x000c) points the offset to first IFD entry. Example of actual data |
* structure is shown below. |
* |
* :0000: 46 55 4A 49 46 49 4C 4D-0C 00 00 00 0F 00 00 00 :0000: FUJIFILM........ |
* :0010: 07 00 04 00 00 00 30 31-33 30 00 10 02 00 08 00 :0010: ......0130...... |
* |
* There are two big differences to the other manufacturers. |
* - Fujifilm's Exif data uses Motorola align, but MakerNote ignores it and uses Intel |
* align. |
* - The other manufacturer's MakerNote counts the "offset to data" from the first byte |
* of TIFF header (same as the other IFD), but Fujifilm counts it from the first byte |
* of MakerNote itself. |
*/ |
public class FujifilmMakernoteDescriptor extends TagDescriptor |
{ |
public FujifilmMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS: |
return getSharpnessDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR: |
return getColorDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE: |
return getToneDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE: |
return getFlashModeDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH: |
return getFlashStrengthDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO: |
return getMacroDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE: |
return getFocusModeDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO: |
return getSlowSyncDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE: |
return getPictureModeDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING: |
return getContinuousTakingOrAutoBrackettingDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING: |
return getBlurWarningDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING: |
return getFocusWarningDescription(); |
case FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING: |
return getAutoExposureWarningDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getAutoExposureWarningDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_AE_WARNING); |
switch (value) { |
case 0: |
return "AE good"; |
case 1: |
return "Over exposed (>1/1000s @ F11)"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusWarningDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_WARNING); |
switch (value) { |
case 0: |
return "Auto focus good"; |
case 1: |
return "Out of focus"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getBlurWarningDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_BLUR_WARNING); |
switch (value) { |
case 0: |
return "No blur warning"; |
case 1: |
return "Blur warning"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getContinuousTakingOrAutoBrackettingDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING); |
switch (value) { |
case 0: |
return "Off"; |
case 1: |
return "On"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getPictureModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_PICTURE_MODE); |
switch (value) { |
case 0: |
return "Auto"; |
case 1: |
return "Portrait scene"; |
case 2: |
return "Landscape scene"; |
case 4: |
return "Sports scene"; |
case 5: |
return "Night scene"; |
case 6: |
return "Program AE"; |
case 256: |
return "Aperture priority AE"; |
case 512: |
return "Shutter priority AE"; |
case 768: |
return "Manual exposure"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSlowSyncDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SLOW_SYNCHRO); |
switch (value) { |
case 0: |
return "Off"; |
case 1: |
return "On"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FOCUS_MODE); |
switch (value) { |
case 0: |
return "Auto focus"; |
case 1: |
return "Manual focus"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getMacroDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_MACRO); |
switch (value) { |
case 0: |
return "Off"; |
case 1: |
return "On"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashStrengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH)) return null; |
Rational value = _directory.getRational(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_STRENGTH); |
return value.toSimpleString(false) + " EV (Apex)"; |
} |
public String getFlashModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_FLASH_MODE); |
switch (value) { |
case 0: |
return "Auto"; |
case 1: |
return "On"; |
case 2: |
return "Off"; |
case 3: |
return "Red-eye reduction"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getToneDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_TONE); |
switch (value) { |
case 0: |
return "Normal (STD)"; |
case 256: |
return "High (HARD)"; |
case 512: |
return "Low (ORG)"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getColorDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_COLOR); |
switch (value) { |
case 0: |
return "Normal (STD)"; |
case 256: |
return "High"; |
case 512: |
return "Low (ORG)"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_WHITE_BALANCE); |
switch (value) { |
case 0: |
return "Auto"; |
case 256: |
return "Daylight"; |
case 512: |
return "Cloudy"; |
case 768: |
return "DaylightColor-fluorescence"; |
case 769: |
return "DaywhiteColor-fluorescence"; |
case 770: |
return "White-fluorescence"; |
case 1024: |
return "Incandenscense"; |
case 3840: |
return "Custom white balance"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS)) return null; |
int value = _directory.getInt(FujifilmMakernoteDirectory.TAG_FUJIFILM_SHARPNESS); |
switch (value) { |
case 1: |
return "Softest"; |
case 2: |
return "Soft"; |
case 3: |
return "Normal"; |
case 4: |
return "Hard"; |
case 5: |
return "Hardest"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType2MakernoteDirectory.java |
---|
0,0 → 1,218 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment. |
* Makernote data begins after a 6-byte header: "QVC\x00\x00\x00" |
*/ |
public class CasioType2MakernoteDirectory extends Directory |
{ |
/** |
* 2 values - x,y dimensions in pixels. |
*/ |
public static final int TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS = 0x0002; |
/** |
* Size in bytes |
*/ |
public static final int TAG_CASIO_TYPE2_THUMBNAIL_SIZE = 0x0003; |
/** |
* Offset of Preview Thumbnail |
*/ |
public static final int TAG_CASIO_TYPE2_THUMBNAIL_OFFSET = 0x0004; |
/** |
* 1 = Fine |
* 2 = Super Fine |
*/ |
public static final int TAG_CASIO_TYPE2_QUALITY_MODE = 0x0008; |
/** |
* 0 = 640 x 480 pixels |
* 4 = 1600 x 1200 pixels |
* 5 = 2048 x 1536 pixels |
* 20 = 2288 x 1712 pixels |
* 21 = 2592 x 1944 pixels |
* 22 = 2304 x 1728 pixels |
* 36 = 3008 x 2008 pixels |
*/ |
public static final int TAG_CASIO_TYPE2_IMAGE_SIZE = 0x0009; |
/** |
* 0 = Normal |
* 1 = Macro |
*/ |
public static final int TAG_CASIO_TYPE2_FOCUS_MODE_1 = 0x000D; |
/** |
* 3 = 50 |
* 4 = 64 |
* 6 = 100 |
* 9 = 200 |
*/ |
public static final int TAG_CASIO_TYPE2_ISO_SENSITIVITY = 0x0014; |
/** |
* 0 = Auto |
* 1 = Daylight |
* 2 = Shade |
* 3 = Tungsten |
* 4 = Fluorescent |
* 5 = Manual |
*/ |
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_1 = 0x0019; |
/** |
* Units are tenths of a millimetre |
*/ |
public static final int TAG_CASIO_TYPE2_FOCAL_LENGTH = 0x001D; |
/** |
* 0 = -1 |
* 1 = Normal |
* 2 = +1 |
*/ |
public static final int TAG_CASIO_TYPE2_SATURATION = 0x001F; |
/** |
* 0 = -1 |
* 1 = Normal |
* 2 = +1 |
*/ |
public static final int TAG_CASIO_TYPE2_CONTRAST = 0x0020; |
/** |
* 0 = -1 |
* 1 = Normal |
* 2 = +1 |
*/ |
public static final int TAG_CASIO_TYPE2_SHARPNESS = 0x0021; |
/** |
* See PIM specification here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html |
*/ |
public static final int TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO = 0x0E00; |
/** |
* Alternate thumbnail offset |
*/ |
public static final int TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL = 0x2000; |
/** |
* |
*/ |
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS = 0x2011; |
/** |
* 12 = Flash |
* 0 = Manual |
* 1 = Auto? |
* 4 = Flash? |
*/ |
public static final int TAG_CASIO_TYPE2_WHITE_BALANCE_2 = 0x2012; |
/** |
* Units are millimetres |
*/ |
public static final int TAG_CASIO_TYPE2_OBJECT_DISTANCE = 0x2022; |
/** |
* 0 = Off |
*/ |
public static final int TAG_CASIO_TYPE2_FLASH_DISTANCE = 0x2034; |
/** |
* 2 = Normal Mode |
*/ |
public static final int TAG_CASIO_TYPE2_RECORD_MODE = 0x3000; |
/** |
* 1 = Off? |
*/ |
public static final int TAG_CASIO_TYPE2_SELF_TIMER = 0x3001; |
/** |
* 3 = Fine |
*/ |
public static final int TAG_CASIO_TYPE2_QUALITY = 0x3002; |
/** |
* 1 = Fixation |
* 6 = Multi-Area Auto Focus |
*/ |
public static final int TAG_CASIO_TYPE2_FOCUS_MODE_2 = 0x3003; |
/** |
* (string) |
*/ |
public static final int TAG_CASIO_TYPE2_TIME_ZONE = 0x3006; |
/** |
* |
*/ |
public static final int TAG_CASIO_TYPE2_BESTSHOT_MODE = 0x3007; |
/** |
* 0 = Off |
* 1 = On? |
*/ |
public static final int TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY = 0x3014; |
/** |
* 0 = Off |
*/ |
public static final int TAG_CASIO_TYPE2_COLOUR_MODE = 0x3015; |
/** |
* 0 = Off |
*/ |
public static final int TAG_CASIO_TYPE2_ENHANCEMENT = 0x3016; |
/** |
* 0 = Off |
*/ |
public static final int TAG_CASIO_TYPE2_FILTER = 0x3017; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
// TODO add names |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS), "Thumbnail Dimensions"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_SIZE), "Thumbnail Size"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_THUMBNAIL_OFFSET), "Thumbnail Offset"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY_MODE), "Quality Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_IMAGE_SIZE), "Image Size"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_1), "Focus Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ISO_SENSITIVITY), "ISO Sensitivity"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_1), "White Balance"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCAL_LENGTH), "Focal Length"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SATURATION), "Saturation"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CONTRAST), "Contrast"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL), "Casio Preview Thumbnail"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS), "White Balance Bias"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_WHITE_BALANCE_2), "White Balance"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_OBJECT_DISTANCE), "Object Distance"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FLASH_DISTANCE), "Flash Distance"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_RECORD_MODE), "Record Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_SELF_TIMER), "Self Timer"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_QUALITY), "Quality"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FOCUS_MODE_2), "Focus Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_TIME_ZONE), "Time Zone"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_BESTSHOT_MODE), "BestShot Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY), "CCD ISO Sensitivity"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_COLOUR_MODE), "Colour Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_ENHANCEMENT), "Enhancement"); |
tagNameMap.put(new Integer(TAG_CASIO_TYPE2_FILTER), "Filter"); |
} |
public CasioType2MakernoteDirectory() |
{ |
this.setDescriptor(new CasioType2MakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Casio Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifReader.java |
---|
0,0 → 1,668 |
/* |
* EXIFExtractor.java |
* |
* This class based upon code from Jhead, a C program for extracting and |
* manipulating the Exif data within files written by Matthias Wandel. |
* http://www.sentex.net/~mwandel/jhead/ |
* |
* Jhead is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. Similarly, I release this Java version under the |
* same license, though I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. Unlike |
* Jhead, this code (as it stands) only supports reading of Exif data - no |
* manipulation, and no thumbnail stuff. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew.noakes@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on 28 April 2002, 23:54 |
* Modified 04 Aug 2002 |
* - Renamed constants to be inline with changes to ExifTagValues interface |
* - Substituted usage of JDK 1.4 features (java.nio package) |
* Modified 29 Oct 2002 (v1.2) |
* - Proper traversing of Exif file structure and complete refactor & tidy of |
* the codebase (a few unnoticed bugs removed) |
* - Reads makernote data for 6 families of camera (5 makes) |
* - Tags now stored in directories... use the IFD_* constants to refer to the |
* image file directory you require (Exif, Interop, GPS and Makernote*) -- |
* this avoids collisions where two tags share the same code |
* - Takes componentCount of unknown tags into account |
* - Now understands GPS tags (thanks to Colin Briton for his help with this) |
* - Some other bug fixes, pointed out by users around the world. Thanks! |
* Modified 27 Nov 2002 (v2.0) |
* - Renamed to ExifReader |
* - Moved to new package com.drew.metadata.exif |
* Modified since, however changes have not been logged. See release notes for |
* library-wide modifications. |
*/ |
package com.drew.metadata.exif; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentData; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataReader; |
import java.io.File; |
import java.io.InputStream; |
import java.util.HashMap; |
/** |
* Extracts Exif data from a JPEG header segment, providing information about the |
* camera/scanner/capture device (if available). Information is encapsulated in |
* an <code>Metadata</code> object. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class ExifReader implements MetadataReader |
{ |
/** |
* The JPEG segment as an array of bytes. |
*/ |
private final byte[] _data; |
/** |
* Represents the native byte ordering used in the JPEG segment. If true, |
* then we're using Motorolla ordering (Big endian), else we're using Intel |
* ordering (Little endian). |
*/ |
private boolean _isMotorollaByteOrder; |
/** |
* Bean instance to store information about the image and camera/scanner/capture |
* device. |
*/ |
private Metadata _metadata; |
/** |
* The number of bytes used per format descriptor. |
*/ |
private static final int[] BYTES_PER_FORMAT = {0, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8}; |
/** |
* The number of formats known. |
*/ |
private static final int MAX_FORMAT_CODE = 12; |
// Format types |
// Note: Cannot use the DataFormat enumeration in the case statement that uses these tags. |
// Is there a better way? |
private static final int FMT_BYTE = 1; |
private static final int FMT_STRING = 2; |
private static final int FMT_USHORT = 3; |
private static final int FMT_ULONG = 4; |
private static final int FMT_URATIONAL = 5; |
private static final int FMT_SBYTE = 6; |
private static final int FMT_UNDEFINED = 7; |
private static final int FMT_SSHORT = 8; |
private static final int FMT_SLONG = 9; |
private static final int FMT_SRATIONAL = 10; |
private static final int FMT_SINGLE = 11; |
private static final int FMT_DOUBLE = 12; |
public static final int TAG_EXIF_OFFSET = 0x8769; |
public static final int TAG_INTEROP_OFFSET = 0xA005; |
public static final int TAG_GPS_INFO_OFFSET = 0x8825; |
public static final int TAG_MAKER_NOTE = 0x927C; |
public static final int TIFF_HEADER_START_OFFSET = 6; |
/** |
* Creates an ExifReader for a JpegSegmentData object. |
* @param segmentData |
*/ |
public ExifReader(JpegSegmentData segmentData) |
{ |
this(segmentData.getSegment(JpegSegmentReader.SEGMENT_APP1)); |
} |
/** |
* Creates an ExifReader for a Jpeg file. |
* @param file |
* @throws JpegProcessingException |
*/ |
public ExifReader(File file) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(file).readSegment(JpegSegmentReader.SEGMENT_APP1)); |
} |
/** |
* Creates an ExifReader for a Jpeg stream. |
* @param is JPEG stream. Stream will be closed. |
*/ |
public ExifReader(InputStream is) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APP1)); |
} |
/** |
* Creates an ExifReader for the given JPEG header segment. |
*/ |
public ExifReader(byte[] data) |
{ |
_data = data; |
} |
/** |
* Performs the Exif data extraction, returning a new instance of <code>Metadata</code>. |
*/ |
public Metadata extract() |
{ |
return extract(new Metadata()); |
} |
/** |
* Performs the Exif data extraction, adding found values to the specified |
* instance of <code>Metadata</code>. |
*/ |
public Metadata extract(Metadata metadata) |
{ |
_metadata = metadata; |
if (_data==null) |
return _metadata; |
// once we know there's some data, create the directory and start working on it |
ExifDirectory directory = (ExifDirectory)_metadata.getDirectory(ExifDirectory.class); |
// check for the header length |
if (_data.length<=14) { |
directory.addError("Exif data segment must contain at least 14 bytes"); |
return _metadata; |
} |
// check for the header preamble |
if (!"Exif\0\0".equals(new String(_data, 0, 6))) { |
directory.addError("Exif data segment doesn't begin with 'Exif'"); |
return _metadata; |
} |
// this should be either "MM" or "II" |
String byteOrderIdentifier = new String(_data, 6, 2); |
if (!setByteOrder(byteOrderIdentifier)) { |
directory.addError("Unclear distinction between Motorola/Intel byte ordering: " + byteOrderIdentifier); |
return _metadata; |
} |
// Check the next two values for correctness. |
if (get16Bits(8)!=0x2a) { |
directory.addError("Invalid Exif start - should have 0x2A at offset 8 in Exif header"); |
return _metadata; |
} |
int firstDirectoryOffset = get32Bits(10) + TIFF_HEADER_START_OFFSET; |
// David Ekholm sent an digital camera image that has this problem |
if (firstDirectoryOffset>=_data.length - 1) { |
directory.addError("First exif directory offset is beyond end of Exif data segment"); |
// First directory normally starts 14 bytes in -- try it here and catch another error in the worst case |
firstDirectoryOffset = 14; |
} |
HashMap processedDirectoryOffsets = new HashMap(); |
// 0th IFD (we merge with Exif IFD) |
processDirectory(directory, processedDirectoryOffsets, firstDirectoryOffset, TIFF_HEADER_START_OFFSET); |
// after the extraction process, if we have the correct tags, we may be able to store thumbnail information |
storeThumbnailBytes(directory, TIFF_HEADER_START_OFFSET); |
return _metadata; |
} |
private void storeThumbnailBytes(ExifDirectory exifDirectory, int tiffHeaderOffset) |
{ |
if (!exifDirectory.containsTag(ExifDirectory.TAG_COMPRESSION)) |
return; |
if (!exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH) || |
!exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) |
return; |
try { |
int offset = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET); |
int length = exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH); |
byte[] result = new byte[length]; |
for (int i = 0; i<result.length; i++) { |
result[i] = _data[tiffHeaderOffset + offset + i]; |
} |
exifDirectory.setByteArray(ExifDirectory.TAG_THUMBNAIL_DATA, result); |
} catch (Throwable e) { |
exifDirectory.addError("Unable to extract thumbnail: " + e.getMessage()); |
} |
} |
private boolean setByteOrder(String byteOrderIdentifier) |
{ |
if ("MM".equals(byteOrderIdentifier)) { |
_isMotorollaByteOrder = true; |
} else if ("II".equals(byteOrderIdentifier)) { |
_isMotorollaByteOrder = false; |
} else { |
return false; |
} |
return true; |
} |
/** |
* Process one of the nested Tiff IFD directories. |
* 2 bytes: number of tags |
* for each tag |
* 2 bytes: tag type |
* 2 bytes: format code |
* 4 bytes: component count |
*/ |
private void processDirectory(Directory directory, HashMap processedDirectoryOffsets, int dirStartOffset, int tiffHeaderOffset) |
{ |
// check for directories we've already visited to avoid stack overflows when recursive/cyclic directory structures exist |
if (processedDirectoryOffsets.containsKey(new Integer(dirStartOffset))) |
return; |
// remember that we've visited this directory so that we don't visit it again later |
processedDirectoryOffsets.put(new Integer(dirStartOffset), "processed"); |
if (dirStartOffset>=_data.length || dirStartOffset<0) { |
directory.addError("Ignored directory marked to start outside data segement"); |
return; |
} |
if (!isDirectoryLengthValid(dirStartOffset, tiffHeaderOffset)) { |
directory.addError("Illegally sized directory"); |
return; |
} |
// First two bytes in the IFD are the number of tags in this directory |
int dirTagCount = get16Bits(dirStartOffset); |
// Handle each tag in this directory |
for (int tagNumber = 0; tagNumber<dirTagCount; tagNumber++) |
{ |
final int tagOffset = calculateTagOffset(dirStartOffset, tagNumber); |
// 2 bytes for the tag type |
final int tagType = get16Bits(tagOffset); |
// 2 bytes for the format code |
final int formatCode = get16Bits(tagOffset + 2); |
if (formatCode<1 || formatCode>MAX_FORMAT_CODE) { |
directory.addError("Invalid format code: " + formatCode); |
continue; |
} |
// 4 bytes dictate the number of components in this tag's data |
final int componentCount = get32Bits(tagOffset + 4); |
if (componentCount<0) { |
directory.addError("Negative component count in EXIF"); |
continue; |
} |
// each component may have more than one byte... calculate the total number of bytes |
final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; |
final int tagValueOffset = calculateTagValueOffset(byteCount, tagOffset, tiffHeaderOffset); |
if (tagValueOffset<0 || tagValueOffset > _data.length) { |
directory.addError("Illegal pointer offset value in EXIF"); |
continue; |
} |
// Check that this tag isn't going to allocate outside the bounds of the data array. |
// This addresses an uncommon OutOfMemoryError. |
if (byteCount < 0 || tagValueOffset + byteCount > _data.length) |
{ |
directory.addError("Illegal number of bytes: " + byteCount); |
continue; |
} |
// Calculate the value as an offset for cases where the tag represents directory |
final int subdirOffset = tiffHeaderOffset + get32Bits(tagValueOffset); |
switch (tagType) { |
case TAG_EXIF_OFFSET: |
processDirectory(_metadata.getDirectory(ExifDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
continue; |
case TAG_INTEROP_OFFSET: |
processDirectory(_metadata.getDirectory(ExifInteropDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
continue; |
case TAG_GPS_INFO_OFFSET: |
processDirectory(_metadata.getDirectory(GpsDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
continue; |
case TAG_MAKER_NOTE: |
processMakerNote(tagValueOffset, processedDirectoryOffsets, tiffHeaderOffset); |
continue; |
default: |
processTag(directory, tagType, tagValueOffset, componentCount, formatCode); |
break; |
} |
} |
// at the end of each IFD is an optional link to the next IFD |
final int finalTagOffset = calculateTagOffset(dirStartOffset, dirTagCount); |
int nextDirectoryOffset = get32Bits(finalTagOffset); |
if (nextDirectoryOffset!=0) { |
nextDirectoryOffset += tiffHeaderOffset; |
if (nextDirectoryOffset>=_data.length) { |
// Last 4 bytes of IFD reference another IFD with an address that is out of bounds |
// Note this could have been caused by jhead 1.3 cropping too much |
return; |
} else if (nextDirectoryOffset < dirStartOffset) { |
// Last 4 bytes of IFD reference another IFD with an address that is before the start of this directory |
return; |
} |
// the next directory is of same type as this one |
processDirectory(directory, processedDirectoryOffsets, nextDirectoryOffset, tiffHeaderOffset); |
} |
} |
private void processMakerNote(int subdirOffset, HashMap processedDirectoryOffsets, int tiffHeaderOffset) |
{ |
// Determine the camera model and makernote format |
Directory exifDirectory = _metadata.getDirectory(ExifDirectory.class); |
if (exifDirectory==null) |
return; |
String cameraModel = exifDirectory.getString(ExifDirectory.TAG_MAKE); |
final String firstTwoChars = new String(_data, subdirOffset, 2); |
final String firstThreeChars = new String(_data, subdirOffset, 3); |
final String firstFourChars = new String(_data, subdirOffset, 4); |
final String firstFiveChars = new String(_data, subdirOffset, 5); |
final String firstSixChars = new String(_data, subdirOffset, 6); |
final String firstSevenChars = new String(_data, subdirOffset, 7); |
final String firstEightChars = new String(_data, subdirOffset, 8); |
if ("OLYMP".equals(firstFiveChars) || "EPSON".equals(firstFiveChars) || "AGFA".equals(firstFourChars)) |
{ |
// Olympus Makernote |
// Epson and Agfa use Olypus maker note standard, see: |
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/ |
processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset); |
} |
else if (cameraModel!=null && cameraModel.trim().toUpperCase().startsWith("NIKON")) |
{ |
if ("Nikon".equals(firstFiveChars)) |
{ |
/* There are two scenarios here: |
* Type 1: ** |
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... |
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ |
* Type 3: ** |
* :0000: 4E 69 6B 6F 6E 00 02 00-00 00 4D 4D 00 2A 00 00 Nikon....MM.*... |
* :0010: 00 08 00 1E 00 01 00 07-00 00 00 04 30 32 30 30 ............0200 |
*/ |
if (_data[subdirOffset+6]==1) |
processDirectory(_metadata.getDirectory(NikonType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 8, tiffHeaderOffset); |
else if (_data[subdirOffset+6]==2) |
processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 18, subdirOffset + 10); |
else |
exifDirectory.addError("Unsupported makernote data ignored."); |
} |
else |
{ |
// The IFD begins with the first MakerNote byte (no ASCII name). This occurs with CoolPix 775, E990 and D1 models. |
processDirectory(_metadata.getDirectory(NikonType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
} |
} |
else if ("SONY CAM".equals(firstEightChars) || "SONY DSC".equals(firstEightChars)) |
{ |
processDirectory(_metadata.getDirectory(SonyMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset); |
} |
else if ("KDK".equals(firstThreeChars)) |
{ |
processDirectory(_metadata.getDirectory(KodakMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 20, tiffHeaderOffset); |
} |
else if ("Canon".equalsIgnoreCase(cameraModel)) |
{ |
processDirectory(_metadata.getDirectory(CanonMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
} |
else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("CASIO")) |
{ |
if ("QVC\u0000\u0000\u0000".equals(firstSixChars)) |
processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, tiffHeaderOffset); |
else |
processDirectory(_metadata.getDirectory(CasioType1MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
} |
else if ("FUJIFILM".equals(firstEightChars) || "Fujifilm".equalsIgnoreCase(cameraModel)) |
{ |
// TODO make this field a passed parameter, to avoid threading issues |
boolean byteOrderBefore = _isMotorollaByteOrder; |
// bug in fujifilm makernote ifd means we temporarily use Intel byte ordering |
_isMotorollaByteOrder = false; |
// the 4 bytes after "FUJIFILM" in the makernote point to the start of the makernote |
// IFD, though the offset is relative to the start of the makernote, not the TIFF |
// header (like everywhere else) |
int ifdStart = subdirOffset + get32Bits(subdirOffset + 8); |
processDirectory(_metadata.getDirectory(FujifilmMakernoteDirectory.class), processedDirectoryOffsets, ifdStart, tiffHeaderOffset); |
_isMotorollaByteOrder = byteOrderBefore; |
} |
else if (cameraModel!=null && cameraModel.toUpperCase().startsWith("MINOLTA")) |
{ |
// Cases seen with the model starting with MINOLTA in capitals seem to have a valid Olympus makernote |
// area that commences immediately. |
processDirectory(_metadata.getDirectory(OlympusMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, tiffHeaderOffset); |
} |
else if ("KC".equals(firstTwoChars) || "MINOL".equals(firstFiveChars) || "MLY".equals(firstThreeChars) || "+M+M+M+M".equals(firstEightChars)) |
{ |
// This Konica data is not understood. Header identified in accordance with information at this site: |
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/minolta_mn.html |
// TODO determine how to process the information described at the above website |
exifDirectory.addError("Unsupported Konica/Minolta data ignored."); |
} |
else if ("KYOCERA".equals(firstSevenChars)) |
{ |
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html |
processDirectory(_metadata.getDirectory(KyoceraMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 22, tiffHeaderOffset); |
} |
else if ("Panasonic\u0000\u0000\u0000".equals(new String(_data, subdirOffset, 12))) |
{ |
// NON-Standard TIFF IFD Data using Panasonic Tags. There is no Next-IFD pointer after the IFD |
// Offsets are relative to the start of the TIFF header at the beginning of the EXIF segment |
// more information here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html |
processDirectory(_metadata.getDirectory(PanasonicMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 12, tiffHeaderOffset); |
} |
else if ("AOC\u0000".equals(firstFourChars)) |
{ |
// NON-Standard TIFF IFD Data using Casio Type 2 Tags |
// IFD has no Next-IFD pointer at end of IFD, and |
// Offsets are relative to the start of the current IFD tag, not the TIFF header |
// Observed for: |
// - Pentax ist D |
processDirectory(_metadata.getDirectory(CasioType2MakernoteDirectory.class), processedDirectoryOffsets, subdirOffset + 6, subdirOffset); |
} |
else if (cameraModel!=null && (cameraModel.toUpperCase().startsWith("PENTAX") || cameraModel.toUpperCase().startsWith("ASAHI"))) |
{ |
// NON-Standard TIFF IFD Data using Pentax Tags |
// IFD has no Next-IFD pointer at end of IFD, and |
// Offsets are relative to the start of the current IFD tag, not the TIFF header |
// Observed for: |
// - PENTAX Optio 330 |
// - PENTAX Optio 430 |
processDirectory(_metadata.getDirectory(PentaxMakernoteDirectory.class), processedDirectoryOffsets, subdirOffset, subdirOffset); |
} |
else |
{ |
// TODO how to store makernote data when it's not from a supported camera model? |
// this is difficult as the starting offset is not known. we could look for it... |
exifDirectory.addError("Unsupported makernote data ignored."); |
} |
} |
private boolean isDirectoryLengthValid(int dirStartOffset, int tiffHeaderOffset) |
{ |
int dirTagCount = get16Bits(dirStartOffset); |
int dirLength = (2 + (12 * dirTagCount) + 4); |
if (dirLength + dirStartOffset + tiffHeaderOffset>=_data.length) { |
// Note: Files that had thumbnails trimmed with jhead 1.3 or earlier might trigger this |
return false; |
} |
return true; |
} |
private void processTag(Directory directory, int tagType, int tagValueOffset, int componentCount, int formatCode) |
{ |
// Directory simply stores raw values |
// The display side uses a Descriptor class per directory to turn the raw values into 'pretty' descriptions |
switch (formatCode) |
{ |
case FMT_UNDEFINED: |
// this includes exif user comments |
final byte[] tagBytes = new byte[componentCount]; |
final int byteCount = componentCount * BYTES_PER_FORMAT[formatCode]; |
for (int i=0; i<byteCount; i++) |
tagBytes[i] = _data[tagValueOffset + i]; |
directory.setByteArray(tagType, tagBytes); |
break; |
case FMT_STRING: |
directory.setString(tagType, readString(tagValueOffset, componentCount)); |
break; |
case FMT_SRATIONAL: |
case FMT_URATIONAL: |
if (componentCount==1) { |
Rational rational = new Rational(get32Bits(tagValueOffset), get32Bits(tagValueOffset + 4)); |
directory.setRational(tagType, rational); |
} else { |
Rational[] rationals = new Rational[componentCount]; |
for (int i = 0; i<componentCount; i++) |
rationals[i] = new Rational(get32Bits(tagValueOffset + (8 * i)), get32Bits(tagValueOffset + 4 + (8 * i))); |
directory.setRationalArray(tagType, rationals); |
} |
break; |
case FMT_SBYTE: |
case FMT_BYTE: |
if (componentCount==1) { |
// this may need to be a byte, but I think casting to int is fine |
int b = _data[tagValueOffset]; |
directory.setInt(tagType, b); |
} else { |
int[] bytes = new int[componentCount]; |
for (int i = 0; i<componentCount; i++) |
bytes[i] = _data[tagValueOffset + i]; |
directory.setIntArray(tagType, bytes); |
} |
break; |
case FMT_SINGLE: |
case FMT_DOUBLE: |
if (componentCount==1) { |
int i = _data[tagValueOffset]; |
directory.setInt(tagType, i); |
} else { |
int[] ints = new int[componentCount]; |
for (int i = 0; i<componentCount; i++) |
ints[i] = _data[tagValueOffset + i]; |
directory.setIntArray(tagType, ints); |
} |
break; |
case FMT_USHORT: |
case FMT_SSHORT: |
if (componentCount==1) { |
int i = get16Bits(tagValueOffset); |
directory.setInt(tagType, i); |
} else { |
int[] ints = new int[componentCount]; |
for (int i = 0; i<componentCount; i++) |
ints[i] = get16Bits(tagValueOffset + (i * 2)); |
directory.setIntArray(tagType, ints); |
} |
break; |
case FMT_SLONG: |
case FMT_ULONG: |
if (componentCount==1) { |
int i = get32Bits(tagValueOffset); |
directory.setInt(tagType, i); |
} else { |
int[] ints = new int[componentCount]; |
for (int i = 0; i<componentCount; i++) |
ints[i] = get32Bits(tagValueOffset + (i * 4)); |
directory.setIntArray(tagType, ints); |
} |
break; |
default: |
directory.addError("Unknown format code " + formatCode + " for tag " + tagType); |
} |
} |
private int calculateTagValueOffset(int byteCount, int dirEntryOffset, int tiffHeaderOffset) |
{ |
if (byteCount>4) { |
// If its bigger than 4 bytes, the dir entry contains an offset. |
// dirEntryOffset must be passed, as some makernote implementations (e.g. FujiFilm) incorrectly use an |
// offset relative to the start of the makernote itself, not the TIFF segment. |
final int offsetVal = get32Bits(dirEntryOffset + 8); |
if (offsetVal + byteCount>_data.length) { |
// Bogus pointer offset and / or bytecount value |
return -1; // signal error |
} |
return tiffHeaderOffset + offsetVal; |
} else { |
// 4 bytes or less and value is in the dir entry itself |
return dirEntryOffset + 8; |
} |
} |
/** |
* Creates a String from the _data buffer starting at the specified offset, |
* and ending where byte=='\0' or where length==maxLength. |
*/ |
private String readString(int offset, int maxLength) |
{ |
int length = 0; |
while ((offset + length)<_data.length && _data[offset + length]!='\0' && length<maxLength) |
length++; |
return new String(_data, offset, length); |
} |
/** |
* Determine the offset at which a given InteropArray entry begins within the specified IFD. |
* @param dirStartOffset the offset at which the IFD starts |
* @param entryNumber the zero-based entry number |
*/ |
private int calculateTagOffset(int dirStartOffset, int entryNumber) |
{ |
// add 2 bytes for the tag count |
// each entry is 12 bytes, so we skip 12 * the number seen so far |
return dirStartOffset + 2 + (12 * entryNumber); |
} |
/** |
* Get a 16 bit value from file's native byte order. Between 0x0000 and 0xFFFF. |
*/ |
private int get16Bits(int offset) |
{ |
if (offset<0 || offset+2>_data.length) |
throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")"); |
if (_isMotorollaByteOrder) { |
// Motorola - MSB first |
return (_data[offset] << 8 & 0xFF00) | (_data[offset + 1] & 0xFF); |
} else { |
// Intel ordering - LSB first |
return (_data[offset + 1] << 8 & 0xFF00) | (_data[offset] & 0xFF); |
} |
} |
/** |
* Get a 32 bit value from file's native byte order. |
*/ |
private int get32Bits(int offset) |
{ |
if (offset<0 || offset+4>_data.length) |
throw new ArrayIndexOutOfBoundsException("attempt to read data outside of exif segment (index " + offset + " where max index is " + (_data.length - 1) + ")"); |
if (_isMotorollaByteOrder) { |
// Motorola - MSB first |
return (_data[offset] << 24 & 0xFF000000) | |
(_data[offset + 1] << 16 & 0xFF0000) | |
(_data[offset + 2] << 8 & 0xFF00) | |
(_data[offset + 3] & 0xFF); |
} else { |
// Intel ordering - LSB first |
return (_data[offset + 3] << 24 & 0xFF000000) | |
(_data[offset + 2] << 16 & 0xFF0000) | |
(_data[offset + 1] << 8 & 0xFF00) | |
(_data[offset] & 0xFF); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/GpsDirectory.java |
---|
0,0 → 1,130 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Nov-2002 11:00:52 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class GpsDirectory extends Directory |
{ |
/** GPS tag version GPSVersionID 0 0 BYTE 4 */ |
public static final int TAG_GPS_VERSION_ID = 0x0000; |
/** North or South Latitude GPSLatitudeRef 1 1 ASCII 2 */ |
public static final int TAG_GPS_LATITUDE_REF = 0x0001; |
/** Latitude GPSLatitude 2 2 RATIONAL 3 */ |
public static final int TAG_GPS_LATITUDE = 0x0002; |
/** East or West Longitude GPSLongitudeRef 3 3 ASCII 2 */ |
public static final int TAG_GPS_LONGITUDE_REF = 0x0003; |
/** Longitude GPSLongitude 4 4 RATIONAL 3 */ |
public static final int TAG_GPS_LONGITUDE = 0x0004; |
/** Altitude reference GPSAltitudeRef 5 5 BYTE 1 */ |
public static final int TAG_GPS_ALTITUDE_REF = 0x0005; |
/** Altitude GPSAltitude 6 6 RATIONAL 1 */ |
public static final int TAG_GPS_ALTITUDE = 0x0006; |
/** GPS time (atomic clock) GPSTimeStamp 7 7 RATIONAL 3 */ |
public static final int TAG_GPS_TIME_STAMP = 0x0007; |
/** GPS satellites used for measurement GPSSatellites 8 8 ASCII Any */ |
public static final int TAG_GPS_SATELLITES = 0x0008; |
/** GPS receiver status GPSStatus 9 9 ASCII 2 */ |
public static final int TAG_GPS_STATUS = 0x0009; |
/** GPS measurement mode GPSMeasureMode 10 A ASCII 2 */ |
public static final int TAG_GPS_MEASURE_MODE = 0x000A; |
/** Measurement precision GPSDOP 11 B RATIONAL 1 */ |
public static final int TAG_GPS_DOP = 0x000B; |
/** Speed unit GPSSpeedRef 12 C ASCII 2 */ |
public static final int TAG_GPS_SPEED_REF = 0x000C; |
/** Speed of GPS receiver GPSSpeed 13 D RATIONAL 1 */ |
public static final int TAG_GPS_SPEED = 0x000D; |
/** Reference for direction of movement GPSTrackRef 14 E ASCII 2 */ |
public static final int TAG_GPS_TRACK_REF = 0x000E; |
/** Direction of movement GPSTrack 15 F RATIONAL 1 */ |
public static final int TAG_GPS_TRACK = 0x000F; |
/** Reference for direction of image GPSImgDirectionRef 16 10 ASCII 2 */ |
public static final int TAG_GPS_IMG_DIRECTION_REF = 0x0010; |
/** Direction of image GPSImgDirection 17 11 RATIONAL 1 */ |
public static final int TAG_GPS_IMG_DIRECTION = 0x0011; |
/** Geodetic survey data used GPSMapDatum 18 12 ASCII Any */ |
public static final int TAG_GPS_MAP_DATUM = 0x0012; |
/** Reference for latitude of destination GPSDestLatitudeRef 19 13 ASCII 2 */ |
public static final int TAG_GPS_DEST_LATITUDE_REF = 0x0013; |
/** Latitude of destination GPSDestLatitude 20 14 RATIONAL 3 */ |
public static final int TAG_GPS_DEST_LATITUDE = 0x0014; |
/** Reference for longitude of destination GPSDestLongitudeRef 21 15 ASCII 2 */ |
public static final int TAG_GPS_DEST_LONGITUDE_REF = 0x0015; |
/** Longitude of destination GPSDestLongitude 22 16 RATIONAL 3 */ |
public static final int TAG_GPS_DEST_LONGITUDE = 0x0016; |
/** Reference for bearing of destination GPSDestBearingRef 23 17 ASCII 2 */ |
public static final int TAG_GPS_DEST_BEARING_REF = 0x0017; |
/** Bearing of destination GPSDestBearing 24 18 RATIONAL 1 */ |
public static final int TAG_GPS_DEST_BEARING = 0x0018; |
/** Reference for distance to destination GPSDestDistanceRef 25 19 ASCII 2 */ |
public static final int TAG_GPS_DEST_DISTANCE_REF = 0x0019; |
/** Distance to destination GPSDestDistance 26 1A RATIONAL 1 */ |
public static final int TAG_GPS_DEST_DISTANCE = 0x001A; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_GPS_VERSION_ID), "GPS Version ID"); |
tagNameMap.put(new Integer(TAG_GPS_LATITUDE_REF), "GPS Latitude Ref"); |
tagNameMap.put(new Integer(TAG_GPS_LATITUDE), "GPS Latitude"); |
tagNameMap.put(new Integer(TAG_GPS_LONGITUDE_REF), "GPS Longitude Ref"); |
tagNameMap.put(new Integer(TAG_GPS_LONGITUDE), "GPS Longitude"); |
tagNameMap.put(new Integer(TAG_GPS_ALTITUDE_REF), "GPS Altitude Ref"); |
tagNameMap.put(new Integer(TAG_GPS_ALTITUDE), "GPS Altitude"); |
tagNameMap.put(new Integer(TAG_GPS_TIME_STAMP), "GPS Time-Stamp"); |
tagNameMap.put(new Integer(TAG_GPS_SATELLITES), "GPS Satellites"); |
tagNameMap.put(new Integer(TAG_GPS_STATUS), "GPS Status"); |
tagNameMap.put(new Integer(TAG_GPS_MEASURE_MODE), "GPS Measure Mode"); |
tagNameMap.put(new Integer(TAG_GPS_DOP), "GPS DOP"); |
tagNameMap.put(new Integer(TAG_GPS_SPEED_REF), "GPS Speed Ref"); |
tagNameMap.put(new Integer(TAG_GPS_SPEED), "GPS Speed"); |
tagNameMap.put(new Integer(TAG_GPS_TRACK_REF), "GPS Track Ref"); |
tagNameMap.put(new Integer(TAG_GPS_TRACK), "GPS Track"); |
tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction Ref"); |
tagNameMap.put(new Integer(TAG_GPS_IMG_DIRECTION_REF), "GPS Img Direction"); |
tagNameMap.put(new Integer(TAG_GPS_MAP_DATUM), "GPS Map Datum"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE_REF), "GPS Dest Latitude Ref"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_LATITUDE), "GPS Dest Latitude"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE_REF), "GPS Dest Longitude Ref"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_LONGITUDE), "GPS Dest Longitude"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING_REF), "GPS Dest Bearing Ref"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_BEARING), "GPS Dest Bearing"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE_REF), "GPS Dest Distance Ref"); |
tagNameMap.put(new Integer(TAG_GPS_DEST_DISTANCE), "GPS Dest Distance"); |
} |
public GpsDirectory() |
{ |
this.setDescriptor(new GpsDescriptor(this)); |
} |
public String getName() |
{ |
return "GPS"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PanasonicMakernoteDescriptor.java |
---|
0,0 → 1,85 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a PanasonicMakernoteDirectory. |
* |
* Some information about this makernote taken from here: |
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/panasonic_mn.html |
*/ |
public class PanasonicMakernoteDescriptor extends TagDescriptor |
{ |
public PanasonicMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) |
{ |
case PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE: |
return getMacroModeDescription(); |
case PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE: |
return getRecordModeDescription(); |
case PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO: |
return getPrintImageMatchingInfoDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getPrintImageMatchingInfoDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null; |
byte[] bytes = _directory.getByteArray(PanasonicMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO); |
return "(" + bytes.length + " bytes)"; |
} |
public String getMacroModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null; |
int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_MACRO_MODE); |
switch (value) { |
case 1: |
return "On"; |
case 2: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getRecordModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null; |
int value = _directory.getInt(PanasonicMakernoteDirectory.TAG_PANASONIC_RECORD_MODE); |
switch (value) { |
case 1: |
return "Normal"; |
case 2: |
return "Portrait"; |
case 9: |
return "Macro"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifDirectory.java |
---|
0,0 → 1,954 |
/* |
* ExifDirectory.java |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 25-Nov-2002 20:41:00 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import java.io.FileOutputStream; |
import java.io.IOException; |
import java.util.HashMap; |
/** |
* |
*/ |
public class ExifDirectory extends Directory |
{ |
// TODO do these tags belong in the exif directory? |
public static final int TAG_SUB_IFDS = 0x014A; |
public static final int TAG_GPS_INFO = 0x8825; |
/** |
* The actual aperture value of lens when the image was taken. Unit is APEX. |
* To convert this value to ordinary F-number (F-stop), calculate this value's |
* power of root 2 (=1.4142). For example, if the ApertureValue is '5', |
* F-number is 1.4142^5 = F5.6. |
*/ |
public static final int TAG_APERTURE = 0x9202; |
/** |
* When image format is no compression, this value shows the number of bits |
* per component for each pixel. Usually this value is '8,8,8'. |
*/ |
public static final int TAG_BITS_PER_SAMPLE = 0x0102; |
/** |
* Shows compression method for Thumbnail. |
* 1 = Uncompressed |
* 2 = CCITT 1D |
* 3 = T4/Group 3 Fax |
* 4 = T6/Group 4 Fax |
* 5 = LZW |
* 6 = JPEG (old-style) |
* 7 = JPEG |
* 8 = Adobe Deflate |
* 9 = JBIG B&W |
* 10 = JBIG Color |
* 32766 = Next |
* 32771 = CCIRLEW |
* 32773 = PackBits |
* 32809 = Thunderscan |
* 32895 = IT8CTPAD |
* 32896 = IT8LW |
* 32897 = IT8MP |
* 32898 = IT8BL |
* 32908 = PixarFilm |
* 32909 = PixarLog |
* 32946 = Deflate |
* 32947 = DCS |
* 34661 = JBIG |
* 34676 = SGILog |
* 34677 = SGILog24 |
* 34712 = JPEG 2000 |
* 34713 = Nikon NEF Compressed |
*/ |
public static final int TAG_COMPRESSION = 0x0103; |
public static final int COMPRESSION_NONE = 1; |
public static final int COMPRESSION_JPEG = 6; |
/** |
* Shows the color space of the image data components. |
* 0 = WhiteIsZero |
* 1 = BlackIsZero |
* 2 = RGB |
* 3 = RGB Palette |
* 4 = Transparency Mask |
* 5 = CMYK |
* 6 = YCbCr |
* 8 = CIELab |
* 9 = ICCLab |
* 10 = ITULab |
* 32803 = Color Filter Array |
* 32844 = Pixar LogL |
* 32845 = Pixar LogLuv |
* 34892 = Linear Raw |
*/ |
public static final int TAG_PHOTOMETRIC_INTERPRETATION = 0x0106; |
/** |
* 1 = No dithering or halftoning |
* 2 = Ordered dither or halftone |
* 3 = Randomized dither |
*/ |
public static final int TAG_THRESHOLDING = 0x0107; |
public static final int PHOTOMETRIC_INTERPRETATION_MONOCHROME = 1; |
public static final int PHOTOMETRIC_INTERPRETATION_RGB = 2; |
public static final int PHOTOMETRIC_INTERPRETATION_YCBCR = 6; |
/** The position in the file of raster data. */ |
public static final int TAG_STRIP_OFFSETS = 0x0111; |
/** Each pixel is composed of this many samples. */ |
public static final int TAG_SAMPLES_PER_PIXEL = 0x0115; |
/** The raster is codified by a single block of data holding this many rows. */ |
public static final int TAG_ROWS_PER_STRIP = 0x116; |
/** The size of the raster data in bytes. */ |
public static final int TAG_STRIP_BYTE_COUNTS = 0x0117; |
public static final int TAG_MIN_SAMPLE_VALUE = 0x0118; |
public static final int TAG_MAX_SAMPLE_VALUE = 0x0119; |
/** |
* When image format is no compression YCbCr, this value shows byte aligns of |
* YCbCr data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for |
* each subsampling pixel. If value is '2', Y/Cb/Cr value is separated and |
* stored to Y plane/Cb plane/Cr plane format. |
*/ |
public static final int TAG_PLANAR_CONFIGURATION = 0x011C; |
public static final int TAG_YCBCR_SUBSAMPLING = 0x0212; |
public static final int TAG_IMAGE_DESCRIPTION = 0x010E; |
public static final int TAG_SOFTWARE = 0x0131; |
public static final int TAG_DATETIME = 0x0132; |
public static final int TAG_WHITE_POINT = 0x013E; |
public static final int TAG_PRIMARY_CHROMATICITIES = 0x013F; |
public static final int TAG_YCBCR_COEFFICIENTS = 0x0211; |
public static final int TAG_REFERENCE_BLACK_WHITE = 0x0214; |
public static final int TAG_COPYRIGHT = 0x8298; |
/** |
* The new subfile type tag. |
* 0 = Full-resolution Image |
* 1 = Reduced-resolution image |
* 2 = Single page of multi-page image |
* 3 = Single page of multi-page reduced-resolution image |
* 4 = Transparency mask |
* 5 = Transparency mask of reduced-resolution image |
* 6 = Transparency mask of multi-page image |
* 7 = Transparency mask of reduced-resolution multi-page image |
*/ |
public static final int TAG_NEW_SUBFILE_TYPE = 0x00FE; |
/** |
* The old subfile type tag. |
* 1 = Full-resolution image (Main image) |
* 2 = Reduced-resolution image (Thumbnail) |
* 3 = Single page of multi-page image |
*/ |
public static final int TAG_SUBFILE_TYPE = 0x00FF; |
public static final int TAG_TRANSFER_FUNCTION = 0x012D; |
public static final int TAG_ARTIST = 0x013B; |
public static final int TAG_PREDICTOR = 0x013D; |
public static final int TAG_TILE_WIDTH = 0x0142; |
public static final int TAG_TILE_LENGTH = 0x0143; |
public static final int TAG_TILE_OFFSETS = 0x0144; |
public static final int TAG_TILE_BYTE_COUNTS = 0x0145; |
public static final int TAG_JPEG_TABLES = 0x015B; |
public static final int TAG_CFA_REPEAT_PATTERN_DIM = 0x828D; |
/** There are two definitions for CFA pattern, I don't know the difference... */ |
public static final int TAG_CFA_PATTERN_2 = 0x828E; |
public static final int TAG_BATTERY_LEVEL = 0x828F; |
public static final int TAG_IPTC_NAA = 0x83BB; |
public static final int TAG_INTER_COLOR_PROFILE = 0x8773; |
public static final int TAG_SPECTRAL_SENSITIVITY = 0x8824; |
public static final int TAG_OECF = 0x8828; |
public static final int TAG_INTERLACE = 0x8829; |
public static final int TAG_TIME_ZONE_OFFSET = 0x882A; |
public static final int TAG_SELF_TIMER_MODE = 0x882B; |
public static final int TAG_FLASH_ENERGY = 0x920B; |
public static final int TAG_SPATIAL_FREQ_RESPONSE = 0x920C; |
public static final int TAG_NOISE = 0x920D; |
public static final int TAG_IMAGE_NUMBER = 0x9211; |
public static final int TAG_SECURITY_CLASSIFICATION = 0x9212; |
public static final int TAG_IMAGE_HISTORY = 0x9213; |
public static final int TAG_SUBJECT_LOCATION = 0x9214; |
/** There are two definitions for exposure index, I don't know the difference... */ |
public static final int TAG_EXPOSURE_INDEX_2 = 0x9215; |
public static final int TAG_TIFF_EP_STANDARD_ID = 0x9216; |
public static final int TAG_FLASH_ENERGY_2 = 0xA20B; |
public static final int TAG_SPATIAL_FREQ_RESPONSE_2 = 0xA20C; |
public static final int TAG_SUBJECT_LOCATION_2 = 0xA214; |
public static final int TAG_MAKE = 0x010F; |
public static final int TAG_MODEL = 0x0110; |
public static final int TAG_ORIENTATION = 0x0112; |
public static final int TAG_X_RESOLUTION = 0x011A; |
public static final int TAG_Y_RESOLUTION = 0x011B; |
public static final int TAG_PAGE_NAME = 0x011D; |
public static final int TAG_RESOLUTION_UNIT = 0x0128; |
public static final int TAG_THUMBNAIL_OFFSET = 0x0201; |
public static final int TAG_THUMBNAIL_LENGTH = 0x0202; |
public static final int TAG_YCBCR_POSITIONING = 0x0213; |
/** |
* Exposure time (reciprocal of shutter speed). Unit is second. |
*/ |
public static final int TAG_EXPOSURE_TIME = 0x829A; |
/** |
* The actual F-number(F-stop) of lens when the image was taken. |
*/ |
public static final int TAG_FNUMBER = 0x829D; |
/** |
* Exposure program that the camera used when image was taken. '1' means |
* manual control, '2' program normal, '3' aperture priority, '4' shutter |
* priority, '5' program creative (slow program), '6' program action |
* (high-speed program), '7' portrait mode, '8' landscape mode. |
*/ |
public static final int TAG_EXPOSURE_PROGRAM = 0x8822; |
public static final int TAG_ISO_EQUIVALENT = 0x8827; |
public static final int TAG_EXIF_VERSION = 0x9000; |
public static final int TAG_DATETIME_ORIGINAL = 0x9003; |
public static final int TAG_DATETIME_DIGITIZED = 0x9004; |
public static final int TAG_COMPONENTS_CONFIGURATION = 0x9101; |
/** |
* Average (rough estimate) compression level in JPEG bits per pixel. |
* */ |
public static final int TAG_COMPRESSION_LEVEL = 0x9102; |
/** |
* Shutter speed by APEX value. To convert this value to ordinary 'Shutter Speed'; |
* calculate this value's power of 2, then reciprocal. For example, if the |
* ShutterSpeedValue is '4', shutter speed is 1/(24)=1/16 second. |
*/ |
public static final int TAG_SHUTTER_SPEED = 0x9201; |
public static final int TAG_BRIGHTNESS_VALUE = 0x9203; |
public static final int TAG_EXPOSURE_BIAS = 0x9204; |
/** |
* Maximum aperture value of lens. You can convert to F-number by calculating |
* power of root 2 (same process of ApertureValue:0x9202). |
* The actual aperture value of lens when the image was taken. To convert this |
* value to ordinary f-number(f-stop), calculate the value's power of root 2 |
* (=1.4142). For example, if the ApertureValue is '5', f-number is 1.41425^5 = F5.6. |
*/ |
public static final int TAG_MAX_APERTURE = 0x9205; |
/** |
* Indicates the distance the autofocus camera is focused to. Tends to be less accurate as distance increases. |
*/ |
public static final int TAG_SUBJECT_DISTANCE = 0x9206; |
/** |
* Exposure metering method. '0' means unknown, '1' average, '2' center |
* weighted average, '3' spot, '4' multi-spot, '5' multi-segment, '6' partial, |
* '255' other. |
*/ |
public static final int TAG_METERING_MODE = 0x9207; |
public static final int TAG_LIGHT_SOURCE = 0x9208; |
/** |
* White balance (aka light source). '0' means unknown, '1' daylight, |
* '2' fluorescent, '3' tungsten, '10' flash, '17' standard light A, |
* '18' standard light B, '19' standard light C, '20' D55, '21' D65, |
* '22' D75, '255' other. |
*/ |
public static final int TAG_WHITE_BALANCE = 0x9208; |
/** |
* 0x0 = 0000000 = No Flash |
* 0x1 = 0000001 = Fired |
* 0x5 = 0000101 = Fired, Return not detected |
* 0x7 = 0000111 = Fired, Return detected |
* 0x9 = 0001001 = On |
* 0xd = 0001101 = On, Return not detected |
* 0xf = 0001111 = On, Return detected |
* 0x10 = 0010000 = Off |
* 0x18 = 0011000 = Auto, Did not fire |
* 0x19 = 0011001 = Auto, Fired |
* 0x1d = 0011101 = Auto, Fired, Return not detected |
* 0x1f = 0011111 = Auto, Fired, Return detected |
* 0x20 = 0100000 = No flash function |
* 0x41 = 1000001 = Fired, Red-eye reduction |
* 0x45 = 1000101 = Fired, Red-eye reduction, Return not detected |
* 0x47 = 1000111 = Fired, Red-eye reduction, Return detected |
* 0x49 = 1001001 = On, Red-eye reduction |
* 0x4d = 1001101 = On, Red-eye reduction, Return not detected |
* 0x4f = 1001111 = On, Red-eye reduction, Return detected |
* 0x59 = 1011001 = Auto, Fired, Red-eye reduction |
* 0x5d = 1011101 = Auto, Fired, Red-eye reduction, Return not detected |
* 0x5f = 1011111 = Auto, Fired, Red-eye reduction, Return detected |
* 6543210 (positions) |
* |
* This is a bitmask. |
* 0 = flash fired |
* 1 = return detected |
* 2 = return able to be detected |
* 3 = unknown |
* 4 = auto used |
* 5 = unknown |
* 6 = red eye reduction used |
*/ |
public static final int TAG_FLASH = 0x9209; |
/** |
* Focal length of lens used to take image. Unit is millimeter. |
* Nice digital cameras actually save the focal length as a function of how far they are zoomed in. |
*/ |
public static final int TAG_FOCAL_LENGTH = 0x920A; |
public static final int TAG_USER_COMMENT = 0x9286; |
public static final int TAG_SUBSECOND_TIME = 0x9290; |
public static final int TAG_SUBSECOND_TIME_ORIGINAL = 0x9291; |
public static final int TAG_SUBSECOND_TIME_DIGITIZED = 0x9292; |
public static final int TAG_FLASHPIX_VERSION = 0xA000; |
/** |
* Defines Color Space. DCF image must use sRGB color space so value is |
* always '1'. If the picture uses the other color space, value is |
* '65535':Uncalibrated. |
*/ |
public static final int TAG_COLOR_SPACE = 0xA001; |
public static final int TAG_EXIF_IMAGE_WIDTH = 0xA002; |
public static final int TAG_EXIF_IMAGE_HEIGHT = 0xA003; |
public static final int TAG_RELATED_SOUND_FILE = 0xA004; |
public static final int TAG_FOCAL_PLANE_X_RES = 0xA20E; |
public static final int TAG_FOCAL_PLANE_Y_RES = 0xA20F; |
/** |
* Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit, |
* '2' inch, '3' centimeter. |
* |
* Note: Some of Fujifilm's digicam(e.g.FX2700,FX2900,Finepix4700Z/40i etc) |
* uses value '3' so it must be 'centimeter', but it seems that they use a |
* '8.3mm?'(1/3in.?) to their ResolutionUnit. Fuji's BUG? Finepix4900Z has |
* been changed to use value '2' but it doesn't match to actual value also. |
*/ |
public static final int TAG_FOCAL_PLANE_UNIT = 0xA210; |
public static final int TAG_EXPOSURE_INDEX = 0xA215; |
public static final int TAG_SENSING_METHOD = 0xA217; |
public static final int TAG_FILE_SOURCE = 0xA300; |
public static final int TAG_SCENE_TYPE = 0xA301; |
public static final int TAG_CFA_PATTERN = 0xA302; |
// these tags new with Exif 2.2 (?) [A401 - A4 |
/** |
* This tag indicates the use of special processing on image data, such as rendering |
* geared to output. When special processing is performed, the reader is expected to |
* disable or minimize any further processing. |
* Tag = 41985 (A401.H) |
* Type = SHORT |
* Count = 1 |
* Default = 0 |
* 0 = Normal process |
* 1 = Custom process |
* Other = reserved |
*/ |
public static final int TAG_CUSTOM_RENDERED = 0xA401; |
/** |
* This tag indicates the exposure mode set when the image was shot. In auto-bracketing |
* mode, the camera shoots a series of frames of the same scene at different exposure settings. |
* Tag = 41986 (A402.H) |
* Type = SHORT |
* Count = 1 |
* Default = none |
* 0 = Auto exposure |
* 1 = Manual exposure |
* 2 = Auto bracket |
* Other = reserved |
*/ |
public static final int TAG_EXPOSURE_MODE = 0xA402; |
/** |
* This tag indicates the white balance mode set when the image was shot. |
* Tag = 41987 (A403.H) |
* Type = SHORT |
* Count = 1 |
* Default = none |
* 0 = Auto white balance |
* 1 = Manual white balance |
* Other = reserved |
*/ |
public static final int TAG_WHITE_BALANCE_MODE = 0xA403; |
/** |
* This tag indicates the digital zoom ratio when the image was shot. If the |
* numerator of the recorded value is 0, this indicates that digital zoom was |
* not used. |
* Tag = 41988 (A404.H) |
* Type = RATIONAL |
* Count = 1 |
* Default = none |
*/ |
public static final int TAG_DIGITAL_ZOOM_RATIO = 0xA404; |
/** |
* This tag indicates the equivalent focal length assuming a 35mm film camera, |
* in mm. A value of 0 means the focal length is unknown. Note that this tag |
* differs from the FocalLength tag. |
* Tag = 41989 (A405.H) |
* Type = SHORT |
* Count = 1 |
* Default = none |
*/ |
public static final int TAG_35MM_FILM_EQUIV_FOCAL_LENGTH = 0xA405; |
/** |
* This tag indicates the type of scene that was shot. It can also be used to |
* record the mode in which the image was shot. Note that this differs from |
* the scene type (SceneType) tag. |
* Tag = 41990 (A406.H) |
* Type = SHORT |
* Count = 1 |
* Default = 0 |
* 0 = Standard |
* 1 = Landscape |
* 2 = Portrait |
* 3 = Night scene |
* Other = reserved |
*/ |
public static final int TAG_SCENE_CAPTURE_TYPE = 0xA406; |
/** |
* This tag indicates the degree of overall image gain adjustment. |
* Tag = 41991 (A407.H) |
* Type = SHORT |
* Count = 1 |
* Default = none |
* 0 = None |
* 1 = Low gain up |
* 2 = High gain up |
* 3 = Low gain down |
* 4 = High gain down |
* Other = reserved |
*/ |
public static final int TAG_GAIN_CONTROL = 0xA407; |
/** |
* This tag indicates the direction of contrast processing applied by the camera |
* when the image was shot. |
* Tag = 41992 (A408.H) |
* Type = SHORT |
* Count = 1 |
* Default = 0 |
* 0 = Normal |
* 1 = Soft |
* 2 = Hard |
* Other = reserved |
*/ |
public static final int TAG_CONTRAST = 0xA408; |
/** |
* This tag indicates the direction of saturation processing applied by the camera |
* when the image was shot. |
* Tag = 41993 (A409.H) |
* Type = SHORT |
* Count = 1 |
* Default = 0 |
* 0 = Normal |
* 1 = Low saturation |
* 2 = High saturation |
* Other = reserved |
*/ |
public static final int TAG_SATURATION = 0xA409; |
/** |
* This tag indicates the direction of sharpness processing applied by the camera |
* when the image was shot. |
* Tag = 41994 (A40A.H) |
* Type = SHORT |
* Count = 1 |
* Default = 0 |
* 0 = Normal |
* 1 = Soft |
* 2 = Hard |
* Other = reserved |
*/ |
public static final int TAG_SHARPNESS = 0xA40A; |
// TODO support this tag (I haven't seen a camera's actual implementation of this yet) |
/** |
* This tag indicates information on the picture-taking conditions of a particular |
* camera model. The tag is used only to indicate the picture-taking conditions in |
* the reader. |
* Tag = 41995 (A40B.H) |
* Type = UNDEFINED |
* Count = Any |
* Default = none |
* |
* The information is recorded in the format shown below. The data is recorded |
* in Unicode using SHORT type for the number of display rows and columns and |
* UNDEFINED type for the camera settings. The Unicode (UCS-2) string including |
* Signature is NULL terminated. The specifics of the Unicode string are as given |
* in ISO/IEC 10464-1. |
* |
* Length Type Meaning |
* ------+-----------+------------------ |
* 2 SHORT Display columns |
* 2 SHORT Display rows |
* Any UNDEFINED Camera setting-1 |
* Any UNDEFINED Camera setting-2 |
* : : : |
* Any UNDEFINED Camera setting-n |
*/ |
public static final int TAG_DEVICE_SETTING_DESCRIPTION = 0xA40B; |
/** |
* This tag indicates the distance to the subject. |
* Tag = 41996 (A40C.H) |
* Type = SHORT |
* Count = 1 |
* Default = none |
* 0 = unknown |
* 1 = Macro |
* 2 = Close view |
* 3 = Distant view |
* Other = reserved |
*/ |
public static final int TAG_SUBJECT_DISTANCE_RANGE = 0xA40C; |
/** |
* The image title, as used by Windows XP. |
*/ |
public static final int TAG_WIN_TITLE = 0x9C9B; |
/** |
* The image comment, as used by Windows XP. |
*/ |
public static final int TAG_WIN_COMMENT = 0x9C9C; |
/** |
* The image author, as used by Windows XP (called Artist in the Windows shell). |
*/ |
public static final int TAG_WIN_AUTHOR = 0x9C9D; |
/** |
* The image keywords, as used by Windows XP. |
*/ |
public static final int TAG_WIN_KEYWORDS = 0x9C9E; |
/** |
* The image subject, as used by Windows XP. |
*/ |
public static final int TAG_WIN_SUBJECT = 0x9C9F; |
/** |
* This tag indicates an identifier assigned uniquely to each image. It is |
* recorded as an ASCII string equivalent to hexadecimal notation and 128-bit |
* fixed length. |
* Tag = 42016 (A420.H) |
* Type = ASCII |
* Count = 33 |
* Default = none |
*/ |
public static final int TAG_IMAGE_UNIQUE_ID = 0xA420; |
public static final int TAG_THUMBNAIL_IMAGE_WIDTH = 0x0100; |
public static final int TAG_THUMBNAIL_IMAGE_HEIGHT = 0x0101; |
public static final int TAG_THUMBNAIL_DATA = 0xF001; |
/** |
* 1 = Normal |
* 2 = Reversed |
*/ |
public static final int TAG_FILL_ORDER = 0x010A; |
public static final int TAG_DOCUMENT_NAME = 0x010D; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_FILL_ORDER), "Fill Order"); |
tagNameMap.put(new Integer(TAG_DOCUMENT_NAME), "Document Name"); |
tagNameMap.put(new Integer(0x1000), "Related Image File Format"); |
tagNameMap.put(new Integer(0x1001), "Related Image Width"); |
tagNameMap.put(new Integer(0x1002), "Related Image Length"); |
tagNameMap.put(new Integer(0x0156), "Transfer Range"); |
tagNameMap.put(new Integer(0x0200), "JPEG Proc"); |
tagNameMap.put(new Integer(0x8769), "Exif Offset"); |
tagNameMap.put(new Integer(TAG_COMPRESSION_LEVEL), "Compressed Bits Per Pixel"); |
tagNameMap.put(new Integer(0x927C), "Maker Note"); |
tagNameMap.put(new Integer(0xA005), "Interoperability Offset"); |
tagNameMap.put(new Integer(TAG_NEW_SUBFILE_TYPE), "New Subfile Type"); |
tagNameMap.put(new Integer(TAG_SUBFILE_TYPE), "Subfile Type"); |
tagNameMap.put(new Integer(TAG_THUMBNAIL_IMAGE_WIDTH), "Thumbnail Image Width"); |
tagNameMap.put(new Integer(TAG_THUMBNAIL_IMAGE_HEIGHT), "Thumbnail Image Height"); |
tagNameMap.put(new Integer(TAG_BITS_PER_SAMPLE), "Bits Per Sample"); |
tagNameMap.put(new Integer(TAG_COMPRESSION), "Compression"); |
tagNameMap.put(new Integer(TAG_PHOTOMETRIC_INTERPRETATION), "Photometric Interpretation"); |
tagNameMap.put(new Integer(TAG_THRESHOLDING), "Thresholding"); |
tagNameMap.put(new Integer(TAG_IMAGE_DESCRIPTION), "Image Description"); |
tagNameMap.put(new Integer(TAG_MAKE), "Make"); |
tagNameMap.put(new Integer(TAG_MODEL), "Model"); |
tagNameMap.put(new Integer(TAG_STRIP_OFFSETS), "Strip Offsets"); |
tagNameMap.put(new Integer(TAG_ORIENTATION), "Orientation"); |
tagNameMap.put(new Integer(TAG_SAMPLES_PER_PIXEL), "Samples Per Pixel"); |
tagNameMap.put(new Integer(TAG_ROWS_PER_STRIP), "Rows Per Strip"); |
tagNameMap.put(new Integer(TAG_STRIP_BYTE_COUNTS), "Strip Byte Counts"); |
tagNameMap.put(new Integer(TAG_X_RESOLUTION), "X Resolution"); |
tagNameMap.put(new Integer(TAG_Y_RESOLUTION), "Y Resolution"); |
tagNameMap.put(new Integer(TAG_PAGE_NAME), "Page Name"); |
tagNameMap.put(new Integer(TAG_PLANAR_CONFIGURATION), "Planar Configuration"); |
tagNameMap.put(new Integer(TAG_RESOLUTION_UNIT), "Resolution Unit"); |
tagNameMap.put(new Integer(TAG_TRANSFER_FUNCTION), "Transfer Function"); |
tagNameMap.put(new Integer(TAG_SOFTWARE), "Software"); |
tagNameMap.put(new Integer(TAG_DATETIME), "Date/Time"); |
tagNameMap.put(new Integer(TAG_ARTIST), "Artist"); |
tagNameMap.put(new Integer(TAG_PREDICTOR), "Predictor"); |
tagNameMap.put(new Integer(TAG_WHITE_POINT), "White Point"); |
tagNameMap.put(new Integer(TAG_PRIMARY_CHROMATICITIES), "Primary Chromaticities"); |
tagNameMap.put(new Integer(TAG_TILE_WIDTH), "Tile Width"); |
tagNameMap.put(new Integer(TAG_TILE_LENGTH), "Tile Length"); |
tagNameMap.put(new Integer(TAG_TILE_OFFSETS), "Tile Offsets"); |
tagNameMap.put(new Integer(TAG_TILE_BYTE_COUNTS), "Tile Byte Counts"); |
tagNameMap.put(new Integer(TAG_SUB_IFDS), "Sub IFDs"); |
tagNameMap.put(new Integer(TAG_JPEG_TABLES), "JPEG Tables"); |
tagNameMap.put(new Integer(TAG_THUMBNAIL_OFFSET), "Thumbnail Offset"); |
tagNameMap.put(new Integer(TAG_THUMBNAIL_LENGTH), "Thumbnail Length"); |
tagNameMap.put(new Integer(TAG_THUMBNAIL_DATA), "Thumbnail Data"); |
tagNameMap.put(new Integer(TAG_YCBCR_COEFFICIENTS), "YCbCr Coefficients"); |
tagNameMap.put(new Integer(TAG_YCBCR_SUBSAMPLING), "YCbCr Sub-Sampling"); |
tagNameMap.put(new Integer(TAG_YCBCR_POSITIONING), "YCbCr Positioning"); |
tagNameMap.put(new Integer(TAG_REFERENCE_BLACK_WHITE), "Reference Black/White"); |
tagNameMap.put(new Integer(TAG_CFA_REPEAT_PATTERN_DIM), "CFA Repeat Pattern Dim"); |
tagNameMap.put(new Integer(TAG_CFA_PATTERN_2), "CFA Pattern"); |
tagNameMap.put(new Integer(TAG_BATTERY_LEVEL), "Battery Level"); |
tagNameMap.put(new Integer(TAG_COPYRIGHT), "Copyright"); |
tagNameMap.put(new Integer(TAG_EXPOSURE_TIME), "Exposure Time"); |
tagNameMap.put(new Integer(TAG_FNUMBER), "F-Number"); |
tagNameMap.put(new Integer(TAG_IPTC_NAA), "IPTC/NAA"); |
tagNameMap.put(new Integer(TAG_INTER_COLOR_PROFILE), "Inter Color Profile"); |
tagNameMap.put(new Integer(TAG_EXPOSURE_PROGRAM), "Exposure Program"); |
tagNameMap.put(new Integer(TAG_SPECTRAL_SENSITIVITY), "Spectral Sensitivity"); |
tagNameMap.put(new Integer(TAG_GPS_INFO), "GPS Info"); |
tagNameMap.put(new Integer(TAG_ISO_EQUIVALENT), "ISO Speed Ratings"); |
tagNameMap.put(new Integer(TAG_OECF), "OECF"); |
tagNameMap.put(new Integer(TAG_INTERLACE), "Interlace"); |
tagNameMap.put(new Integer(TAG_TIME_ZONE_OFFSET), "Time Zone Offset"); |
tagNameMap.put(new Integer(TAG_SELF_TIMER_MODE), "Self Timer Mode"); |
tagNameMap.put(new Integer(TAG_EXIF_VERSION), "Exif Version"); |
tagNameMap.put(new Integer(TAG_DATETIME_ORIGINAL), "Date/Time Original"); |
tagNameMap.put(new Integer(TAG_DATETIME_DIGITIZED), "Date/Time Digitized"); |
tagNameMap.put(new Integer(TAG_COMPONENTS_CONFIGURATION), "Components Configuration"); |
tagNameMap.put(new Integer(TAG_SHUTTER_SPEED), "Shutter Speed Value"); |
tagNameMap.put(new Integer(TAG_APERTURE), "Aperture Value"); |
tagNameMap.put(new Integer(TAG_BRIGHTNESS_VALUE), "Brightness Value"); |
tagNameMap.put(new Integer(TAG_EXPOSURE_BIAS), "Exposure Bias Value"); |
tagNameMap.put(new Integer(TAG_MAX_APERTURE), "Max Aperture Value"); |
tagNameMap.put(new Integer(TAG_SUBJECT_DISTANCE), "Subject Distance"); |
tagNameMap.put(new Integer(TAG_METERING_MODE), "Metering Mode"); |
tagNameMap.put(new Integer(TAG_WHITE_BALANCE), "Light Source"); |
tagNameMap.put(new Integer(TAG_FLASH), "Flash"); |
tagNameMap.put(new Integer(TAG_FOCAL_LENGTH), "Focal Length"); |
tagNameMap.put(new Integer(TAG_FLASH_ENERGY), "Flash Energy"); |
tagNameMap.put(new Integer(TAG_SPATIAL_FREQ_RESPONSE), "Spatial Frequency Response"); |
tagNameMap.put(new Integer(TAG_NOISE), "Noise"); |
tagNameMap.put(new Integer(TAG_IMAGE_NUMBER), "Image Number"); |
tagNameMap.put(new Integer(TAG_SECURITY_CLASSIFICATION), "Security Classification"); |
tagNameMap.put(new Integer(TAG_IMAGE_HISTORY), "Image History"); |
tagNameMap.put(new Integer(TAG_SUBJECT_LOCATION), "Subject Location"); |
tagNameMap.put(new Integer(TAG_EXPOSURE_INDEX), "Exposure Index"); |
tagNameMap.put(new Integer(TAG_TIFF_EP_STANDARD_ID), "TIFF/EP Standard ID"); |
tagNameMap.put(new Integer(TAG_USER_COMMENT), "User Comment"); |
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME), "Sub-Sec Time"); |
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME_ORIGINAL), "Sub-Sec Time Original"); |
tagNameMap.put(new Integer(TAG_SUBSECOND_TIME_DIGITIZED), "Sub-Sec Time Digitized"); |
tagNameMap.put(new Integer(TAG_FLASHPIX_VERSION), "FlashPix Version"); |
tagNameMap.put(new Integer(TAG_COLOR_SPACE), "Color Space"); |
tagNameMap.put(new Integer(TAG_EXIF_IMAGE_WIDTH), "Exif Image Width"); |
tagNameMap.put(new Integer(TAG_EXIF_IMAGE_HEIGHT), "Exif Image Height"); |
tagNameMap.put(new Integer(TAG_RELATED_SOUND_FILE), "Related Sound File"); |
// 0x920B in TIFF/EP |
tagNameMap.put(new Integer(TAG_FLASH_ENERGY_2), "Flash Energy"); |
// 0x920C in TIFF/EP |
tagNameMap.put(new Integer(TAG_SPATIAL_FREQ_RESPONSE_2), "Spatial Frequency Response"); |
// 0x920E in TIFF/EP |
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_X_RES), "Focal Plane X Resolution"); |
// 0x920F in TIFF/EP |
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_Y_RES), "Focal Plane Y Resolution"); |
// 0x9210 in TIFF/EP |
tagNameMap.put(new Integer(TAG_FOCAL_PLANE_UNIT), "Focal Plane Resolution Unit"); |
// 0x9214 in TIFF/EP |
tagNameMap.put(new Integer(TAG_SUBJECT_LOCATION_2), "Subject Location"); |
// 0x9215 in TIFF/EP |
tagNameMap.put(new Integer(TAG_EXPOSURE_INDEX_2), "Exposure Index"); |
// 0x9217 in TIFF/EP |
tagNameMap.put(new Integer(TAG_SENSING_METHOD), "Sensing Method"); |
tagNameMap.put(new Integer(TAG_FILE_SOURCE), "File Source"); |
tagNameMap.put(new Integer(TAG_SCENE_TYPE), "Scene Type"); |
tagNameMap.put(new Integer(TAG_CFA_PATTERN), "CFA Pattern"); |
tagNameMap.put(new Integer(TAG_CUSTOM_RENDERED), "Custom Rendered"); |
tagNameMap.put(new Integer(TAG_EXPOSURE_MODE), "Exposure Mode"); |
tagNameMap.put(new Integer(TAG_WHITE_BALANCE_MODE), "White Balance"); |
tagNameMap.put(new Integer(TAG_DIGITAL_ZOOM_RATIO), "Digital Zoom Ratio"); |
tagNameMap.put(new Integer(TAG_35MM_FILM_EQUIV_FOCAL_LENGTH), "Focal Length 35"); |
tagNameMap.put(new Integer(TAG_SCENE_CAPTURE_TYPE), "Scene Capture Type"); |
tagNameMap.put(new Integer(TAG_GAIN_CONTROL), "Gain Control"); |
tagNameMap.put(new Integer(TAG_CONTRAST), "Contrast"); |
tagNameMap.put(new Integer(TAG_SATURATION), "Saturation"); |
tagNameMap.put(new Integer(TAG_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_DEVICE_SETTING_DESCRIPTION), "Device Setting Description"); |
tagNameMap.put(new Integer(TAG_SUBJECT_DISTANCE_RANGE), "Subject Distance Range"); |
tagNameMap.put(new Integer(TAG_WIN_AUTHOR), "Windows XP Author"); |
tagNameMap.put(new Integer(TAG_WIN_COMMENT), "Windows XP Comment"); |
tagNameMap.put(new Integer(TAG_WIN_KEYWORDS), "Windows XP Keywords"); |
tagNameMap.put(new Integer(TAG_WIN_SUBJECT), "Windows XP Subject"); |
tagNameMap.put(new Integer(TAG_WIN_TITLE), "Windows XP Title"); |
tagNameMap.put(new Integer(TAG_MIN_SAMPLE_VALUE), "Minimum sample value"); |
tagNameMap.put(new Integer(TAG_MAX_SAMPLE_VALUE), "Maximum sample value"); |
} |
public ExifDirectory() |
{ |
this.setDescriptor(new ExifDescriptor(this)); |
} |
public String getName() |
{ |
return "Exif"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
public byte[] getThumbnailData() throws MetadataException |
{ |
if (!containsThumbnail()) |
return null; |
return this.getByteArray(ExifDirectory.TAG_THUMBNAIL_DATA); |
} |
public void writeThumbnail(String filename) throws MetadataException, IOException |
{ |
byte[] data = getThumbnailData(); |
if (data==null) |
throw new MetadataException("No thumbnail data exists."); |
FileOutputStream stream = null; |
try { |
stream = new FileOutputStream(filename); |
stream.write(data); |
} finally { |
if (stream!=null) |
stream.close(); |
} |
} |
/* |
// This thumbnail extraction code is not complete, and is included to assist anyone who feels like looking into |
// it. Please share any progress with the original author, and hence the community. Thanks. |
/** |
* |
* @return |
* @throws MetadataException |
* / |
public Image getThumbnailImage() throws MetadataException |
{ |
if (!containsThumbnail()) |
return null; |
int compression = 0; |
try { |
compression = this.getInt(ExifDirectory.TAG_COMPRESSION); |
} catch (Throwable e) { |
this.addError("Unable to determine thumbnail type " + e.getMessage()); |
} |
final byte[] thumbnailBytes = getThumbnailData(); |
if (compression == ExifDirectory.COMPRESSION_JPEG) |
{ |
// JPEG Thumbnail |
// operate directly on thumbnailBytes |
// try { |
// int offset = this.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET); |
// int length = this.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH); |
// byte[] result = new byte[length]; |
// for (int i = 0; i<result.length; i++) { |
// result[i] = _data[tiffHeaderOffset + offset + i]; |
// } |
// this.setByteArray(ExifDirectory.TAG_THUMBNAIL_DATA, result); |
// } catch (Throwable e) { |
// this.addError("Unable to extract thumbnail: " + e.getMessage()); |
// } |
// TODO decode the JPEG bytes as an image |
return null; //new Image(); |
} |
else if (compression == ExifDirectory.COMPRESSION_NONE) |
{ |
// uncompressed thumbnail (raw RGB data) |
if (!this.containsTag(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) |
return null; |
try |
{ |
// If the image is RGB format, then convert it to a bitmap |
final int photometricInterpretation = this.getInt(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION); |
if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_RGB) |
{ |
// RGB |
Image image = createImageFromRawRgb(thumbnailBytes); |
return image; |
} |
else if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_YCBCR) |
{ |
// YCbCr |
Image image = createImageFromRawYCbCr(thumbnailBytes); |
return image; |
} |
else if (photometricInterpretation == ExifDirectory.PHOTOMETRIC_INTERPRETATION_MONOCHROME) |
{ |
// Monochrome |
// TODO |
return null; |
} |
} catch (Throwable e) { |
this.addError("Unable to extract thumbnail: " + e.getMessage()); |
} |
} |
return null; |
} |
/** |
* Handle the YCbCr thumbnail encoding used by Ricoh RDC4200/4300, Fuji DS-7/300 and DX-5/7/9 cameras. |
* |
* At DX-5/7/9, YCbCrSubsampling(0x0212) has values of '2,1', PlanarConfiguration(0x011c) has a value '1'. So the |
* data align of this image is below. |
* |
* Y(0,0),Y(1,0),Cb(0,0),Cr(0,0), Y(2,0),Y(3,0),Cb(2,0),Cr(3.0), Y(4,0),Y(5,0),Cb(4,0),Cr(4,0). . . . |
* |
* The numerics in parenthesis are pixel coordinates. DX series' YCbCrCoefficients(0x0211) has values '0.299/0.587/0.114', |
* ReferenceBlackWhite(0x0214) has values '0,255,128,255,128,255'. Therefore to convert from Y/Cb/Cr to RGB is; |
* |
* B(0,0)=(Cb-128)*(2-0.114*2)+Y(0,0) |
* R(0,0)=(Cr-128)*(2-0.299*2)+Y(0,0) |
* G(0,0)=(Y(0,0)-0.114*B(0,0)-0.299*R(0,0))/0.587 |
* |
* Horizontal subsampling is a value '2', so you can calculate B(1,0)/R(1,0)/G(1,0) by using the Y(1,0) and Cr(0,0)/Cb(0,0). |
* Repeat this conversion by value of ImageWidth(0x0100) and ImageLength(0x0101). |
* |
* @param thumbnailBytes |
* @return |
* @throws com.drew.metadata.MetadataException |
* / |
private Image createImageFromRawYCbCr(byte[] thumbnailBytes) throws MetadataException |
{ |
/* |
Y = 0.257R + 0.504G + 0.098B + 16 |
Cb = -0.148R - 0.291G + 0.439B + 128 |
Cr = 0.439R - 0.368G - 0.071B + 128 |
G = 1.164(Y-16) - 0.391(Cb-128) - 0.813(Cr-128) |
R = 1.164(Y-16) + 1.596(Cr-128) |
B = 1.164(Y-16) + 2.018(Cb-128) |
R, G and B range from 0 to 255. |
Y ranges from 16 to 235. |
Cb and Cr range from 16 to 240. |
http://www.faqs.org/faqs/graphics/colorspace-faq/ |
* / |
int length = thumbnailBytes.length; // this.getInt(ExifDirectory.TAG_STRIP_BYTE_COUNTS); |
final int imageWidth = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH); |
final int imageHeight = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT); |
// final int headerLength = 54; |
// byte[] result = new byte[length + headerLength]; |
// // Add a windows BMP header described: |
// // http://www.onicos.com/staff/iz/formats/bmp.html |
// result[0] = 'B'; |
// result[1] = 'M'; // File Type identifier |
// result[3] = (byte)(result.length / 256); |
// result[2] = (byte)result.length; |
// result[10] = (byte)headerLength; |
// result[14] = 40; // MS Windows BMP header |
// result[18] = (byte)imageWidth; |
// result[22] = (byte)imageHeight; |
// result[26] = 1; // 1 Plane |
// result[28] = 24; // Colour depth |
// result[34] = (byte)length; |
// result[35] = (byte)(length / 256); |
final BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB); |
// order is YCbCr and image is upside down, bitmaps are BGR |
//// for (int i = headerLength, dataOffset = length; i<result.length; i += 3, dataOffset -= 3) |
// { |
// final int y = thumbnailBytes[dataOffset - 2] & 0xFF; |
// final int cb = thumbnailBytes[dataOffset - 1] & 0xFF; |
// final int cr = thumbnailBytes[dataOffset] & 0xFF; |
// if (y<16 || y>235 || cb<16 || cb>240 || cr<16 || cr>240) |
// "".toString(); |
// |
// int g = (int)(1.164*(y-16) - 0.391*(cb-128) - 0.813*(cr-128)); |
// int r = (int)(1.164*(y-16) + 1.596*(cr-128)); |
// int b = (int)(1.164*(y-16) + 2.018*(cb-128)); |
// |
//// result[i] = (byte)b; |
//// result[i + 1] = (byte)g; |
//// result[i + 2] = (byte)r; |
// |
// // TODO compose the image here |
// image.setRGB(1, 2, 3); |
// } |
return image; |
} |
/** |
* Creates a thumbnail image in (Windows) BMP format from raw RGB data. |
* @param thumbnailBytes |
* @return |
* @throws com.drew.metadata.MetadataException |
* / |
private Image createImageFromRawRgb(byte[] thumbnailBytes) throws MetadataException |
{ |
final int length = thumbnailBytes.length; // this.getInt(ExifDirectory.TAG_STRIP_BYTE_COUNTS); |
final int imageWidth = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH); |
final int imageHeight = this.getInt(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT); |
// final int headerlength = 54; |
// final byte[] result = new byte[length + headerlength]; |
// // Add a windows BMP header described: |
// // http://www.onicos.com/staff/iz/formats/bmp.html |
// result[0] = 'B'; |
// result[1] = 'M'; // File Type identifier |
// result[3] = (byte)(result.length / 256); |
// result[2] = (byte)result.length; |
// result[10] = (byte)headerlength; |
// result[14] = 40; // MS Windows BMP header |
// result[18] = (byte)imageWidth; |
// result[22] = (byte)imageHeight; |
// result[26] = 1; // 1 Plane |
// result[28] = 24; // Colour depth |
// result[34] = (byte)length; |
// result[35] = (byte)(length / 256); |
final BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_RGB); |
// order is RGB and image is upside down, bitmaps are BGR |
// for (int i = headerlength, dataOffset = length; i<result.length; i += 3, dataOffset -= 3) |
// { |
// byte b = thumbnailBytes[dataOffset - 2]; |
// byte g = thumbnailBytes[dataOffset - 1]; |
// byte r = thumbnailBytes[dataOffset]; |
// |
// // TODO compose the image here |
// image.setRGB(1, 2, 3); |
// } |
return image; |
} |
*/ |
public boolean containsThumbnail() |
{ |
return containsTag(ExifDirectory.TAG_THUMBNAIL_DATA); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifInteropDirectory.java |
---|
0,0 → 1,60 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Nov-2002 10:58:13 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class ExifInteropDirectory extends Directory |
{ |
public static final int TAG_INTEROP_INDEX = 0x0001; |
public static final int TAG_INTEROP_VERSION = 0x0002; |
public static final int TAG_RELATED_IMAGE_FILE_FORMAT = 0x1000; |
public static final int TAG_RELATED_IMAGE_WIDTH = 0x1001; |
public static final int TAG_RELATED_IMAGE_LENGTH = 0x1002; |
protected static final HashMap tagNameMap; |
static |
{ |
tagNameMap = new HashMap(); |
tagNameMap.put(new Integer(TAG_INTEROP_INDEX), "Interoperability Index"); |
tagNameMap.put(new Integer(TAG_INTEROP_VERSION), "Interoperability Version"); |
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_FILE_FORMAT), "Related Image File Format"); |
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_WIDTH), "Related Image Width"); |
tagNameMap.put(new Integer(TAG_RELATED_IMAGE_LENGTH), "Related Image Length"); |
} |
public ExifInteropDirectory() |
{ |
this.setDescriptor(new ExifInteropDescriptor(this)); |
} |
public String getName() |
{ |
return "Interoperability"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KodakMakernoteDirectory.java |
---|
0,0 → 1,37 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* Describes tags specific to Kodak cameras. |
*/ |
public class KodakMakernoteDirectory extends Directory |
{ |
protected static final HashMap _tagNameMap = new HashMap(); |
public String getName() |
{ |
return "Kodak Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/GpsDescriptor.java |
---|
0,0 → 1,201 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 22:27:52 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class GpsDescriptor extends TagDescriptor |
{ |
public GpsDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case GpsDirectory.TAG_GPS_ALTITUDE: |
return getGpsAltitudeDescription(); |
case GpsDirectory.TAG_GPS_ALTITUDE_REF: |
return getGpsAltitudeRefDescription(); |
case GpsDirectory.TAG_GPS_STATUS: |
return getGpsStatusDescription(); |
case GpsDirectory.TAG_GPS_MEASURE_MODE: |
return getGpsMeasureModeDescription(); |
case GpsDirectory.TAG_GPS_SPEED_REF: |
return getGpsSpeedRefDescription(); |
case GpsDirectory.TAG_GPS_TRACK_REF: |
case GpsDirectory.TAG_GPS_IMG_DIRECTION_REF: |
case GpsDirectory.TAG_GPS_DEST_BEARING_REF: |
return getGpsDirectionReferenceDescription(tagType); |
case GpsDirectory.TAG_GPS_TRACK: |
case GpsDirectory.TAG_GPS_IMG_DIRECTION: |
case GpsDirectory.TAG_GPS_DEST_BEARING: |
return getGpsDirectionDescription(tagType); |
case GpsDirectory.TAG_GPS_DEST_DISTANCE_REF: |
return getGpsDestinationReferenceDescription(); |
case GpsDirectory.TAG_GPS_TIME_STAMP: |
return getGpsTimeStampDescription(); |
// three rational numbers -- displayed in HH"MM"SS.ss |
case GpsDirectory.TAG_GPS_LONGITUDE: |
return getGpsLongitudeDescription(); |
case GpsDirectory.TAG_GPS_LATITUDE: |
return getGpsLatitudeDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getGpsLatitudeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_LATITUDE)) return null; |
return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LATITUDE); |
} |
public String getGpsLongitudeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)) return null; |
return getHoursMinutesSecondsDescription(GpsDirectory.TAG_GPS_LONGITUDE); |
} |
public String getHoursMinutesSecondsDescription(int tagType) throws MetadataException |
{ |
Rational[] components = _directory.getRationalArray(tagType); |
// TODO create an HoursMinutesSecods class ?? |
int deg = components[0].intValue(); |
float min = components[1].floatValue(); |
float sec = components[2].floatValue(); |
// carry fractions of minutes into seconds -- thanks Colin Briton |
sec += (min % 1) * 60; |
return String.valueOf(deg) + "\"" + String.valueOf((int)min) + "'" + String.valueOf(sec); |
} |
public String getGpsTimeStampDescription() throws MetadataException |
{ |
// time in hour, min, sec |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP)) return null; |
int[] timeComponents = _directory.getIntArray(GpsDirectory.TAG_GPS_TIME_STAMP); |
StringBuffer sbuffer = new StringBuffer(); |
sbuffer.append(timeComponents[0]); |
sbuffer.append(":"); |
sbuffer.append(timeComponents[1]); |
sbuffer.append(":"); |
sbuffer.append(timeComponents[2]); |
sbuffer.append(" UTC"); |
return sbuffer.toString(); |
} |
public String getGpsDestinationReferenceDescription() |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF)) return null; |
String destRef = _directory.getString(GpsDirectory.TAG_GPS_DEST_DISTANCE_REF).trim(); |
if ("K".equalsIgnoreCase(destRef)) { |
return "kilometers"; |
} else if ("M".equalsIgnoreCase(destRef)) { |
return "miles"; |
} else if ("N".equalsIgnoreCase(destRef)) { |
return "knots"; |
} else { |
return "Unknown (" + destRef + ")"; |
} |
} |
public String getGpsDirectionDescription(int tagType) |
{ |
if (!_directory.containsTag(tagType)) return null; |
String gpsDirection = _directory.getString(tagType).trim(); |
return gpsDirection + " degrees"; |
} |
public String getGpsDirectionReferenceDescription(int tagType) |
{ |
if (!_directory.containsTag(tagType)) return null; |
String gpsDistRef = _directory.getString(tagType).trim(); |
if ("T".equalsIgnoreCase(gpsDistRef)) { |
return "True direction"; |
} else if ("M".equalsIgnoreCase(gpsDistRef)) { |
return "Magnetic direction"; |
} else { |
return "Unknown (" + gpsDistRef + ")"; |
} |
} |
public String getGpsSpeedRefDescription() |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_SPEED_REF)) return null; |
String gpsSpeedRef = _directory.getString(GpsDirectory.TAG_GPS_SPEED_REF).trim(); |
if ("K".equalsIgnoreCase(gpsSpeedRef)) { |
return "kph"; |
} else if ("M".equalsIgnoreCase(gpsSpeedRef)) { |
return "mph"; |
} else if ("N".equalsIgnoreCase(gpsSpeedRef)) { |
return "knots"; |
} else { |
return "Unknown (" + gpsSpeedRef + ")"; |
} |
} |
public String getGpsMeasureModeDescription() |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_MEASURE_MODE)) return null; |
String gpsSpeedMeasureMode = _directory.getString(GpsDirectory.TAG_GPS_MEASURE_MODE).trim(); |
if ("2".equalsIgnoreCase(gpsSpeedMeasureMode)) { |
return "2-dimensional measurement"; |
} else if ("3".equalsIgnoreCase(gpsSpeedMeasureMode)) { |
return "3-dimensional measurement"; |
} else { |
return "Unknown (" + gpsSpeedMeasureMode + ")"; |
} |
} |
public String getGpsStatusDescription() |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_STATUS)) return null; |
String gpsStatus = _directory.getString(GpsDirectory.TAG_GPS_STATUS).trim(); |
if ("A".equalsIgnoreCase(gpsStatus)) { |
return "Measurement in progess"; |
} else if ("V".equalsIgnoreCase(gpsStatus)) { |
return "Measurement Interoperability"; |
} else { |
return "Unknown (" + gpsStatus + ")"; |
} |
} |
public String getGpsAltitudeRefDescription() throws MetadataException |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF)) return null; |
int alititudeRef = _directory.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF); |
if (alititudeRef == 0) { |
return "Sea level"; |
} else { |
return "Unknown (" + alititudeRef + ")"; |
} |
} |
public String getGpsAltitudeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(GpsDirectory.TAG_GPS_ALTITUDE)) return null; |
String alititude = _directory.getRational(GpsDirectory.TAG_GPS_ALTITUDE).toSimpleString(true); |
return alititude + " metres"; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PentaxMakernoteDirectory.java |
---|
0,0 → 1,158 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* Directory for metadata specific to Pentax and Asahi cameras. |
*/ |
public class PentaxMakernoteDirectory extends Directory |
{ |
/** |
* 0 = Auto |
* 1 = Night-scene |
* 2 = Manual |
* 4 = Multiple |
*/ |
public static final int TAG_PENTAX_CAPTURE_MODE = 0x0001; |
/** |
* 0 = Good |
* 1 = Better |
* 2 = Best |
*/ |
public static final int TAG_PENTAX_QUALITY_LEVEL = 0x0002; |
/** |
* 2 = Custom |
* 3 = Auto |
*/ |
public static final int TAG_PENTAX_FOCUS_MODE = 0x0003; |
/** |
* 1 = Auto |
* 2 = Flash on |
* 4 = Flash off |
* 6 = Red-eye Reduction |
*/ |
public static final int TAG_PENTAX_FLASH_MODE = 0x0004; |
/** |
* 0 = Auto |
* 1 = Daylight |
* 2 = Shade |
* 3 = Tungsten |
* 4 = Fluorescent |
* 5 = Manual |
*/ |
public static final int TAG_PENTAX_WHITE_BALANCE = 0x0007; |
/** |
* (0 = Off) |
*/ |
public static final int TAG_PENTAX_DIGITAL_ZOOM = 0x000A; |
/** |
* 0 = Normal |
* 1 = Soft |
* 2 = Hard |
*/ |
public static final int TAG_PENTAX_SHARPNESS = 0x000B; |
/** |
* 0 = Normal |
* 1 = Low |
* 2 = High |
*/ |
public static final int TAG_PENTAX_CONTRAST = 0x000C; |
/** |
* 0 = Normal |
* 1 = Low |
* 2 = High |
*/ |
public static final int TAG_PENTAX_SATURATION = 0x000D; |
/** |
* 10 = ISO 100 |
* 16 = ISO 200 |
* 100 = ISO 100 |
* 200 = ISO 200 |
*/ |
public static final int TAG_PENTAX_ISO_SPEED = 0x0014; |
/** |
* 1 = Normal |
* 2 = Black & White |
* 3 = Sepia |
*/ |
public static final int TAG_PENTAX_COLOUR = 0x0017; |
/** |
* See Print Image Matching for specification. |
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html |
*/ |
public static final int TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO = 0x0E00; |
/** |
* (String). |
*/ |
public static final int TAG_PENTAX_TIME_ZONE = 0x1000; |
/** |
* (String). |
*/ |
public static final int TAG_PENTAX_DAYLIGHT_SAVINGS = 0x1001; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_PENTAX_CAPTURE_MODE), "Capture Mode"); |
tagNameMap.put(new Integer(TAG_PENTAX_QUALITY_LEVEL), "Quality Level"); |
tagNameMap.put(new Integer(TAG_PENTAX_FOCUS_MODE), "Focus Mode"); |
tagNameMap.put(new Integer(TAG_PENTAX_FLASH_MODE), "Flash Mode"); |
tagNameMap.put(new Integer(TAG_PENTAX_WHITE_BALANCE), "White Balance"); |
tagNameMap.put(new Integer(TAG_PENTAX_DIGITAL_ZOOM), "Digital Zoom"); |
tagNameMap.put(new Integer(TAG_PENTAX_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_PENTAX_CONTRAST), "Contrast"); |
tagNameMap.put(new Integer(TAG_PENTAX_SATURATION), "Saturation"); |
tagNameMap.put(new Integer(TAG_PENTAX_ISO_SPEED), "ISO Speed"); |
tagNameMap.put(new Integer(TAG_PENTAX_COLOUR), "Colour"); |
tagNameMap.put(new Integer(TAG_PENTAX_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); |
tagNameMap.put(new Integer(TAG_PENTAX_TIME_ZONE), "Time Zone"); |
tagNameMap.put(new Integer(TAG_PENTAX_DAYLIGHT_SAVINGS), "Daylight Savings"); |
} |
public PentaxMakernoteDirectory() |
{ |
this.setDescriptor(new PentaxMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Pentax Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifDescriptor.java |
---|
0,0 → 1,1121 |
/* |
* ExifDescriptor.java |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 22:27:15 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.imaging.PhotographicConversions; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
import java.io.UnsupportedEncodingException; |
import java.text.DecimalFormat; |
/** |
* Contains all logic for the presentation of raw Exif data, as stored in ExifDirectory. Use |
* this class to provide human-readable descriptions of tag values. |
*/ |
public class ExifDescriptor extends TagDescriptor |
{ |
/** |
* Dictates whether rational values will be represented in decimal format in instances |
* where decimal notation is elegant (such as 1/2 -> 0.5, but not 1/3). |
*/ |
private boolean _allowDecimalRepresentationOfRationals = true; |
private static final java.text.DecimalFormat SimpleDecimalFormatter = new DecimalFormat("0.#"); |
public ExifDescriptor(Directory directory) |
{ |
super(directory); |
} |
// Note for the potential addition of brightness presentation in eV: |
// Brightness of taken subject. To calculate Exposure(Ev) from BrigtnessValue(Bv), |
// you must add SensitivityValue(Sv). |
// Ev=BV+Sv Sv=log2(ISOSpeedRating/3.125) |
// ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32. |
/** |
* Returns a descriptive value of the the specified tag for this image. |
* Where possible, known values will be substituted here in place of the raw |
* tokens actually kept in the Exif segment. If no substitution is |
* available, the value provided by getString(int) will be returned. |
* @param tagType the tag to find a description for |
* @return a description of the image's value for the specified tag, or |
* <code>null</code> if the tag hasn't been defined. |
*/ |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case ExifDirectory.TAG_ORIENTATION: |
return getOrientationDescription(); |
case ExifDirectory.TAG_NEW_SUBFILE_TYPE: |
return getNewSubfileTypeDescription(); |
case ExifDirectory.TAG_SUBFILE_TYPE: |
return getSubfileTypeDescription(); |
case ExifDirectory.TAG_THRESHOLDING: |
return getThresholdingDescription(); |
case ExifDirectory.TAG_FILL_ORDER: |
return getFillOrderDescription(); |
case ExifDirectory.TAG_RESOLUTION_UNIT: |
return getResolutionDescription(); |
case ExifDirectory.TAG_YCBCR_POSITIONING: |
return getYCbCrPositioningDescription(); |
case ExifDirectory.TAG_EXPOSURE_TIME: |
return getExposureTimeDescription(); |
case ExifDirectory.TAG_SHUTTER_SPEED: |
return getShutterSpeedDescription(); |
case ExifDirectory.TAG_FNUMBER: |
return getFNumberDescription(); |
case ExifDirectory.TAG_X_RESOLUTION: |
return getXResolutionDescription(); |
case ExifDirectory.TAG_Y_RESOLUTION: |
return getYResolutionDescription(); |
case ExifDirectory.TAG_THUMBNAIL_OFFSET: |
return getThumbnailOffsetDescription(); |
case ExifDirectory.TAG_THUMBNAIL_LENGTH: |
return getThumbnailLengthDescription(); |
case ExifDirectory.TAG_COMPRESSION_LEVEL: |
return getCompressionLevelDescription(); |
case ExifDirectory.TAG_SUBJECT_DISTANCE: |
return getSubjectDistanceDescription(); |
case ExifDirectory.TAG_METERING_MODE: |
return getMeteringModeDescription(); |
case ExifDirectory.TAG_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case ExifDirectory.TAG_FLASH: |
return getFlashDescription(); |
case ExifDirectory.TAG_FOCAL_LENGTH: |
return getFocalLengthDescription(); |
case ExifDirectory.TAG_COLOR_SPACE: |
return getColorSpaceDescription(); |
case ExifDirectory.TAG_EXIF_IMAGE_WIDTH: |
return getExifImageWidthDescription(); |
case ExifDirectory.TAG_EXIF_IMAGE_HEIGHT: |
return getExifImageHeightDescription(); |
case ExifDirectory.TAG_FOCAL_PLANE_UNIT: |
return getFocalPlaneResolutionUnitDescription(); |
case ExifDirectory.TAG_FOCAL_PLANE_X_RES: |
return getFocalPlaneXResolutionDescription(); |
case ExifDirectory.TAG_FOCAL_PLANE_Y_RES: |
return getFocalPlaneYResolutionDescription(); |
case ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH: |
return getThumbnailImageWidthDescription(); |
case ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT: |
return getThumbnailImageHeightDescription(); |
case ExifDirectory.TAG_BITS_PER_SAMPLE: |
return getBitsPerSampleDescription(); |
case ExifDirectory.TAG_COMPRESSION: |
return getCompressionDescription(); |
case ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION: |
return getPhotometricInterpretationDescription(); |
case ExifDirectory.TAG_ROWS_PER_STRIP: |
return getRowsPerStripDescription(); |
case ExifDirectory.TAG_STRIP_BYTE_COUNTS: |
return getStripByteCountsDescription(); |
case ExifDirectory.TAG_SAMPLES_PER_PIXEL: |
return getSamplesPerPixelDescription(); |
case ExifDirectory.TAG_PLANAR_CONFIGURATION: |
return getPlanarConfigurationDescription(); |
case ExifDirectory.TAG_YCBCR_SUBSAMPLING: |
return getYCbCrSubsamplingDescription(); |
case ExifDirectory.TAG_EXPOSURE_PROGRAM: |
return getExposureProgramDescription(); |
case ExifDirectory.TAG_APERTURE: |
return getApertureValueDescription(); |
case ExifDirectory.TAG_MAX_APERTURE: |
return getMaxApertureValueDescription(); |
case ExifDirectory.TAG_SENSING_METHOD: |
return getSensingMethodDescription(); |
case ExifDirectory.TAG_EXPOSURE_BIAS: |
return getExposureBiasDescription(); |
case ExifDirectory.TAG_FILE_SOURCE: |
return getFileSourceDescription(); |
case ExifDirectory.TAG_SCENE_TYPE: |
return getSceneTypeDescription(); |
case ExifDirectory.TAG_COMPONENTS_CONFIGURATION: |
return getComponentConfigurationDescription(); |
case ExifDirectory.TAG_EXIF_VERSION: |
return getExifVersionDescription(); |
case ExifDirectory.TAG_FLASHPIX_VERSION: |
return getFlashPixVersionDescription(); |
case ExifDirectory.TAG_REFERENCE_BLACK_WHITE: |
return getReferenceBlackWhiteDescription(); |
case ExifDirectory.TAG_ISO_EQUIVALENT: |
return getIsoEquivalentDescription(); |
case ExifDirectory.TAG_THUMBNAIL_DATA: |
return getThumbnailDescription(); |
case ExifDirectory.TAG_USER_COMMENT: |
return getUserCommentDescription(); |
case ExifDirectory.TAG_CUSTOM_RENDERED: |
return getCustomRenderedDescription(); |
case ExifDirectory.TAG_EXPOSURE_MODE: |
return getExposureModeDescription(); |
case ExifDirectory.TAG_WHITE_BALANCE_MODE: |
return getWhiteBalanceModeDescription(); |
case ExifDirectory.TAG_DIGITAL_ZOOM_RATIO: |
return getDigitalZoomRatioDescription(); |
case ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH: |
return get35mmFilmEquivFocalLengthDescription(); |
case ExifDirectory.TAG_SCENE_CAPTURE_TYPE: |
return getSceneCaptureTypeDescription(); |
case ExifDirectory.TAG_GAIN_CONTROL: |
return getGainControlDescription(); |
case ExifDirectory.TAG_CONTRAST: |
return getContrastDescription(); |
case ExifDirectory.TAG_SATURATION: |
return getSaturationDescription(); |
case ExifDirectory.TAG_SHARPNESS: |
return getSharpnessDescription(); |
case ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE: |
return getSubjectDistanceRangeDescription(); |
case ExifDirectory.TAG_WIN_AUTHOR: |
return getWindowsAuthorDescription(); |
case ExifDirectory.TAG_WIN_COMMENT: |
return getWindowsCommentDescription(); |
case ExifDirectory.TAG_WIN_KEYWORDS: |
return getWindowsKeywordsDescription(); |
case ExifDirectory.TAG_WIN_SUBJECT: |
return getWindowsSubjectDescription(); |
case ExifDirectory.TAG_WIN_TITLE: |
return getWindowsTitleDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getNewSubfileTypeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_NEW_SUBFILE_TYPE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_NEW_SUBFILE_TYPE)) { |
case 1: return "Full-resolution image"; |
case 2: return "Reduced-resolution image"; |
case 3: return "Single page of multi-page reduced-resolution image"; |
case 4: return "Transparency mask"; |
case 5: return "Transparency mask of reduced-resolution image"; |
case 6: return "Transparency mask of multi-page image"; |
case 7: return "Transparency mask of reduced-resolution multi-page image"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_NEW_SUBFILE_TYPE) + ")"; |
} |
} |
public String getSubfileTypeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SUBFILE_TYPE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_SUBFILE_TYPE)) { |
case 1: return "Full-resolution image"; |
case 2: return "Reduced-resolution image"; |
case 3: return "Single page of multi-page image"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SUBFILE_TYPE) + ")"; |
} |
} |
public String getThresholdingDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THRESHOLDING)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_THRESHOLDING)) { |
case 1: return "No dithering or halftoning"; |
case 2: return "Ordered dither or halftone"; |
case 3: return "Randomized dither"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_THRESHOLDING) + ")"; |
} |
} |
public String getFillOrderDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FILL_ORDER)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_FILL_ORDER)) { |
case 1: return "Normal"; |
case 2: return "Reversed"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_FILL_ORDER) + ")"; |
} |
} |
public String getSubjectDistanceRangeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE)) { |
case 0: |
return "Unknown"; |
case 1: |
return "Macro"; |
case 2: |
return "Close view"; |
case 3: |
return "Distant view"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SUBJECT_DISTANCE_RANGE) + ")"; |
} |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SHARPNESS)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_SHARPNESS)) { |
case 0: |
return "None"; |
case 1: |
return "Low"; |
case 2: |
return "Hard"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SHARPNESS) + ")"; |
} |
} |
public String getSaturationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SATURATION)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_SATURATION)) { |
case 0: |
return "None"; |
case 1: |
return "Low saturation"; |
case 2: |
return "High saturation"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SATURATION) + ")"; |
} |
} |
public String getContrastDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_CONTRAST)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_CONTRAST)) { |
case 0: |
return "None"; |
case 1: |
return "Soft"; |
case 2: |
return "Hard"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_CONTRAST) + ")"; |
} |
} |
public String getGainControlDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_GAIN_CONTROL)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_GAIN_CONTROL)) { |
case 0: |
return "None"; |
case 1: |
return "Low gain up"; |
case 2: |
return "Low gain down"; |
case 3: |
return "High gain up"; |
case 4: |
return "High gain down"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_GAIN_CONTROL) + ")"; |
} |
} |
public String getSceneCaptureTypeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SCENE_CAPTURE_TYPE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_SCENE_CAPTURE_TYPE)) { |
case 0: |
return "Standard"; |
case 1: |
return "Landscape"; |
case 2: |
return "Portrait"; |
case 3: |
return "Night scene"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_SCENE_CAPTURE_TYPE) + ")"; |
} |
} |
public String get35mmFilmEquivFocalLengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH)) return null; |
int equivalentFocalLength = _directory.getInt(ExifDirectory.TAG_35MM_FILM_EQUIV_FOCAL_LENGTH); |
if (equivalentFocalLength==0) |
return "Unknown"; |
else |
return SimpleDecimalFormatter.format(equivalentFocalLength) + "mm"; |
} |
public String getDigitalZoomRatioDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_DIGITAL_ZOOM_RATIO)) return null; |
Rational rational = _directory.getRational(ExifDirectory.TAG_DIGITAL_ZOOM_RATIO); |
if (rational.getNumerator()==0) |
return "Digital zoom not used."; |
return SimpleDecimalFormatter.format(rational.doubleValue()); |
} |
public String getWhiteBalanceModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_WHITE_BALANCE_MODE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_WHITE_BALANCE_MODE)) { |
case 0: |
return "Auto white balance"; |
case 1: |
return "Manual white balance"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_WHITE_BALANCE_MODE) + ")"; |
} |
} |
public String getExposureModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_MODE)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_EXPOSURE_MODE)) { |
case 0: |
return "Auto exposure"; |
case 1: |
return "Manual exposure"; |
case 2: |
return "Auto bracket"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_EXPOSURE_MODE) + ")"; |
} |
} |
public String getCustomRenderedDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_CUSTOM_RENDERED)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_CUSTOM_RENDERED)) { |
case 0: |
return "Normal process"; |
case 1: |
return "Custom process"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_CUSTOM_RENDERED) + ")"; |
} |
} |
public String getUserCommentDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_USER_COMMENT)) return null; |
byte[] commentBytes = _directory.getByteArray(ExifDirectory.TAG_USER_COMMENT); |
if (commentBytes.length==0) |
return ""; |
final String[] encodingNames = new String[] { "ASCII", "UNICODE", "JIS" }; |
if (commentBytes.length>=10) |
{ |
String encodingRegion = new String(commentBytes, 0, 10); |
// try each encoding name |
for (int i = 0; i<encodingNames.length; i++) { |
String encodingName = encodingNames[i]; |
if (encodingRegion.startsWith(encodingName)) |
{ |
// remove the null characters (and any spaces) commonly present after the encoding name |
for (int j = encodingName.length(); j<10; j++) { |
byte b = commentBytes[j]; |
if (b!='\0' && b!=' ') { |
if (encodingName.equals("UNICODE")) { |
try { |
return new String(commentBytes, j, commentBytes.length - j, "UTF-16LE").trim(); |
} |
catch (UnsupportedEncodingException ex) { |
return null; |
} |
} |
return new String(commentBytes, j, commentBytes.length - j).trim(); |
} |
} |
return new String(commentBytes, 10, commentBytes.length - 10).trim(); |
} |
} |
} |
// special handling fell through, return a plain string representation |
return new String(commentBytes).trim(); |
} |
public String getThumbnailDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA)) return null; |
int[] thumbnailBytes = _directory.getIntArray(ExifDirectory.TAG_THUMBNAIL_DATA); |
return "[" + thumbnailBytes.length + " bytes of thumbnail data]"; |
} |
public String getIsoEquivalentDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_ISO_EQUIVALENT)) return null; |
int isoEquiv = _directory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT); |
if (isoEquiv < 50) { |
isoEquiv *= 200; |
} |
return Integer.toString(isoEquiv); |
} |
public String getReferenceBlackWhiteDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_REFERENCE_BLACK_WHITE)) return null; |
int[] ints = _directory.getIntArray(ExifDirectory.TAG_REFERENCE_BLACK_WHITE); |
int blackR = ints[0]; |
int whiteR = ints[1]; |
int blackG = ints[2]; |
int whiteG = ints[3]; |
int blackB = ints[4]; |
int whiteB = ints[5]; |
String pos = "[" + blackR + "," + blackG + "," + blackB + "] " + |
"[" + whiteR + "," + whiteG + "," + whiteB + "]"; |
return pos; |
} |
public String getExifVersionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_VERSION)) return null; |
int[] ints = _directory.getIntArray(ExifDirectory.TAG_EXIF_VERSION); |
return ExifDescriptor.convertBytesToVersionString(ints); |
} |
public String getFlashPixVersionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FLASHPIX_VERSION)) return null; |
int[] ints = _directory.getIntArray(ExifDirectory.TAG_FLASHPIX_VERSION); |
return ExifDescriptor.convertBytesToVersionString(ints); |
} |
public String getSceneTypeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SCENE_TYPE)) return null; |
int sceneType = _directory.getInt(ExifDirectory.TAG_SCENE_TYPE); |
if (sceneType == 1) { |
return "Directly photographed image"; |
} else { |
return "Unknown (" + sceneType + ")"; |
} |
} |
public String getFileSourceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FILE_SOURCE)) return null; |
int fileSource = _directory.getInt(ExifDirectory.TAG_FILE_SOURCE); |
if (fileSource == 3) { |
return "Digital Still Camera (DSC)"; |
} else { |
return "Unknown (" + fileSource + ")"; |
} |
} |
public String getExposureBiasDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_BIAS)) return null; |
Rational exposureBias = _directory.getRational(ExifDirectory.TAG_EXPOSURE_BIAS); |
return exposureBias.toSimpleString(true) + " EV"; |
} |
public String getMaxApertureValueDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_MAX_APERTURE)) return null; |
double aperture = _directory.getDouble(ExifDirectory.TAG_MAX_APERTURE); |
double fStop = PhotographicConversions.apertureToFStop(aperture); |
return "F" + SimpleDecimalFormatter.format(fStop); |
} |
public String getApertureValueDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_APERTURE)) return null; |
double aperture = _directory.getDouble(ExifDirectory.TAG_APERTURE); |
double fStop = PhotographicConversions.apertureToFStop(aperture); |
return "F" + SimpleDecimalFormatter.format(fStop); |
} |
public String getExposureProgramDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_PROGRAM)) return null; |
// '1' means manual control, '2' program normal, '3' aperture priority, |
// '4' shutter priority, '5' program creative (slow program), |
// '6' program action(high-speed program), '7' portrait mode, '8' landscape mode. |
switch (_directory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM)) { |
case 1: return "Manual control"; |
case 2: return "Program normal"; |
case 3: return "Aperture priority"; |
case 4: return "Shutter priority"; |
case 5: return "Program creative (slow program)"; |
case 6: return "Program action (high-speed program)"; |
case 7: return "Portrait mode"; |
case 8: return "Landscape mode"; |
default: |
return "Unknown program (" + _directory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM) + ")"; |
} |
} |
public String getYCbCrSubsamplingDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_YCBCR_SUBSAMPLING)) return null; |
int[] positions = _directory.getIntArray(ExifDirectory.TAG_YCBCR_SUBSAMPLING); |
if (positions[0] == 2 && positions[1] == 1) { |
return "YCbCr4:2:2"; |
} else if (positions[0] == 2 && positions[1] == 2) { |
return "YCbCr4:2:0"; |
} else { |
return "(Unknown)"; |
} |
} |
public String getPlanarConfigurationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_PLANAR_CONFIGURATION)) return null; |
// When image format is no compression YCbCr, this value shows byte aligns of YCbCr |
// data. If value is '1', Y/Cb/Cr value is chunky format, contiguous for each subsampling |
// pixel. If value is '2', Y/Cb/Cr value is separated and stored to Y plane/Cb plane/Cr |
// plane format. |
switch (_directory.getInt(ExifDirectory.TAG_PLANAR_CONFIGURATION)) { |
case 1: return "Chunky (contiguous for each subsampling pixel)"; |
case 2: return "Separate (Y-plane/Cb-plane/Cr-plane format)"; |
default: |
return "Unknown configuration"; |
} |
} |
public String getSamplesPerPixelDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SAMPLES_PER_PIXEL)) return null; |
return _directory.getString(ExifDirectory.TAG_SAMPLES_PER_PIXEL) + " samples/pixel"; |
} |
public String getRowsPerStripDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_ROWS_PER_STRIP)) return null; |
return _directory.getString(ExifDirectory.TAG_ROWS_PER_STRIP) + " rows/strip"; |
} |
public String getStripByteCountsDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_STRIP_BYTE_COUNTS)) return null; |
return _directory.getString(ExifDirectory.TAG_STRIP_BYTE_COUNTS) + " bytes"; |
} |
public String getPhotometricInterpretationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) return null; |
// Shows the color space of the image data components |
switch (_directory.getInt(ExifDirectory.TAG_PHOTOMETRIC_INTERPRETATION)) { |
case 0: return "WhiteIsZero"; |
case 1: return "BlackIsZero"; |
case 2: return "RGB"; |
case 3: return "RGB Palette"; |
case 4: return "Transparency Mask"; |
case 5: return "CMYK"; |
case 6: return "YCbCr"; |
case 8: return "CIELab"; |
case 9: return "ICCLab"; |
case 10: return "ITULab"; |
case 32803: return "Color Filter Array"; |
case 32844: return "Pixar LogL"; |
case 32845: return "Pixar LogLuv"; |
case 32892: return "Linear Raw"; |
default: |
return "Unknown colour space"; |
} |
} |
public String getCompressionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_COMPRESSION)) return null; |
switch (_directory.getInt(ExifDirectory.TAG_COMPRESSION)) { |
case 1: return "Uncompressed"; |
case 2: return "CCITT 1D"; |
case 3: return "T4/Group 3 Fax"; |
case 4: return "T6/Group 4 Fax"; |
case 5: return "LZW"; |
case 6: return "JPEG (old-style)"; |
case 7: return "JPEG"; |
case 8: return "Adobe Deflate"; |
case 9: return "JBIG B&W"; |
case 10: return "JBIG Color"; |
case 32766: return "Next"; |
case 32771: return "CCIRLEW"; |
case 32773: return "PackBits"; |
case 32809: return "Thunderscan"; |
case 32895: return "IT8CTPAD"; |
case 32896: return "IT8LW"; |
case 32897: return "IT8MP"; |
case 32898: return "IT8BL"; |
case 32908: return "PixarFilm"; |
case 32909: return "PixarLog"; |
case 32946: return "Deflate"; |
case 32947: return "DCS"; |
case 32661: return "JBIG"; |
case 32676: return "SGILog"; |
case 32677: return "SGILog24"; |
case 32712: return "JPEG 2000"; |
case 32713: return "Nikon NEF Compressed"; |
default: |
return "Unknown compression"; |
} |
} |
public String getBitsPerSampleDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_BITS_PER_SAMPLE)) return null; |
return _directory.getString(ExifDirectory.TAG_BITS_PER_SAMPLE) + " bits/component/pixel"; |
} |
public String getThumbnailImageWidthDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH)) return null; |
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_IMAGE_WIDTH) + " pixels"; |
} |
public String getThumbnailImageHeightDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT)) return null; |
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_IMAGE_HEIGHT) + " pixels"; |
} |
public String getFocalPlaneXResolutionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_X_RES)) return null; |
Rational rational = _directory.getRational(ExifDirectory.TAG_FOCAL_PLANE_X_RES); |
return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals) + " " + |
getFocalPlaneResolutionUnitDescription().toLowerCase(); |
} |
public String getFocalPlaneYResolutionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_Y_RES)) return null; |
Rational rational = _directory.getRational(ExifDirectory.TAG_FOCAL_PLANE_Y_RES); |
return rational.getReciprocal().toSimpleString(_allowDecimalRepresentationOfRationals) + " " + |
getFocalPlaneResolutionUnitDescription().toLowerCase(); |
} |
public String getFocalPlaneResolutionUnitDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) return null; |
// Unit of FocalPlaneXResoluton/FocalPlaneYResolution. '1' means no-unit, |
// '2' inch, '3' centimeter. |
switch (_directory.getInt(ExifDirectory.TAG_FOCAL_PLANE_UNIT)) { |
case 1: |
return "(No unit)"; |
case 2: |
return "Inches"; |
case 3: |
return "cm"; |
default: |
return ""; |
} |
} |
public String getExifImageWidthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)) return null; |
return _directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH) + " pixels"; |
} |
public String getExifImageHeightDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)) return null; |
return _directory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT) + " pixels"; |
} |
public String getColorSpaceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_COLOR_SPACE)) return null; |
int colorSpace = _directory.getInt(ExifDirectory.TAG_COLOR_SPACE); |
if (colorSpace == 1) { |
return "sRGB"; |
} else if (colorSpace == 65535) { |
return "Undefined"; |
} else { |
return "Unknown"; |
} |
} |
public String getFocalLengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FOCAL_LENGTH)) return null; |
java.text.DecimalFormat formatter = new DecimalFormat("0.0##"); |
Rational focalLength = _directory.getRational(ExifDirectory.TAG_FOCAL_LENGTH); |
return formatter.format(focalLength.doubleValue()) + " mm"; |
} |
public String getFlashDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FLASH)) return null; |
/* |
* This is a bitmask. |
* 0 = flash fired |
* 1 = return detected |
* 2 = return able to be detected |
* 3 = unknown |
* 4 = auto used |
* 5 = unknown |
* 6 = red eye reduction used |
*/ |
int val = _directory.getInt(ExifDirectory.TAG_FLASH); |
StringBuffer sb = new StringBuffer(); |
if ((val & 0x1)!=0) |
sb.append("Flash fired"); |
else |
sb.append("Flash did not fire"); |
// check if we're able to detect a return, before we mention it |
if ((val & 0x4)!=0) |
{ |
if ((val & 0x2)!=0) |
sb.append(", return detected"); |
else |
sb.append(", return not detected"); |
} |
if ((val & 0x10)!=0) |
sb.append(", auto"); |
if ((val & 0x40)!=0) |
sb.append(", red-eye reduction"); |
return sb.toString(); |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_WHITE_BALANCE)) return null; |
// '0' means unknown, '1' daylight, '2' fluorescent, '3' tungsten, '10' flash, |
// '17' standard light A, '18' standard light B, '19' standard light C, '20' D55, |
// '21' D65, '22' D75, '255' other. |
switch (_directory.getInt(ExifDirectory.TAG_WHITE_BALANCE)) { |
case 0: |
return "Unknown"; |
case 1: |
return "Daylight"; |
case 2: |
return "Flourescent"; |
case 3: |
return "Tungsten"; |
case 10: |
return "Flash"; |
case 17: |
return "Standard light"; |
case 18: |
return "Standard light (B)"; |
case 19: |
return "Standard light (C)"; |
case 20: |
return "D55"; |
case 21: |
return "D65"; |
case 22: |
return "D75"; |
case 255: |
return "(Other)"; |
default: |
return "Unknown (" + _directory.getInt(ExifDirectory.TAG_WHITE_BALANCE) + ")"; |
} |
} |
public String getMeteringModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_METERING_MODE)) return null; |
// '0' means unknown, '1' average, '2' center weighted average, '3' spot |
// '4' multi-spot, '5' multi-segment, '6' partial, '255' other |
int meteringMode = _directory.getInt(ExifDirectory.TAG_METERING_MODE); |
switch (meteringMode) { |
case 0: |
return "Unknown"; |
case 1: |
return "Average"; |
case 2: |
return "Center weighted average"; |
case 3: |
return "Spot"; |
case 4: |
return "Multi-spot"; |
case 5: |
return "Multi-segment"; |
case 6: |
return "Partial"; |
case 255: |
return "(Other)"; |
default: |
return ""; |
} |
} |
public String getSubjectDistanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SUBJECT_DISTANCE)) return null; |
Rational distance = _directory.getRational(ExifDirectory.TAG_SUBJECT_DISTANCE); |
java.text.DecimalFormat formatter = new DecimalFormat("0.0##"); |
return formatter.format(distance.doubleValue()) + " metres"; |
} |
public String getCompressionLevelDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_COMPRESSION_LEVEL)) return null; |
Rational compressionRatio = _directory.getRational(ExifDirectory.TAG_COMPRESSION_LEVEL); |
String ratio = compressionRatio.toSimpleString(_allowDecimalRepresentationOfRationals); |
if (compressionRatio.isInteger() && compressionRatio.intValue() == 1) { |
return ratio + " bit/pixel"; |
} else { |
return ratio + " bits/pixel"; |
} |
} |
public String getThumbnailLengthDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_LENGTH)) return null; |
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_LENGTH) + " bytes"; |
} |
public String getThumbnailOffsetDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_THUMBNAIL_OFFSET)) return null; |
return _directory.getString(ExifDirectory.TAG_THUMBNAIL_OFFSET) + " bytes"; |
} |
public String getYResolutionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_Y_RESOLUTION)) return null; |
Rational resolution = _directory.getRational(ExifDirectory.TAG_Y_RESOLUTION); |
return resolution.toSimpleString(_allowDecimalRepresentationOfRationals) + |
" dots per " + |
getResolutionDescription().toLowerCase(); |
} |
public String getXResolutionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_X_RESOLUTION)) return null; |
Rational resolution = _directory.getRational(ExifDirectory.TAG_X_RESOLUTION); |
return resolution.toSimpleString(_allowDecimalRepresentationOfRationals) + |
" dots per " + |
getResolutionDescription().toLowerCase(); |
} |
public String getExposureTimeDescription() |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_EXPOSURE_TIME)) return null; |
return _directory.getString(ExifDirectory.TAG_EXPOSURE_TIME) + " sec"; |
} |
public String getShutterSpeedDescription() throws MetadataException |
{ |
// I believe this method to now be stable, but am leaving some alternative snippets of |
// code in here, to assist anyone who's looking into this (given that I don't have a public CVS). |
if (!_directory.containsTag(ExifDirectory.TAG_SHUTTER_SPEED)) return null; |
// float apexValue = _directory.getFloat(ExifDirectory.TAG_SHUTTER_SPEED); |
// int apexPower = (int)Math.pow(2.0, apexValue); |
// return "1/" + apexPower + " sec"; |
// TODO test this method |
// thanks to Mark Edwards for spotting and patching a bug in the calculation of this |
// description (spotted bug using a Canon EOS 300D) |
// thanks also to Gli Blr for spotting this bug |
float apexValue = _directory.getFloat(ExifDirectory.TAG_SHUTTER_SPEED); |
if (apexValue<=1) { |
float apexPower = (float)(1/(Math.exp(apexValue*Math.log(2)))); |
long apexPower10 = Math.round((double)apexPower * 10.0); |
float fApexPower = (float) apexPower10 / 10.0f; |
return fApexPower + " sec"; |
} else { |
int apexPower = (int)((Math.exp(apexValue*Math.log(2)))); |
return "1/" + apexPower + " sec"; |
} |
/* |
// This alternative implementation offered by Bill Richards |
// TODO determine which is the correct / more-correct implementation |
double apexValue = _directory.getDouble(ExifDirectory.TAG_SHUTTER_SPEED); |
double apexPower = Math.pow(2.0, apexValue); |
StringBuffer sb = new StringBuffer(); |
if (apexPower > 1) |
apexPower = Math.floor(apexPower); |
if (apexPower < 1) { |
sb.append((int)Math.round(1/apexPower)); |
} else { |
sb.append("1/"); |
sb.append((int)apexPower); |
} |
sb.append(" sec"); |
return sb.toString(); |
*/ |
} |
public String getFNumberDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_FNUMBER)) return null; |
Rational fNumber = _directory.getRational(ExifDirectory.TAG_FNUMBER); |
return "F" + SimpleDecimalFormatter.format(fNumber.doubleValue()); |
} |
public String getYCbCrPositioningDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_YCBCR_POSITIONING)) return null; |
int yCbCrPosition = _directory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING); |
switch (yCbCrPosition) { |
case 1: return "Center of pixel array"; |
case 2: return "Datum point"; |
default: |
return String.valueOf(yCbCrPosition); |
} |
} |
public String getOrientationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_ORIENTATION)) return null; |
int orientation = _directory.getInt(ExifDirectory.TAG_ORIENTATION); |
switch (orientation) { |
case 1: return "Top, left side (Horizontal / normal)"; |
case 2: return "Top, right side (Mirror horizontal)"; |
case 3: return "Bottom, right side (Rotate 180)"; |
case 4: return "Bottom, left side (Mirror vertical)"; |
case 5: return "Left side, top (Mirror horizontal and rotate 270 CW)"; |
case 6: return "Right side, top (Rotate 90 CW)"; |
case 7: return "Right side, bottom (Mirror horizontal and rotate 90 CW)"; |
case 8: return "Left side, bottom (Rotate 270 CW)"; |
default: |
return String.valueOf(orientation); |
} |
} |
public String getResolutionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_RESOLUTION_UNIT)) return ""; |
// '1' means no-unit, '2' means inch, '3' means centimeter. Default value is '2'(inch) |
int resolutionUnit = _directory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT); |
switch (resolutionUnit) { |
case 1: return "(No unit)"; |
case 2: return "Inch"; |
case 3: return "cm"; |
default: |
return ""; |
} |
} |
public String getSensingMethodDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifDirectory.TAG_SENSING_METHOD)) return null; |
// '1' Not defined, '2' One-chip color area sensor, '3' Two-chip color area sensor |
// '4' Three-chip color area sensor, '5' Color sequential area sensor |
// '7' Trilinear sensor '8' Color sequential linear sensor, 'Other' reserved |
int sensingMethod = _directory.getInt(ExifDirectory.TAG_SENSING_METHOD); |
switch (sensingMethod) { |
case 1: |
return "(Not defined)"; |
case 2: |
return "One-chip color area sensor"; |
case 3: |
return "Two-chip color area sensor"; |
case 4: |
return "Three-chip color area sensor"; |
case 5: |
return "Color sequential area sensor"; |
case 7: |
return "Trilinear sensor"; |
case 8: |
return "Color sequential linear sensor"; |
default: |
return ""; |
} |
} |
public String getComponentConfigurationDescription() throws MetadataException |
{ |
int[] components = _directory.getIntArray(ExifDirectory.TAG_COMPONENTS_CONFIGURATION); |
String[] componentStrings = {"", "Y", "Cb", "Cr", "R", "G", "B"}; |
StringBuffer componentConfig = new StringBuffer(); |
for (int i = 0; i < Math.min(4, components.length); i++) { |
int j = components[i]; |
if (j > 0 && j < componentStrings.length) { |
componentConfig.append(componentStrings[j]); |
} |
} |
return componentConfig.toString(); |
} |
/** |
* Takes a series of 4 bytes from the specified offset, and converts these to a |
* well-known version number, where possible. For example, (hex) 30 32 31 30 == 2.10). |
* @param components the four version values |
* @return the version as a string of form 2.10 |
*/ |
public static String convertBytesToVersionString(int[] components) |
{ |
StringBuffer version = new StringBuffer(); |
for (int i = 0; i < 4 && i < components.length; i++) { |
if (i == 2) version.append('.'); |
String digit = String.valueOf((char)components[i]); |
if (i == 0 && "0".equals(digit)) continue; |
version.append(digit); |
} |
return version.toString(); |
} |
/** |
* The Windows specific tags uses plain Unicode |
*/ |
private String getUnicodeDescription(int tag) throws MetadataException |
{ |
if (!_directory.containsTag(tag)) return null; |
byte[] commentBytes = _directory.getByteArray(tag); |
try { |
// decode the unicode string |
// trim it, as i'm seeing a junk character on the end |
return new String(commentBytes, "UTF-16LE").trim(); |
} |
catch (UnsupportedEncodingException ex) { |
return null; |
} |
} |
public String getWindowsAuthorDescription() throws MetadataException |
{ |
return getUnicodeDescription(ExifDirectory.TAG_WIN_AUTHOR); |
} |
public String getWindowsCommentDescription() throws MetadataException |
{ |
return getUnicodeDescription(ExifDirectory.TAG_WIN_COMMENT); |
} |
public String getWindowsKeywordsDescription() throws MetadataException |
{ |
return getUnicodeDescription(ExifDirectory.TAG_WIN_KEYWORDS); |
} |
public String getWindowsTitleDescription() throws MetadataException |
{ |
return getUnicodeDescription(ExifDirectory.TAG_WIN_TITLE); |
} |
public String getWindowsSubjectDescription() throws MetadataException |
{ |
return getUnicodeDescription(ExifDirectory.TAG_WIN_SUBJECT); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/SonyMakernoteDescriptor.java |
---|
0,0 → 1,36 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a SonyMakernoteDirectory. |
* Thanks to David Carson for the initial version of this class. |
*/ |
public class SonyMakernoteDescriptor extends TagDescriptor |
{ |
public SonyMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
return _directory.getString(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType2MakernoteDirectory.java |
---|
0,0 → 1,544 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 3-Oct-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import java.util.HashMap; |
/** |
* Contains values specific to Nikon cameras. Type-2 applies to the E990 and D-series cameras such as the E990, D1, |
* D70 and D100. |
* |
* Thanks to Fabrizio Giudici for publishing his reverse-engineering of the D100 makernote data. |
* http://www.timelesswanderings.net/equipment/D100/NEF.html |
* |
* Note that the camera implements image protection (locking images) via the file's 'readonly' attribute. Similarly |
* image hiding uses the 'hidden' attribute (observed on the D70). Consequently, these values are not available here. |
* |
* Additional sample images have been observed, and their tag values recorded in javadoc comments for each tag's field. |
* New tags have subsequently been added since Fabrizio's observations. |
* |
* In earlier models (such as the E990 and D1), this directory begins at the first byte of the makernote IFD. In |
* later models, the IFD was given the standard prefix to indicate the camera models (most other manufacturers also |
* provide this prefix to aid in software decoding). |
*/ |
public class NikonType2MakernoteDirectory extends Directory |
{ |
/** |
* Values observed |
* - 0200 (D70) |
* - 0200 (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_FIRMWARE_VERSION = 0x0001; |
/** |
* Values observed |
* - 0 250 |
* - 0 400 |
*/ |
public static final int TAG_NIKON_TYPE2_ISO_1 = 0x0002; |
/** |
* Values observed |
* - COLOR (seen in the D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_COLOR_MODE = 0x0003; |
/** |
* Values observed |
* - FILE |
* - RAW |
* - NORMAL |
* - FINE |
*/ |
public static final int TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT = 0x0004; |
/** |
* The white balance as set in the camera. |
* |
* Values observed |
* - AUTO |
* - SUNNY (D70) |
* - FLASH (D1X) |
* (presumably also SHADOW / INCANDESCENT / FLUORESCENT / CLOUDY) |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE = 0x0005; |
/** |
* The sharpening as set in the camera. |
* |
* Values observed |
* - AUTO |
* - NORMAL (D70) |
* - NONE (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_SHARPENING = 0x0006; |
/** |
* The auto-focus type used by the camera. |
* |
* Values observed |
* - AF-S |
* - AF-C |
* - MANUAL |
*/ |
public static final int TAG_NIKON_TYPE2_AF_TYPE = 0x0007; |
/** |
* Values observed |
* - NORMAL |
* - RED-EYE |
* |
* Note: when TAG_NIKON_TYPE2_AUTO_FLASH_MODE is blank, Nikon Browser displays "Flash Sync Mode: Not Attached" |
*/ |
public static final int TAG_NIKON_TYPE2_FLASH_SYNC_MODE = 0x0008; |
/** |
* Values observed |
* - Built-in,TTL |
* - Optional,TTL (with speedlight SB800, flash sync mode as NORMAL. NikonBrowser reports Auto Flash Comp: 0 EV -- which tag is that?) (D70) |
* - NEW_TTL (Nikon Browser interprets as "D-TTL") |
* - (blank -- accompanied FlashSyncMode of NORMAL) (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_AUTO_FLASH_MODE = 0x0009; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_34 = 0x000A; |
/** |
* Values observed |
* - 0 |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE = 0x000B; |
/** |
* The first two numbers are coefficients to multiply red and blue channels according to white balance as set in the |
* camera. The meaning of the third and the fourth numbers is unknown. |
* |
* Values observed |
* - 2.25882352 1.76078431 0.0 0.0 |
* - 10242/1 34305/1 0/1 0/1 |
* - 234765625/100000000 1140625/1000000 1/1 1/1 |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF = 0x000C; |
/** |
* Values observed |
* - 0,1,6,0 (hex) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_1 = 0x000D; |
/** |
* Values observed |
* - î |
* - 0,1,c,0 (hex) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_2 = 0x000E; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_ISO_SELECTION = 0x000F; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_DATA_DUMP = 0x0010; |
/** |
* Values observed |
* - 914 |
* - 1379 (D70) |
* - 2781 (D1X) |
* - 6942 (D100) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_3 = 0x0011; |
/** |
* Values observed |
* - (no value -- blank) |
*/ |
public static final int TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION = 0x0012; |
/** |
* Values observed |
* - 0 250 |
* - 0 400 |
*/ |
public static final int TAG_NIKON_TYPE2_ISO_2 = 0x0013; |
/** |
* Values observed |
* - 0 0 49163 53255 |
* - 0 0 3008 2000 (the image dimensions were 3008x2000) (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_21 = 0x0016; |
/** |
* Values observed |
* - (blank) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_22 = 0x0017; |
/** |
* Values observed |
* - (blank) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_23 = 0x0018; |
/** |
* Values observed |
* - 0 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_24 = 0x0019; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT = 0x0080; |
/** |
* The tone compensation as set in the camera. |
* |
* Values observed |
* - AUTO |
* - NORMAL (D1X, D100) |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION = 0x0081; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_ADAPTER = 0x0082; |
/** |
* Values observed |
* - 6 |
* - 6 (D70) |
* - 2 (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_4 = 0x0083; |
/** |
* A pair of focal/max-fstop values that describe the lens used. |
* |
* Values observed |
* - 180.0,180.0,2.8,2.8 (D100) |
* - 240/10 850/10 35/10 45/10 |
* - 18-70mm f/3.5-4.5 (D70) |
* - 17-35mm f/2.8-2.8 (D1X) |
* - 70-200mm f/2.8-2.8 (D70) |
* |
* Nikon Browser identifies the lens as "18-70mm F/3.5-4.5 G" which |
* is identical to metadata extractor, except for the "G". This must |
* be coming from another tag... |
*/ |
public static final int TAG_NIKON_TYPE2_LENS = 0x0084; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE = 0x0085; |
/** |
* Added during merge of Type2 & Type3. May apply to earlier models, such as E990 and D1. |
*/ |
public static final int TAG_NIKON_TYPE2_DIGITAL_ZOOM = 0x0086; |
/** |
* Values observed |
* - 0 |
* - 9 |
* - 3 (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_5 = 0x0087; |
/** |
* Values observed |
* - |
*/ |
public static final int TAG_NIKON_TYPE2_AF_FOCUS_POSITION = 0x0088; |
/** |
* Values observed |
* - 0 |
* - 1 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_7 = 0x0089; |
/** |
* Values observed |
* - 0 |
* - 0 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_20 = 0x008A; |
/** |
* Values observed |
* - 48,1,c,0 (hex) (D100) |
* - @ |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_8 = 0x008B; |
/** |
* Unknown. Fabrizio believes this may be a lookup table for the user-defined curve. |
* |
* Values observed |
* - (blank) (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_9 = 0x008C; |
/** |
* The color space as set in the camera. |
* |
* Values observed |
* - MODE1 |
* - Mode I (sRGB) (D70) |
* - MODE2 (D1X, D100) |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_COLOR_MODE = 0x008D; |
/** |
* Values observed |
* - NATURAL |
* - SPEEDLIGHT (D70, D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_LIGHT_SOURCE = 0x0090; |
/** |
* Values observed |
* - 0100) |
* - 0103 (D70) |
* - 0100 (D1X) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_11 = 0x0091; |
/** |
* The hue adjustment as set in the camera. |
* |
* Values observed |
* - 0 |
*/ |
public static final int TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT = 0x0092; |
/** |
* Values observed |
* - OFF |
*/ |
public static final int TAG_NIKON_TYPE2_NOISE_REDUCTION = 0x0095; |
/** |
* Values observed |
* - 0100'~e3 |
* - 0103 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_12 = 0x0097; |
/** |
* Values observed |
* - 0100fht@7b,4x,D"Y |
* - 01015 |
* - 0100w\cH+D$$h$î5Q (D1X) |
* - 30,31,30,30,0,0,b,48,7c,7c,24,24,5,15,24,0,0,0,0,0 (hex) (D100) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_13 = 0x0098; |
/** |
* Values observed |
* - 2014 662 (D1X) |
* - 1517,1012 (D100) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_14 = 0x0099; |
/** |
* Values observed |
* - 78/10 78/10 |
* - 78/10 78/10 (D70) |
* - 59/10 59/5 (D1X) |
* - 7.8,7.8 (D100) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_15 = 0x009A; |
/** |
* Values observed |
* - NO= 00002539 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_25 = 0x00A0; |
/** |
* Values observed |
* - 1564851 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_26 = 0x00A2; |
/** |
* Values observed |
* - 0 |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_27 = 0x00A3; |
/** |
* This appears to be a sequence number to indentify the exposure. This value seems to increment |
* for consecutive exposures (observed on D70). |
* |
* Values observed |
* - 5062 |
*/ |
public static final int TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER = 0x00A7; |
/** |
* Values observed |
* - 0100 (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_32 = 0x00A8; |
/** |
* Values observed |
* - NORMAL (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_33 = 0x00A9; |
/** |
* Nikon Browser suggests this value represents Saturation... |
* Values observed |
* - NORMAL (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_29 = 0x00AA; |
/** |
* Values observed |
* - AUTO (D70) |
* - (blank) (D70) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_30 = 0x00AB; |
/** |
* Data about changes set by Nikon Capture Editor. |
* |
* Values observed |
*/ |
public static final int TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA = 0x0E01; |
/** |
* Values observed |
* - 1473 |
* - 7036 (D100) |
*/ |
public static final int TAG_NIKON_TYPE2_UNKNOWN_16 = 0x0E10; |
protected static final HashMap _tagNameMap = new HashMap(); |
static |
{ |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FIRMWARE_VERSION), "Firmware Version"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_1), "ISO"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT), "Quality & File Format"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE), "White Balance"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_SHARPENING), "Sharpening"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_TYPE), "AF Type"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE), "White Balance Fine"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_RB_COEFF), "White Balance RB Coefficients"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_2), "ISO"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ISO_SELECTION), "ISO Selection"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DATA_DUMP), "Data Dump"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT), "Image Adjustment"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION), "Tone Compensation"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_ADAPTER), "Adapter"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LENS), "Lens"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE), "Manual Focus Distance"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_DIGITAL_ZOOM), "Digital Zoom"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_COLOR_MODE), "Colour Mode"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT), "Camera Hue Adjustment"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_NOISE_REDUCTION), "Noise Reduction"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_CAPTURE_EDITOR_DATA), "Capture Editor Data"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_1), "Unknown 01"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_2), "Unknown 02"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_3), "Unknown 03"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_4), "Unknown 04"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_5), "Unknown 05"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AF_FOCUS_POSITION), "AF Focus Position"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_7), "Unknown 07"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_8), "Unknown 08"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_9), "Unknown 09"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_LIGHT_SOURCE), "Light source"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_11), "Unknown 11"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_12), "Unknown 12"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_13), "Unknown 13"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_14), "Unknown 14"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_15), "Unknown 15"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_16), "Unknown 16"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_FLASH_SYNC_MODE), "Flash Sync Mode"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_MODE), "Auto Flash Mode"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION), "Auto Flash Compensation"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_EXPOSURE_SEQUENCE_NUMBER), "Exposure Sequence Number"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_COLOR_MODE), "Color Mode"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_20), "Unknown 20"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_21), "Unknown 21"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_22), "Unknown 22"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_23), "Unknown 23"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_24), "Unknown 24"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_25), "Unknown 25"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_26), "Unknown 26"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_27), "Unknown 27"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_29), "Unknown 29"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_30), "Unknown 30"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_32), "Unknown 32"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE2_UNKNOWN_33), "Unknown 33"); |
} |
public NikonType2MakernoteDirectory() |
{ |
this.setDescriptor(new NikonType2MakernoteDescriptor(this)); |
} |
public Rational getAutoFlashCompensation() throws MetadataException |
{ |
if (!containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION)) |
return null; |
byte[] bytes = getByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION); |
return CalculateFlashCompensationFromBytes(bytes); |
} |
public static Rational CalculateFlashCompensationFromBytes(byte[] bytes) |
{ |
if (bytes.length==3) |
{ |
byte denominator = bytes[2]; |
int numerator = (int)bytes[0] * bytes[1]; |
return new Rational(numerator, denominator); |
} |
return null; |
} |
public String getName() |
{ |
return "Nikon Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KodakMakernoteDescriptor.java |
---|
0,0 → 1,36 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a KodakMakernoteDirectory. |
* Thanks to David Carson for the initial version of this class. |
*/ |
public class KodakMakernoteDescriptor extends TagDescriptor |
{ |
public KodakMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
return _directory.getString(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CanonMakernoteDescriptor.java |
---|
0,0 → 1,716 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class CanonMakernoteDescriptor extends TagDescriptor |
{ |
public CanonMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY: |
return getFlashActivityDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE: |
return getFocusTypeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM: |
return getDigitalZoomDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY: |
return getQualityDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE: |
return getMacroModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY: |
return getSelfTimerDelayDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE: |
return getFlashModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE: |
return getContinuousDriveModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1: |
return getFocusMode1Description(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE: |
return getImageSizeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE: |
return getEasyShootingModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST: |
return getContrastDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION: |
return getSaturationDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS: |
return getSharpnessDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_ISO: |
return getIsoDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE: |
return getMeteringModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED: |
return getAfPointSelectedDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE: |
return getExposureModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH: |
return getLongFocalLengthDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH: |
return getShortFocalLengthDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM: |
return getFocalUnitsPerMillimetreDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS: |
return getFlashDetailsDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2: |
return getFocusMode2Description(); |
case CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED: |
return getAfPointUsedDescription(); |
case CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS: |
return getFlashBiasDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION: |
return getLongExposureNoiseReductionDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS: |
return getShutterAutoExposureLockButtonDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP: |
return getMirrorLockupDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL: |
return getTvAndAvExposureLevelDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT: |
return getAutoFocusAssistLightDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE: |
return getShutterSpeedInAvModeDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING: |
return getAutoExposureBrackettingSequenceAndAutoCancellationDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC: |
return getShutterCurtainSyncDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP: |
return getLensAutoFocusStopButtonDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION: |
return getFillFlashReductionDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN: |
return getMenuButtonReturnPositionDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION: |
return getSetButtonFunctionWhenShootingDescription(); |
case CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING: |
return getSensorCleaningDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getLongExposureNoiseReductionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION); |
switch (value) { |
case 0: return "Off"; |
case 1: return "On"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getShutterAutoExposureLockButtonDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS); |
switch (value) { |
case 0: return "AF/AE lock"; |
case 1: return "AE lock/AF"; |
case 2: return "AF/AF lock"; |
case 3: return "AE+release/AE+AF"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getMirrorLockupDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP); |
switch (value) { |
case 0: return "Disabled"; |
case 1: return "Enabled"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getTvAndAvExposureLevelDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL); |
switch (value) { |
case 0: return "1/2 stop"; |
case 1: return "1/3 stop"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getAutoFocusAssistLightDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT); |
switch (value) { |
case 0: return "On (Auto)"; |
case 1: return "Off"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getShutterSpeedInAvModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE); |
switch (value) { |
case 0: return "Automatic"; |
case 1: return "1/200 (fixed)"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getAutoExposureBrackettingSequenceAndAutoCancellationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_BRACKETTING); |
switch (value) { |
case 0: return "0,-,+ / Enabled"; |
case 1: return "0,-,+ / Disabled"; |
case 2: return "-,0,+ / Enabled"; |
case 3: return "-,0,+ / Disabled"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getShutterCurtainSyncDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC); |
switch (value) { |
case 0: return "1st Curtain Sync"; |
case 1: return "2nd Curtain Sync"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getLensAutoFocusStopButtonDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_AF_STOP); |
switch (value) { |
case 0: return "AF stop"; |
case 1: return "Operate AF"; |
case 2: return "Lock AE and start timer"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getFillFlashReductionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION); |
switch (value) { |
case 0: return "Enabled"; |
case 1: return "Disabled"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getMenuButtonReturnPositionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN); |
switch (value) { |
case 0: return "Top"; |
case 1: return "Previous (volatile)"; |
case 2: return "Previous"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getSetButtonFunctionWhenShootingDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION); |
switch (value) { |
case 0: return "Not Assigned"; |
case 1: return "Change Quality"; |
case 2: return "Change ISO Speed"; |
case 3: return "Select Parameters"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getSensorCleaningDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING); |
switch (value) { |
case 0: return "Disabled"; |
case 1: return "Enabled"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getFlashBiasDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS); |
boolean isNegative = false; |
if (value > 0xF000) |
{ |
isNegative = true; |
value = 0xFFFF - value; |
value++; |
} |
// this tag is interesting in that the values returned are: |
// 0, 0.375, 0.5, 0.626, 1 |
// not |
// 0, 0.33, 0.5, 0.66, 1 |
return ((isNegative) ? "-" : "") + Float.toString(value / 32f) + " EV"; |
} |
public String getAfPointUsedDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_AF_POINT_USED); |
if ((value & 0x7) == 0) { |
return "Right"; |
} else if ((value & 0x7) == 1) { |
return "Centre"; |
} else if ((value & 0x7) == 2) { |
return "Left"; |
} else { |
return "Unknown (" + value + ")"; |
} |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE2_WHITE_BALANCE); |
switch (value) { |
case 0: |
return "Auto"; |
case 1: |
return "Sunny"; |
case 2: |
return "Cloudy"; |
case 3: |
return "Tungsten"; |
case 4: |
return "Flourescent"; |
case 5: |
return "Flash"; |
case 6: |
return "Custom"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusMode2Description() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_2); |
switch (value) { |
case 0: |
return "Single"; |
case 1: |
return "Continuous"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashDetailsDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_DETAILS); |
if (((value << 14) & 1) > 0) { |
return "External E-TTL"; |
} |
if (((value << 13) & 1) > 0) { |
return "Internal flash"; |
} |
if (((value << 11) & 1) > 0) { |
return "FP sync used"; |
} |
if (((value << 4) & 1) > 0) { |
return "FP sync enabled"; |
} |
return "Unknown (" + value + ")"; |
} |
public String getFocalUnitsPerMillimetreDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM)) return ""; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCAL_UNITS_PER_MM); |
if (value != 0) { |
return Integer.toString(value); |
} else { |
return ""; |
} |
} |
public String getShortFocalLengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHORT_FOCAL_LENGTH); |
String units = getFocalUnitsPerMillimetreDescription(); |
return Integer.toString(value) + " " + units; |
} |
public String getLongFocalLengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_LONG_FOCAL_LENGTH); |
String units = getFocalUnitsPerMillimetreDescription(); |
return Integer.toString(value) + " " + units; |
} |
public String getExposureModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EXPOSURE_MODE); |
switch (value) { |
case 0: |
return "Easy shooting"; |
case 1: |
return "Program"; |
case 2: |
return "Tv-priority"; |
case 3: |
return "Av-priority"; |
case 4: |
return "Manual"; |
case 5: |
return "A-DEP"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getAfPointSelectedDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_AF_POINT_SELECTED); |
switch (value) { |
case 0x3000: |
return "None (MF)"; |
case 0x3001: |
return "Auto selected"; |
case 0x3002: |
return "Right"; |
case 0x3003: |
return "Centre"; |
case 0x3004: |
return "Left"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getMeteringModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_METERING_MODE); |
switch (value) { |
case 3: |
return "Evaluative"; |
case 4: |
return "Partial"; |
case 5: |
return "Centre weighted"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getIsoDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_ISO); |
switch (value) { |
case 0: |
return "Not specified (see ISOSpeedRatings tag)"; |
case 15: |
return "Auto"; |
case 16: |
return "50"; |
case 17: |
return "100"; |
case 18: |
return "200"; |
case 19: |
return "400"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SHARPNESS); |
switch (value) { |
case 0xFFFF: |
return "Low"; |
case 0x000: |
return "Normal"; |
case 0x001: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSaturationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SATURATION); |
switch (value) { |
case 0xFFFF: |
return "Low"; |
case 0x000: |
return "Normal"; |
case 0x001: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getContrastDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTRAST); |
switch (value) { |
case 0xFFFF: |
return "Low"; |
case 0x000: |
return "Normal"; |
case 0x001: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getEasyShootingModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_EASY_SHOOTING_MODE); |
switch (value) { |
case 0: |
return "Full auto"; |
case 1: |
return "Manual"; |
case 2: |
return "Landscape"; |
case 3: |
return "Fast shutter"; |
case 4: |
return "Slow shutter"; |
case 5: |
return "Night"; |
case 6: |
return "B&W"; |
case 7: |
return "Sepia"; |
case 8: |
return "Portrait"; |
case 9: |
return "Sports"; |
case 10: |
return "Macro / Closeup"; |
case 11: |
return "Pan focus"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getImageSizeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_IMAGE_SIZE); |
switch (value) { |
case 0: |
return "Large"; |
case 1: |
return "Medium"; |
case 2: |
return "Small"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusMode1Description() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_MODE_1); |
switch (value) { |
case 0: |
return "One-shot"; |
case 1: |
return "AI Servo"; |
case 2: |
return "AI Focus"; |
case 3: |
return "Manual Focus"; |
case 4: |
// TODO should check field 32 here (FOCUS_MODE_2) |
return "Single"; |
case 5: |
return "Continuous"; |
case 6: |
return "Manual Focus"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getContinuousDriveModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE); |
switch (value) { |
case 0: |
if (_directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY) == 0) { |
return "Single shot"; |
} else { |
return "Single shot with self-timer"; |
} |
case 1: |
return "Continuous"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_MODE); |
switch (value) { |
case 0: |
return "No flash fired"; |
case 1: |
return "Auto"; |
case 2: |
return "On"; |
case 3: |
return "Red-eye reduction"; |
case 4: |
return "Slow-synchro"; |
case 5: |
return "Auto and red-eye reduction"; |
case 6: |
return "On and red-eye reduction"; |
case 16: |
// note: this value not set on Canon D30 |
return "Extenal flash"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSelfTimerDelayDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_SELF_TIMER_DELAY); |
if (value == 0) { |
return "Self timer not used"; |
} else { |
// TODO find an image that tests this calculation |
return Double.toString((double)value * 0.1d) + " sec"; |
} |
} |
public String getMacroModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_MACRO_MODE); |
switch (value) { |
case 1: |
return "Macro"; |
case 2: |
return "Normal"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getQualityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_QUALITY); |
switch (value) { |
case 2: |
return "Normal"; |
case 3: |
return "Fine"; |
case 5: |
return "Superfine"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getDigitalZoomDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_DIGITAL_ZOOM); |
switch (value) { |
case 0: |
return "No digital zoom"; |
case 1: |
return "2x"; |
case 2: |
return "4x"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusTypeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FOCUS_TYPE); |
switch (value) { |
case 0: |
return "Manual"; |
case 1: |
return "Auto"; |
case 3: |
return "Close-up (Macro)"; |
case 8: |
return "Locked (Pan Mode)"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashActivityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY)) return null; |
int value = _directory.getInt(CanonMakernoteDirectory.TAG_CANON_STATE1_FLASH_ACTIVITY); |
switch (value) { |
case 0: |
return "Flash did not fire"; |
case 1: |
return "Flash fired"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PentaxMakernoteDescriptor.java |
---|
0,0 → 1,248 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in PentaxMakernoteDirectory. |
* |
* Some information about this makernote taken from here: |
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pentax_mn.html |
*/ |
public class PentaxMakernoteDescriptor extends TagDescriptor |
{ |
public PentaxMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) |
{ |
case PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE: |
return getCaptureModeDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL: |
return getQualityLevelDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE: |
return getFocusModeDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE: |
return getFlashModeDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM: |
return getDigitalZoomDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS: |
return getSharpnessDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST: |
return getContrastDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_SATURATION: |
return getSaturationDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED: |
return getIsoSpeedDescription(); |
case PentaxMakernoteDirectory.TAG_PENTAX_COLOUR: |
return getColourDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getColourDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_COLOUR); |
switch (value) |
{ |
case 1: return "Normal"; |
case 2: return "Black & White"; |
case 3: return "Sepia"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getIsoSpeedDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_ISO_SPEED); |
switch (value) |
{ |
// TODO there must be other values which aren't catered for here |
case 10: return "ISO 100"; |
case 16: return "ISO 200"; |
case 100: return "ISO 100"; |
case 200: return "ISO 200"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getSaturationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SATURATION); |
switch (value) |
{ |
case 0: return "Normal"; |
case 1: return "Low"; |
case 2: return "High"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getContrastDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CONTRAST); |
switch (value) |
{ |
case 0: return "Normal"; |
case 1: return "Low"; |
case 2: return "High"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_SHARPNESS); |
switch (value) |
{ |
case 0: return "Normal"; |
case 1: return "Soft"; |
case 2: return "Hard"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getDigitalZoomDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM)) return null; |
float value = _directory.getFloat(PentaxMakernoteDirectory.TAG_PENTAX_DIGITAL_ZOOM); |
if (value==0) |
return "Off"; |
return Float.toString(value); |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_WHITE_BALANCE); |
switch (value) |
{ |
case 0: return "Auto"; |
case 1: return "Daylight"; |
case 2: return "Shade"; |
case 3: return "Tungsten"; |
case 4: return "Fluorescent"; |
case 5: return "Manual"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getFlashModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FLASH_MODE); |
switch (value) |
{ |
case 1: return "Auto"; |
case 2: return "Flash On"; |
case 4: return "Flash Off"; |
case 6: return "Red-eye Reduction"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getFocusModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_FOCUS_MODE); |
switch (value) |
{ |
case 2: return "Custom"; |
case 3: return "Auto"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getQualityLevelDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_QUALITY_LEVEL); |
switch (value) |
{ |
case 0: return "Good"; |
case 1: return "Better"; |
case 2: return "Best"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getCaptureModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PENTAX_CAPTURE_MODE); |
switch (value) |
{ |
case 1: return "Auto"; |
case 2: return "Night-scene"; |
case 3: return "Manual"; |
case 4: return "Multiple"; |
default: return "Unknown (" + value + ")"; |
} |
} |
/* |
public String getPrintImageMatchingInfoDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO)) return null; |
byte[] bytes = _directory.getByteArray(PentaxMakernoteDirectory.TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO); |
return "(" + bytes.length + " bytes)"; |
} |
public String getMacroModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_MACRO_MODE); |
switch (value) { |
case 1: |
return "On"; |
case 2: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getRecordModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE)) return null; |
int value = _directory.getInt(PentaxMakernoteDirectory.TAG_PANASONIC_RECORD_MODE); |
switch (value) { |
case 1: |
return "Normal"; |
case 2: |
return "Portrait"; |
case 9: |
return "Macro"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
*/ |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType1MakernoteDirectory.java |
---|
0,0 → 1,90 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* A standard TIFF IFD directory but always uses Motorola (Big-Endian) Byte Alignment. |
* Makernote data begins immediately (no header). |
*/ |
public class CasioType1MakernoteDirectory extends Directory |
{ |
public static final int TAG_CASIO_RECORDING_MODE = 0x0001; |
public static final int TAG_CASIO_QUALITY = 0x0002; |
public static final int TAG_CASIO_FOCUSING_MODE = 0x0003; |
public static final int TAG_CASIO_FLASH_MODE = 0x0004; |
public static final int TAG_CASIO_FLASH_INTENSITY = 0x0005; |
public static final int TAG_CASIO_OBJECT_DISTANCE = 0x0006; |
public static final int TAG_CASIO_WHITE_BALANCE = 0x0007; |
public static final int TAG_CASIO_UNKNOWN_1 = 0x0008; |
public static final int TAG_CASIO_UNKNOWN_2 = 0x0009; |
public static final int TAG_CASIO_DIGITAL_ZOOM = 0x000A; |
public static final int TAG_CASIO_SHARPNESS = 0x000B; |
public static final int TAG_CASIO_CONTRAST = 0x000C; |
public static final int TAG_CASIO_SATURATION = 0x000D; |
public static final int TAG_CASIO_UNKNOWN_3 = 0x000E; |
public static final int TAG_CASIO_UNKNOWN_4 = 0x000F; |
public static final int TAG_CASIO_UNKNOWN_5 = 0x0010; |
public static final int TAG_CASIO_UNKNOWN_6 = 0x0011; |
public static final int TAG_CASIO_UNKNOWN_7 = 0x0012; |
public static final int TAG_CASIO_UNKNOWN_8 = 0x0013; |
public static final int TAG_CASIO_CCD_SENSITIVITY = 0x0014; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_CASIO_CCD_SENSITIVITY), "CCD Sensitivity"); |
tagNameMap.put(new Integer(TAG_CASIO_CONTRAST), "Contrast"); |
tagNameMap.put(new Integer(TAG_CASIO_DIGITAL_ZOOM), "Digital Zoom"); |
tagNameMap.put(new Integer(TAG_CASIO_FLASH_INTENSITY), "Flash Intensity"); |
tagNameMap.put(new Integer(TAG_CASIO_FLASH_MODE), "Flash Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_FOCUSING_MODE), "Focussing Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_OBJECT_DISTANCE), "Object Distance"); |
tagNameMap.put(new Integer(TAG_CASIO_QUALITY), "Quality"); |
tagNameMap.put(new Integer(TAG_CASIO_RECORDING_MODE), "Recording Mode"); |
tagNameMap.put(new Integer(TAG_CASIO_SATURATION), "Saturation"); |
tagNameMap.put(new Integer(TAG_CASIO_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_1), "Makernote Unknown 1"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_2), "Makernote Unknown 2"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_3), "Makernote Unknown 3"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_4), "Makernote Unknown 4"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_5), "Makernote Unknown 5"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_6), "Makernote Unknown 6"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_7), "Makernote Unknown 7"); |
tagNameMap.put(new Integer(TAG_CASIO_UNKNOWN_8), "Makernote Unknown 8"); |
tagNameMap.put(new Integer(TAG_CASIO_WHITE_BALANCE), "White Balance"); |
} |
public CasioType1MakernoteDirectory() |
{ |
this.setDescriptor(new CasioType1MakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Casio Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/OlympusMakernoteDescriptor.java |
---|
0,0 → 1,148 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in an OlympusMakernoteDirectory. |
*/ |
public class OlympusMakernoteDescriptor extends TagDescriptor |
{ |
public OlympusMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE: |
return getSpecialModeDescription(); |
case OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY: |
return getJpegQualityDescription(); |
case OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE: |
return getMacroModeDescription(); |
case OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO: |
return getDigiZoomRatioDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getDigiZoomRatioDescription() throws MetadataException |
{ |
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO)) return null; |
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_DIGI_ZOOM_RATIO); |
switch (value) { |
case 0: |
return "Normal"; |
case 2: |
return "Digital 2x Zoom"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getMacroModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE)) return null; |
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_MACRO_MODE); |
switch (value) { |
case 0: |
return "Normal (no macro)"; |
case 1: |
return "Macro"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getJpegQualityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY)) return null; |
int value = _directory.getInt(OlympusMakernoteDirectory.TAG_OLYMPUS_JPEG_QUALITY); |
switch (value) { |
case 1: |
return "SQ"; |
case 2: |
return "HQ"; |
case 3: |
return "SHQ"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSpecialModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE)) return null; |
int[] values = _directory.getIntArray(OlympusMakernoteDirectory.TAG_OLYMPUS_SPECIAL_MODE); |
StringBuffer desc = new StringBuffer(); |
switch (values[0]) { |
case 0: |
desc.append("Normal picture taking mode"); |
break; |
case 1: |
desc.append("Unknown picture taking mode"); |
break; |
case 2: |
desc.append("Fast picture taking mode"); |
break; |
case 3: |
desc.append("Panorama picture taking mode"); |
break; |
default: |
desc.append("Unknown picture taking mode"); |
break; |
} |
desc.append(" - "); |
switch (values[1]) { |
case 0: |
desc.append("Unknown sequence number"); |
break; |
case 1: |
desc.append("1st in a sequnce"); |
break; |
case 2: |
desc.append("2nd in a sequence"); |
break; |
case 3: |
desc.append("3rd in a sequence"); |
break; |
default: |
desc.append(values[1]); |
desc.append("th in a sequence"); |
break; |
} |
switch (values[2]) { |
case 1: |
desc.append("Left to right panorama direction"); |
break; |
case 2: |
desc.append("Right to left panorama direction"); |
break; |
case 3: |
desc.append("Bottom to top panorama direction"); |
break; |
case 4: |
desc.append("Top to bottom panorama direction"); |
break; |
} |
return desc.toString(); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/DataFormat.java |
---|
0,0 → 1,76 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.MetadataException; |
/** |
* An enumeration of data formats used in the TIFF IFDs. |
*/ |
public class DataFormat |
{ |
public static final DataFormat BYTE = new DataFormat("BYTE", 1); |
public static final DataFormat STRING = new DataFormat("STRING", 2); |
public static final DataFormat USHORT = new DataFormat("USHORT", 3); |
public static final DataFormat ULONG = new DataFormat("ULONG", 4); |
public static final DataFormat URATIONAL = new DataFormat("URATIONAL", 5); |
public static final DataFormat SBYTE = new DataFormat("SBYTE", 6); |
public static final DataFormat UNDEFINED = new DataFormat("UNDEFINED", 7); |
public static final DataFormat SSHORT = new DataFormat("SSHORT", 8); |
public static final DataFormat SLONG = new DataFormat("SLONG", 9); |
public static final DataFormat SRATIONAL = new DataFormat("SRATIONAL", 10); |
public static final DataFormat SINGLE = new DataFormat("SINGLE", 11); |
public static final DataFormat DOUBLE = new DataFormat("DOUBLE", 12); |
private final String myName; |
private final int value; |
public static DataFormat fromValue(int value) throws MetadataException |
{ |
switch (value) |
{ |
case 1: return BYTE; |
case 2: return STRING; |
case 3: return USHORT; |
case 4: return ULONG; |
case 5: return URATIONAL; |
case 6: return SBYTE; |
case 7: return UNDEFINED; |
case 8: return SSHORT; |
case 9: return SLONG; |
case 10: return SRATIONAL; |
case 11: return SINGLE; |
case 12: return DOUBLE; |
} |
throw new MetadataException("value '"+value+"' does not represent a known data format."); |
} |
private DataFormat(String name, int value) |
{ |
myName = name; |
this.value = value; |
} |
public int getValue() |
{ |
return value; |
} |
public String toString() |
{ |
return myName; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/SonyMakernoteDirectory.java |
---|
0,0 → 1,37 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* Describes tags specific to Sony cameras. |
*/ |
public class SonyMakernoteDirectory extends Directory |
{ |
protected static final HashMap _tagNameMap = new HashMap(); |
public String getName() |
{ |
return "Sony Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType1MakernoteDescriptor.java |
---|
0,0 → 1,273 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class CasioType1MakernoteDescriptor extends TagDescriptor |
{ |
public CasioType1MakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE: |
return getRecordingModeDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_QUALITY: |
return getQualityDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE: |
return getFocusingModeDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE: |
return getFlashModeDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY: |
return getFlashIntensityDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE: |
return getObjectDistanceDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM: |
return getDigitalZoomDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS: |
return getSharpnessDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST: |
return getContrastDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_SATURATION: |
return getSaturationDescription(); |
case CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY: |
return getCcdSensitivityDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getCcdSensitivityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CCD_SENSITIVITY); |
switch (value) { |
// these four for QV3000 |
case 64: |
return "Normal"; |
case 125: |
return "+1.0"; |
case 250: |
return "+2.0"; |
case 244: |
return "+3.0"; |
// these two for QV8000/2000 |
case 80: |
return "Normal (ISO 80 equivalent)"; |
case 100: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSaturationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SATURATION); |
switch (value) { |
case 0: |
return "Normal"; |
case 1: |
return "Low"; |
case 2: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getContrastDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_CONTRAST); |
switch (value) { |
case 0: |
return "Normal"; |
case 1: |
return "Low"; |
case 2: |
return "High"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_SHARPNESS); |
switch (value) { |
case 0: |
return "Normal"; |
case 1: |
return "Soft"; |
case 2: |
return "Hard"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getDigitalZoomDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_DIGITAL_ZOOM); |
switch (value) { |
case 0x10000: |
return "No digital zoom"; |
case 0x10001: |
return "2x digital zoom"; |
case 0x20000: |
return "2x digital zoom"; |
case 0x40000: |
return "4x digital zoom"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_WHITE_BALANCE); |
switch (value) { |
case 1: |
return "Auto"; |
case 2: |
return "Tungsten"; |
case 3: |
return "Daylight"; |
case 4: |
return "Flourescent"; |
case 5: |
return "Shade"; |
case 129: |
return "Manual"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getObjectDistanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_OBJECT_DISTANCE); |
return value + " mm"; |
} |
public String getFlashIntensityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_INTENSITY); |
switch (value) { |
case 11: |
return "Weak"; |
case 13: |
return "Normal"; |
case 15: |
return "Strong"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FLASH_MODE); |
switch (value) { |
case 1: |
return "Auto"; |
case 2: |
return "On"; |
case 3: |
return "Off"; |
case 4: |
// this documented as additional value for off here: |
// http://www.ozhiker.com/electronics/pjmt/jpeg_info/casio_mn.html |
return "Red eye reduction"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusingModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_FOCUSING_MODE); |
switch (value) { |
case 2: |
return "Macro"; |
case 3: |
return "Auto focus"; |
case 4: |
return "Manual focus"; |
case 5: |
return "Infinity"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getQualityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_QUALITY); |
switch (value) { |
case 1: |
return "Economy"; |
case 2: |
return "Normal"; |
case 3: |
return "Fine"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getRecordingModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE)) return null; |
int value = _directory.getInt(CasioType1MakernoteDirectory.TAG_CASIO_RECORDING_MODE); |
switch (value) { |
case 1: |
return "Single shutter"; |
case 2: |
return "Panorama"; |
case 3: |
return "Night scene"; |
case 4: |
return "Portrait"; |
case 5: |
return "Landscape"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CasioType2MakernoteDescriptor.java |
---|
0,0 → 1,430 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:12:05 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class CasioType2MakernoteDescriptor extends TagDescriptor |
{ |
public CasioType2MakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS: |
return getThumbnailDimensionsDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE: |
return getThumbnailSizeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET: |
return getThumbnailOffsetDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE: |
return getQualityModeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE: |
return getImageSizeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1: |
return getFocusMode1Description(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY: |
return getIsoSensitivityDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1: |
return getWhiteBalance1Description(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH: |
return getFocalLengthDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION: |
return getSaturationDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST: |
return getContrastDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS: |
return getSharpnessDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO: |
return getPrintImageMatchingInfoDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL: |
return getCasioPreviewThumbnailDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS: |
return getWhiteBalanceBiasDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2: |
return getWhiteBalance2Description(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE: |
return getObjectDistanceDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE: |
return getFlashDistanceDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE: |
return getRecordModeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER: |
return getSelfTimerDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY: |
return getQualityDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2: |
return getFocusMode2Description(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE: |
return getTimeZoneDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE: |
return getBestShotModeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY: |
return getCcdIsoSensitivityDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE: |
return getColourModeDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT: |
return getEnhancementDescription(); |
case CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER: |
return getFilterDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getFilterDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FILTER); |
switch (value) { |
case 0: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getEnhancementDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ENHANCEMENT); |
switch (value) { |
case 0: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getColourModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_COLOUR_MODE); |
switch (value) { |
case 0: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getCcdIsoSensitivityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CCD_ISO_SENSITIVITY); |
switch (value) { |
case 0: |
return "Off"; |
case 1: |
return "On"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getBestShotModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_BESTSHOT_MODE); |
switch (value) { |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getTimeZoneDescription() |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE)) return null; |
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_TIME_ZONE); |
} |
public String getFocusMode2Description() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_2); |
switch (value) { |
case 1: |
return "Fixation"; |
case 6: |
return "Multi-Area Focus"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getQualityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY); |
switch (value) { |
case 3: |
return "Fine"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSelfTimerDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SELF_TIMER); |
switch (value) { |
case 1: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getRecordModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_RECORD_MODE); |
switch (value) { |
case 2: |
return "Normal"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFlashDistanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FLASH_DISTANCE); |
switch (value) { |
case 0: |
return "Off"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getObjectDistanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_OBJECT_DISTANCE); |
return Integer.toString(value) + " mm"; |
} |
public String getWhiteBalance2Description() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_2); |
switch (value) { |
case 0: |
return "Manual"; |
case 1: |
return "Auto"; // unsure about this |
case 4: |
return "Flash"; // unsure about this |
case 12: |
return "Flash"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getWhiteBalanceBiasDescription() |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS)) return null; |
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_BIAS); |
} |
public String getCasioPreviewThumbnailDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL)) return null; |
final byte[] bytes = _directory.getByteArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CASIO_PREVIEW_THUMBNAIL); |
return "<" + bytes.length + " bytes of image data>"; |
} |
public String getPrintImageMatchingInfoDescription() |
{ |
// TODO research PIM specification http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO)) return null; |
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_PRINT_IMAGE_MATCHING_INFO); |
} |
public String getSharpnessDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SHARPNESS); |
switch (value) { |
case 0: |
return "-1"; |
case 1: |
return "Normal"; |
case 2: |
return "+1"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getContrastDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_CONTRAST); |
switch (value) { |
case 0: |
return "-1"; |
case 1: |
return "Normal"; |
case 2: |
return "+1"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getSaturationDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_SATURATION); |
switch (value) { |
case 0: |
return "-1"; |
case 1: |
return "Normal"; |
case 2: |
return "+1"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocalLengthDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH)) return null; |
double value = _directory.getDouble(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCAL_LENGTH); |
return Double.toString(value / 10d) + " mm"; |
} |
public String getWhiteBalance1Description() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_WHITE_BALANCE_1); |
switch (value) { |
case 0: |
return "Auto"; |
case 1: |
return "Daylight"; |
case 2: |
return "Shade"; |
case 3: |
return "Tungsten"; |
case 4: |
return "Flourescent"; |
case 5: |
return "Manual"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getIsoSensitivityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_ISO_SENSITIVITY); |
switch (value) { |
case 3: |
return "50"; |
case 4: |
return "64"; |
case 6: |
return "100"; |
case 9: |
return "200"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getFocusMode1Description() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_FOCUS_MODE_1); |
switch (value) { |
case 0: |
return "Normal"; |
case 1: |
return "Macro"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getImageSizeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_IMAGE_SIZE); |
switch (value) { |
case 0: return "640 x 480 pixels"; |
case 4: return "1600 x 1200 pixels"; |
case 5: return "2048 x 1536 pixels"; |
case 20: return "2288 x 1712 pixels"; |
case 21: return "2592 x 1944 pixels"; |
case 22: return "2304 x 1728 pixels"; |
case 36: return "3008 x 2008 pixels"; |
default: return "Unknown (" + value + ")"; |
} |
} |
public String getQualityModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_QUALITY_MODE); |
switch (value) { |
case 1: |
return "Fine"; |
case 2: |
return "Super Fine"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getThumbnailOffsetDescription() |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET)) return null; |
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_OFFSET); |
} |
public String getThumbnailSizeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE)) return null; |
int value = _directory.getInt(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_SIZE); |
return Integer.toString(value) + " bytes"; |
} |
public String getThumbnailDimensionsDescription() throws MetadataException |
{ |
if (!_directory.containsTag(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS)) return null; |
int[] dimensions = _directory.getIntArray(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS); |
if (dimensions.length!=2) |
return _directory.getString(CasioType2MakernoteDirectory.TAG_CASIO_TYPE2_THUMBNAIL_DIMENSIONS); |
return dimensions[0] + " x " + dimensions[1] + " pixels"; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KyoceraMakernoteDirectory.java |
---|
0,0 → 1,53 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class KyoceraMakernoteDirectory extends Directory |
{ |
public static final int TAG_KYOCERA_PROPRIETARY_THUMBNAIL = 0x0001; |
public static final int TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO = 0x0E00; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_KYOCERA_PROPRIETARY_THUMBNAIL), "Proprietary Thumbnail Format Data"); |
tagNameMap.put(new Integer(TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); |
} |
public KyoceraMakernoteDirectory() |
{ |
this.setDescriptor(new KyoceraMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Kyocera/Contax Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/CanonMakernoteDirectory.java |
---|
0,0 → 1,448 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* Describes tags specific to Canon cameras. |
* |
* Thanks to Bill Richards for his contribution to this makernote directory. |
* |
* Many tag definitions explained here: http://www.ozhiker.com/electronics/pjmt/jpeg_info/canon_mn.html |
*/ |
public class CanonMakernoteDirectory extends Directory |
{ |
// CANON cameras have some funny bespoke fields that need further processing... |
public static final int TAG_CANON_CAMERA_STATE_1 = 0x0001; |
public static final int TAG_CANON_CAMERA_STATE_2 = 0x0004; |
public static final int TAG_CANON_IMAGE_TYPE = 0x0006; |
public static final int TAG_CANON_FIRMWARE_VERSION = 0x0007; |
public static final int TAG_CANON_IMAGE_NUMBER = 0x0008; |
public static final int TAG_CANON_OWNER_NAME = 0x0009; |
/** |
* To display serial number as on camera use: printf( "%04X%05d", highbyte, lowbyte ) |
* TODO handle this in CanonMakernoteDescriptor |
*/ |
public static final int TAG_CANON_SERIAL_NUMBER = 0x000C; |
public static final int TAG_CANON_UNKNOWN_1 = 0x000D; |
public static final int TAG_CANON_CUSTOM_FUNCTIONS = 0x000F; |
// These 'sub'-tag values have been created for consistency -- they don't exist within the exif segment |
/** |
* 1 = Macro |
* 2 = Normal |
*/ |
public static final int TAG_CANON_STATE1_MACRO_MODE = 0xC101; |
public static final int TAG_CANON_STATE1_SELF_TIMER_DELAY = 0xC102; |
/** |
* 2 = Normal |
* 3 = Fine |
* 5 = Superfine |
*/ |
public static final int TAG_CANON_STATE1_QUALITY = 0xC103; |
/** |
* 0 = Flash Not Fired |
* 1 = Auto |
* 2 = On |
* 3 = Red Eye Reduction |
* 4 = Slow Synchro |
* 5 = Auto + Red Eye Reduction |
* 6 = On + Red Eye Reduction |
* 16 = External Flash |
*/ |
public static final int TAG_CANON_STATE1_FLASH_MODE = 0xC104; |
/** |
* 0 = Single Frame or Timer Mode |
* 1 = Continuous |
*/ |
public static final int TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE = 0xC105; |
public static final int TAG_CANON_STATE1_UNKNOWN_2 = 0xC106; |
/** |
* 0 = One-Shot |
* 1 = AI Servo |
* 2 = AI Focus |
* 3 = Manual Focus |
* 4 = Single |
* 5 = Continuous |
* 6 = Manual Focus |
*/ |
public static final int TAG_CANON_STATE1_FOCUS_MODE_1 = 0xC107; |
public static final int TAG_CANON_STATE1_UNKNOWN_3 = 0xC108; |
public static final int TAG_CANON_STATE1_UNKNOWN_4 = 0xC109; |
/** |
* 0 = Large |
* 1 = Medium |
* 2 = Small |
*/ |
public static final int TAG_CANON_STATE1_IMAGE_SIZE = 0xC10A; |
/** |
* 0 = Full Auto |
* 1 = Manual |
* 2 = Landscape |
* 3 = Fast Shutter |
* 4 = Slow Shutter |
* 5 = Night |
* 6 = Black & White |
* 7 = Sepia |
* 8 = Portrait |
* 9 = Sports |
* 10 = Macro / Close-Up |
* 11 = Pan Focus |
*/ |
public static final int TAG_CANON_STATE1_EASY_SHOOTING_MODE = 0xC10B; |
/** |
* 0 = No Digital Zoom |
* 1 = 2x |
* 2 = 4x |
*/ |
public static final int TAG_CANON_STATE1_DIGITAL_ZOOM = 0xC10C; |
/** |
* 0 = Normal |
* 1 = High |
* 65535 = Low |
*/ |
public static final int TAG_CANON_STATE1_CONTRAST = 0xC10D; |
/** |
* 0 = Normal |
* 1 = High |
* 65535 = Low |
*/ |
public static final int TAG_CANON_STATE1_SATURATION = 0xC10E; |
/** |
* 0 = Normal |
* 1 = High |
* 65535 = Low |
*/ |
public static final int TAG_CANON_STATE1_SHARPNESS = 0xC10F; |
/** |
* 0 = Check ISOSpeedRatings EXIF tag for ISO Speed |
* 15 = Auto ISO |
* 16 = ISO 50 |
* 17 = ISO 100 |
* 18 = ISO 200 |
* 19 = ISO 400 |
*/ |
public static final int TAG_CANON_STATE1_ISO = 0xC110; |
/** |
* 3 = Evaluative |
* 4 = Partial |
* 5 = Centre Weighted |
*/ |
public static final int TAG_CANON_STATE1_METERING_MODE = 0xC111; |
/** |
* 0 = Manual |
* 1 = Auto |
* 3 = Close-up (Macro) |
* 8 = Locked (Pan Mode) |
*/ |
public static final int TAG_CANON_STATE1_FOCUS_TYPE = 0xC112; |
/** |
* 12288 = None (Manual Focus) |
* 12289 = Auto Selected |
* 12290 = Right |
* 12291 = Centre |
* 12292 = Left |
*/ |
public static final int TAG_CANON_STATE1_AF_POINT_SELECTED = 0xC113; |
/** |
* 0 = Easy Shooting (See Easy Shooting Mode) |
* 1 = Program |
* 2 = Tv-Priority |
* 3 = Av-Priority |
* 4 = Manual |
* 5 = A-DEP |
*/ |
public static final int TAG_CANON_STATE1_EXPOSURE_MODE = 0xC114; |
public static final int TAG_CANON_STATE1_UNKNOWN_7 = 0xC115; |
public static final int TAG_CANON_STATE1_UNKNOWN_8 = 0xC116; |
public static final int TAG_CANON_STATE1_LONG_FOCAL_LENGTH = 0xC117; |
public static final int TAG_CANON_STATE1_SHORT_FOCAL_LENGTH = 0xC118; |
public static final int TAG_CANON_STATE1_FOCAL_UNITS_PER_MM = 0xC119; |
public static final int TAG_CANON_STATE1_UNKNOWN_9 = 0xC11A; |
public static final int TAG_CANON_STATE1_UNKNOWN_10 = 0xC11B; |
/** |
* 0 = Flash Did Not Fire |
* 1 = Flash Fired |
*/ |
public static final int TAG_CANON_STATE1_FLASH_ACTIVITY = 0xC11C; |
public static final int TAG_CANON_STATE1_FLASH_DETAILS = 0xC11D; |
public static final int TAG_CANON_STATE1_UNKNOWN_12 = 0xC11E; |
public static final int TAG_CANON_STATE1_UNKNOWN_13 = 0xC11F; |
/** |
* 0 = Focus Mode: Single |
* 1 = Focus Mode: Continuous |
*/ |
public static final int TAG_CANON_STATE1_FOCUS_MODE_2 = 0xC120; |
/** |
* 0 = Auto |
* 1 = Sunny |
* 2 = Cloudy |
* 3 = Tungsten |
* 4 = Flourescent |
* 5 = Flash |
* 6 = Custom |
*/ |
public static final int TAG_CANON_STATE2_WHITE_BALANCE = 0xC207; |
public static final int TAG_CANON_STATE2_SEQUENCE_NUMBER = 0xC209; |
public static final int TAG_CANON_STATE2_AF_POINT_USED = 0xC20E; |
/** |
* The value of this tag may be translated into a flash bias value, in EV. |
* |
* 0xffc0 = -2 EV |
* 0xffcc = -1.67 EV |
* 0xffd0 = -1.5 EV |
* 0xffd4 = -1.33 EV |
* 0xffe0 = -1 EV |
* 0xffec = -0.67 EV |
* 0xfff0 = -0.5 EV |
* 0xfff4 = -0.33 EV |
* 0x0000 = 0 EV |
* 0x000c = 0.33 EV |
* 0x0010 = 0.5 EV |
* 0x0014 = 0.67 EV |
* 0x0020 = 1 EV |
* 0x002c = 1.33 EV |
* 0x0030 = 1.5 EV |
* 0x0034 = 1.67 EV |
* 0x0040 = 2 EV |
*/ |
public static final int TAG_CANON_STATE2_FLASH_BIAS = 0xC20F; |
public static final int TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING = 0xC210; |
public static final int TAG_CANON_STATE2_AEB_BRACKET_VALUE = 0xC211; |
public static final int TAG_CANON_STATE2_SUBJECT_DISTANCE = 0xC213; |
/** |
* Long Exposure Noise Reduction |
* 0 = Off |
* 1 = On |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION = 0xC301; |
/** |
* Shutter/Auto Exposure-lock buttons |
* 0 = AF/AE lock |
* 1 = AE lock/AF |
* 2 = AF/AF lock |
* 3 = AE+release/AE+AF |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS = 0xC302; |
/** |
* Mirror lockup |
* 0 = Disable |
* 1 = Enable |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP = 0xC303; |
/** |
* Tv/Av and exposure level |
* 0 = 1/2 stop |
* 1 = 1/3 stop |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL = 0xC304; |
/** |
* AF-assist light |
* 0 = On (Auto) |
* 1 = Off |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT = 0xC305; |
/** |
* Shutter speed in Av mode |
* 0 = Automatic |
* 1 = 1/200 (fixed) |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE = 0xC306; |
/** |
* Auto-Exposure Bracketting sequence/auto cancellation |
* 0 = 0,-,+ / Enabled |
* 1 = 0,-,+ / Disabled |
* 2 = -,0,+ / Enabled |
* 3 = -,0,+ / Disabled |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_BRACKETTING = 0xC307; |
/** |
* Shutter Curtain Sync |
* 0 = 1st Curtain Sync |
* 1 = 2nd Curtain Sync |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC = 0xC308; |
/** |
* Lens Auto-Focus stop button Function Switch |
* 0 = AF stop |
* 1 = Operate AF |
* 2 = Lock AE and start timer |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_AF_STOP = 0xC309; |
/** |
* Auto reduction of fill flash |
* 0 = Enable |
* 1 = Disable |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION = 0xC30A; |
/** |
* Menu button return position |
* 0 = Top |
* 1 = Previous (volatile) |
* 2 = Previous |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN = 0xC30B; |
/** |
* SET button function when shooting |
* 0 = Not Assigned |
* 1 = Change Quality |
* 2 = Change ISO Speed |
* 3 = Select Parameters |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION = 0xC30C; |
/** |
* Sensor cleaning |
* 0 = Disable |
* 1 = Enable |
*/ |
public static final int TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING = 0xC30D; |
// 9 A B C D E F 10 11 12 13 |
// 9 10 11 12 13 14 15 16 17 18 19 |
protected static final HashMap _tagNameMap = new HashMap(); |
static |
{ |
_tagNameMap.put(new Integer(TAG_CANON_FIRMWARE_VERSION), "Firmware Version"); |
_tagNameMap.put(new Integer(TAG_CANON_IMAGE_NUMBER), "Image Number"); |
_tagNameMap.put(new Integer(TAG_CANON_IMAGE_TYPE), "Image Type"); |
_tagNameMap.put(new Integer(TAG_CANON_OWNER_NAME), "Owner Name"); |
_tagNameMap.put(new Integer(TAG_CANON_UNKNOWN_1), "Makernote Unknown 1"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTIONS), "Custom Functions"); |
_tagNameMap.put(new Integer(TAG_CANON_SERIAL_NUMBER), "Camera Serial Number"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_AF_POINT_SELECTED), "AF Point Selected"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTINUOUS_DRIVE_MODE), "Continuous Drive Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_CONTRAST), "Contrast"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_EASY_SHOOTING_MODE), "Easy Shooting Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_EXPOSURE_MODE), "Exposure Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_DETAILS), "Flash Details"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_MODE), "Flash Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCAL_UNITS_PER_MM), "Focal Units per mm"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_1), "Focus Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_MODE_2), "Focus Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_IMAGE_SIZE), "Image Size"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_ISO), "Iso"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_LONG_FOCAL_LENGTH), "Long Focal Length"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_MACRO_MODE), "Macro Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_METERING_MODE), "Metering Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SATURATION), "Saturation"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SELF_TIMER_DELAY), "Self Timer Delay"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SHARPNESS), "Sharpness"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_SHORT_FOCAL_LENGTH), "Short Focal Length"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_QUALITY), "Quality"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_2), "Unknown Camera State 2"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_3), "Unknown Camera State 3"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_4), "Unknown Camera State 4"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_DIGITAL_ZOOM), "Digital Zoom"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FOCUS_TYPE), "Focus Type"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_7), "Unknown Camera State 7"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_8), "Unknown Camera State 8"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_9), "Unknown Camera State 9"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_10), "Unknown Camera State 10"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_FLASH_ACTIVITY), "Flash Activity"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_12), "Unknown Camera State 12"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE1_UNKNOWN_13), "Unknown Camera State 13"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_WHITE_BALANCE), "White Balance"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_SEQUENCE_NUMBER), "Sequence Number"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AF_POINT_USED), "AF Point Used"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_FLASH_BIAS), "Flash Bias"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AUTO_EXPOSURE_BRACKETING), "Auto Exposure Bracketing"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_AEB_BRACKET_VALUE), "AEB Bracket Value"); |
_tagNameMap.put(new Integer(TAG_CANON_STATE2_SUBJECT_DISTANCE), "Subject Distance"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_LONG_EXPOSURE_NOISE_REDUCTION), "Long Exposure Noise Reduction"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_AUTO_EXPOSURE_LOCK_BUTTONS), "Shutter/Auto Exposure-lock Buttons"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MIRROR_LOCKUP), "Mirror Lockup"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_TV_AV_AND_EXPOSURE_LEVEL), "Tv/Av And Exposure Level"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_ASSIST_LIGHT), "AF-Assist Light"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_SPEED_IN_AV_MODE), "Shutter Speed in Av Mode"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_BRACKETTING), "Auto-Exposure Bracketting Sequence/Auto Cancellation"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SHUTTER_CURTAIN_SYNC), "Shutter Curtain Sync"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_AF_STOP), "Lens Auto-Focus Stop Button Function Switch"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_FILL_FLASH_REDUCTION), "Auto Reduction of Fill Flash"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_MENU_BUTTON_RETURN), "Menu Button Return Position"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SET_BUTTON_FUNCTION), "SET Button Function When Shooting"); |
_tagNameMap.put(new Integer(TAG_CANON_CUSTOM_FUNCTION_SENSOR_CLEANING), "Sensor Cleaning"); |
} |
public CanonMakernoteDirectory() |
{ |
this.setDescriptor(new CanonMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Canon Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
/** |
* We need special handling for selected tags. |
* @param tagType |
* @param ints |
*/ |
public void setIntArray(int tagType, int[] ints) |
{ |
if (tagType == TAG_CANON_CAMERA_STATE_1) { |
// this single tag has multiple values within |
int subTagTypeBase = 0xC100; |
// we intentionally skip the first array member |
for (int i = 1; i < ints.length; i++) { |
setInt(subTagTypeBase + i, ints[i]); |
} |
} else if (tagType == TAG_CANON_CAMERA_STATE_2) { |
// this single tag has multiple values within |
int subTagTypeBase = 0xC200; |
// we intentionally skip the first array member |
for (int i = 1; i < ints.length; i++) { |
setInt(subTagTypeBase + i, ints[i]); |
} |
} if (tagType == TAG_CANON_CUSTOM_FUNCTIONS) { |
// this single tag has multiple values within |
int subTagTypeBase = 0xC300; |
// we intentionally skip the first array member |
for (int i = 1; i < ints.length; i++) { |
setInt(subTagTypeBase + i + 1, ints[i] & 0x0F); |
} |
} else { |
// no special handling... |
super.setIntArray(tagType, ints); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifInteropDescriptor.java |
---|
0,0 → 1,62 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 22:27:34 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class ExifInteropDescriptor extends TagDescriptor |
{ |
public ExifInteropDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case ExifInteropDirectory.TAG_INTEROP_INDEX: |
return getInteropIndexDescription(); |
case ExifInteropDirectory.TAG_INTEROP_VERSION: |
return getInteropVersionDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getInteropVersionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_VERSION)) return null; |
int[] ints = _directory.getIntArray(ExifInteropDirectory.TAG_INTEROP_VERSION); |
return ExifDescriptor.convertBytesToVersionString(ints); |
} |
public String getInteropIndexDescription() |
{ |
if (!_directory.containsTag(ExifInteropDirectory.TAG_INTEROP_INDEX)) return null; |
String interopIndex = _directory.getString(ExifInteropDirectory.TAG_INTEROP_INDEX).trim(); |
if ("R98".equalsIgnoreCase(interopIndex)) { |
return "Recommended Exif Interoperability Rules (ExifR98)"; |
} else { |
return "Unknown (" + interopIndex + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType1MakernoteDirectory.java |
---|
0,0 → 1,80 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* Contains values specific to Nikon cameras. Type-1 is for E-Series cameras prior to (not including) E990. |
* |
* There are 3 formats of Nikon's MakerNote. MakerNote of E700/E800/E900/E900S/E910/E950 |
* starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from |
* offset 0x08. This is the same as Olympus except start string. Example of actual data |
* structure is shown below. |
* <pre><code> |
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... |
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ |
* </code></pre> |
*/ |
public class NikonType1MakernoteDirectory extends Directory |
{ |
public static final int TAG_NIKON_TYPE1_UNKNOWN_1 = 0x0002; |
public static final int TAG_NIKON_TYPE1_QUALITY = 0x0003; |
public static final int TAG_NIKON_TYPE1_COLOR_MODE = 0x0004; |
public static final int TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT = 0x0005; |
public static final int TAG_NIKON_TYPE1_CCD_SENSITIVITY = 0x0006; |
public static final int TAG_NIKON_TYPE1_WHITE_BALANCE = 0x0007; |
public static final int TAG_NIKON_TYPE1_FOCUS = 0x0008; |
public static final int TAG_NIKON_TYPE1_UNKNOWN_2 = 0x0009; |
public static final int TAG_NIKON_TYPE1_DIGITAL_ZOOM = 0x000A; |
public static final int TAG_NIKON_TYPE1_CONVERTER = 0x000B; |
public static final int TAG_NIKON_TYPE1_UNKNOWN_3 = 0x0F00; |
protected static final HashMap _tagNameMap = new HashMap(); |
static |
{ |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_CCD_SENSITIVITY), "CCD Sensitivity"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_COLOR_MODE), "Color Mode"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_DIGITAL_ZOOM), "Digital Zoom"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_CONVERTER), "Fisheye Converter"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_FOCUS), "Focus"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT), "Image Adjustment"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_QUALITY), "Quality"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_1), "Makernote Unknown 1"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_2), "Makernote Unknown 2"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_UNKNOWN_3), "Makernote Unknown 3"); |
_tagNameMap.put(new Integer(TAG_NIKON_TYPE1_WHITE_BALANCE), "White Balance"); |
} |
public NikonType1MakernoteDirectory() |
{ |
this.setDescriptor(new NikonType1MakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Nikon Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withExif.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/noExif.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/windowsXpFields.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType2MakernoteTest1.java |
---|
0,0 → 1,149 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 3-Oct-2002 20:47:31 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.imaging.jpeg.JpegSegmentData; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.exif.ExifReader; |
import com.drew.metadata.exif.NikonType2MakernoteDescriptor; |
import com.drew.metadata.exif.NikonType2MakernoteDirectory; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class NikonType2MakernoteTest1 extends TestCase |
{ |
private NikonType2MakernoteDirectory _nikonDirectory; |
private NikonType2MakernoteDescriptor _descriptor; |
public NikonType2MakernoteTest1(String s) |
{ |
super(s); |
} |
protected void setUp() throws Exception |
{ |
File metadataFile = new File("src/com/drew/metadata/exif/test/nikonMakernoteType2a.metadata"); |
Metadata metadata = new ExifReader(JpegSegmentData.FromFile(metadataFile)).extract(); |
_nikonDirectory = (NikonType2MakernoteDirectory)metadata.getDirectory(NikonType2MakernoteDirectory.class); |
_descriptor = new NikonType2MakernoteDescriptor(_nikonDirectory); |
} |
/* |
[Nikon Makernote] Firmware Version = 0200 |
[Nikon Makernote] ISO = 0 320 |
[Nikon Makernote] File Format = FINE |
[Nikon Makernote] White Balance = FLASH |
[Nikon Makernote] Sharpening = AUTO |
[Nikon Makernote] AF Type = AF-C |
[Nikon Makernote] Unknown 17 = NORMAL |
[Nikon Makernote] Unknown 18 = |
[Nikon Makernote] White Balance Fine = 0 |
[Nikon Makernote] Unknown 01 = |
[Nikon Makernote] Unknown 02 = |
[Nikon Makernote] Unknown 03 = 914 |
[Nikon Makernote] Unknown 19 = |
[Nikon Makernote] ISO = 0 320 |
[Nikon Makernote] Tone Compensation = AUTO |
[Nikon Makernote] Unknown 04 = 6 |
[Nikon Makernote] Lens Focal/Max-FStop pairs = 240/10 850/10 35/10 45/10 |
[Nikon Makernote] Unknown 05 = 0 |
[Nikon Makernote] Unknown 06 = |
[Nikon Makernote] Unknown 07 = 1 |
[Nikon Makernote] Unknown 20 = 0 |
[Nikon Makernote] Unknown 08 = @ |
[Nikon Makernote] Colour Mode = MODE1 |
[Nikon Makernote] Unknown 10 = NATURAL |
[Nikon Makernote] Unknown 11 = 0100 |
- |
[Nikon Makernote] Camera Hue = 0 |
[Nikon Makernote] Noise Reduction = OFF |
[Nikon Makernote] Unknown 12 = 0100 |
[Nikon Makernote] Unknown 13 = 0100{t@7b,4x,D"Y |
[Nikon Makernote] Unknown 15 = 78/10 78/10 |
*/ |
public void testNikonMakernote_MatchesKnownValues() throws Exception |
{ |
assertEquals("48 50 48 48", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION)); |
assertEquals("0 320", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1)); |
assertEquals("0 320", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_2)); |
assertEquals("FLASH ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_SHARPENING)); |
assertEquals("AF-C ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_TYPE)); |
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_SYNC_MODE)); |
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE_FINE)); |
assertEquals("914", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_3)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_TONE_COMPENSATION)); |
assertEquals("6", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_4)); |
assertEquals("240/10 850/10 35/10 45/10", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS)); |
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_5)); |
assertEquals("1", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_7)); |
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_20)); |
assertEquals("MODE1 ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE)); |
assertEquals("NATURAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LIGHT_SOURCE)); |
assertEquals("0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT)); |
assertEquals("OFF ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_NOISE_REDUCTION)); |
assertEquals("78/10 78/10", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_15)); |
} |
public void testGetLensDescription() throws MetadataException |
{ |
assertEquals("24-85mm f/3.5-4.5", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS)); |
assertEquals("24-85mm f/3.5-4.5", _descriptor.getLensDescription()); |
} |
public void testGetHueAdjustmentDescription() throws MetadataException |
{ |
assertEquals("0 degrees", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT)); |
assertEquals("0 degrees", _descriptor.getHueAdjustmentDescription()); |
} |
public void testGetColorModeDescription() throws Exception |
{ |
assertEquals("Mode I (sRGB)", _descriptor.getDescription(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE)); |
assertEquals("Mode I (sRGB)", _descriptor.getColorModeDescription()); |
} |
public void testGetAutoFlashCompensationDescription() throws Exception |
{ |
NikonType2MakernoteDirectory directory = new NikonType2MakernoteDirectory(); |
NikonType2MakernoteDescriptor descriptor = new NikonType2MakernoteDescriptor(directory); |
// no entry exists |
assertEquals("Unknown", descriptor.getAutoFlashCompensationDescription()); |
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x06, 0x01, 0x06 }); |
assertEquals("1 EV", descriptor.getAutoFlashCompensationDescription()); |
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x04, 0x01, 0x06 }); |
assertEquals("0.67 EV", descriptor.getAutoFlashCompensationDescription()); |
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { 0x02, 0x01, 0x06 }); |
assertEquals("0.33 EV", descriptor.getAutoFlashCompensationDescription()); |
directory.setByteArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION, new byte[] { (byte)0xFE, 0x01, 0x06 }); |
assertEquals("-0.33 EV", descriptor.getAutoFlashCompensationDescription()); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType2MakernoteTest2.java |
---|
0,0 → 1,169 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.lang.Rational; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.NikonType2MakernoteDirectory; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class NikonType2MakernoteTest2 extends TestCase |
{ |
private NikonType2MakernoteDirectory _nikonDirectory; |
private ExifDirectory _exifDirectory; |
public NikonType2MakernoteTest2(String s) |
{ |
super(s); |
} |
protected void setUp() throws Exception |
{ |
File nikonJpeg = new File("src/com/drew/metadata/exif/test/nikonMakernoteType2b.jpg"); |
Metadata metadata = JpegMetadataReader.readMetadata(nikonJpeg); |
_nikonDirectory = (NikonType2MakernoteDirectory)metadata.getDirectory(NikonType2MakernoteDirectory.class); |
_exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
} |
/* |
[Nikon Makernote] Makernote Unknown 1 = |
[Nikon Makernote] ISO Setting = Unknown (0 0) |
[Nikon Makernote] Color Mode = COLOR |
[Nikon Makernote] Quality = NORMAL |
[Nikon Makernote] White Balance = AUTO |
[Nikon Makernote] Image Sharpening = AUTO |
[Nikon Makernote] Focus Mode = AF-C |
[Nikon Makernote] Flash Setting = NORMAL |
[Nikon Makernote] Makernote Unknown 2 = 4416/500 |
[Nikon Makernote] ISO Selection = AUTO |
[Nikon Makernote] Unknown tag (0x0011) = 1300 |
[Nikon Makernote] Image Adjustment = AUTO |
[Nikon Makernote] Adapter = OFF |
[Nikon Makernote] Focus Distance = 0 |
[Nikon Makernote] Digital Zoom = No digital zoom |
[Nikon Makernote] AF Focus Position = Unknown () |
[Nikon Makernote] Unknown tag (0x008f) = |
[Nikon Makernote] Unknown tag (0x0094) = 0 |
[Nikon Makernote] Unknown tag (0x0095) = FPNR |
[Nikon Makernote] Unknown tag (0x0e00) = PrintIM |
[Nikon Makernote] Unknown tag (0x0e10) = 1394 |
*/ |
public void testNikonMakernote_MatchesKnownValues() throws Exception |
{ |
assertEquals("0 1 0 0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION)); |
assertEquals("0 0", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1)); |
assertEquals("COLOR", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_COLOR_MODE)); |
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_QUALITY_AND_FILE_FORMAT)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_WHITE_BALANCE)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_SHARPENING)); |
assertEquals("AF-C ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_TYPE)); |
assertEquals("NORMAL ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FLASH_SYNC_MODE)); |
// assertEquals(new Rational(4416,500), _nikonDirectory.getRational(NikonType3MakernoteDirectory.TAG_NIKON_TYPE2_UNKNOWN_2)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_SELECTION)); |
assertEquals(1300, _nikonDirectory.getInt(0x0011)); |
assertEquals("AUTO ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_IMAGE_ADJUSTMENT)); |
assertEquals("OFF ", _nikonDirectory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ADAPTER)); |
assertEquals(0, _nikonDirectory.getInt(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_MANUAL_FOCUS_DISTANCE)); |
assertEquals(1, _nikonDirectory.getInt(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM)); |
assertEquals(" ", _nikonDirectory.getString(0x008f)); |
assertEquals(0, _nikonDirectory.getInt(0x0094)); |
assertEquals("FPNR", _nikonDirectory.getString(0x0095)); |
assertEquals("80 114 105 110 116 73 77 0 48 49 48 48 0 0 13 0 1 0 22 0 22 0 2 0 1 0 0 0 3 0 94 0 0 0 7 0 0 0 0 0 8 0 0 0 0 0 9 0 0 0 0 0 10 0 0 0 0 0 11 0 -90 0 0 0 12 0 0 0 0 0 13 0 0 0 0 0 14 0 -66 0 0 0 0 1 5 0 0 0 1 1 1 0 0 0 9 17 0 0 16 39 0 0 11 15 0 0 16 39 0 0 -105 5 0 0 16 39 0 0 -80 8 0 0 16 39 0 0 1 28 0 0 16 39 0 0 94 2 0 0 16 39 0 0 -117 0 0 0 16 39 0 0 -53 3 0 0 16 39 0 0 -27 27 0 0 16 39 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", _nikonDirectory.getString(0x0e00)); |
// assertEquals("PrintIM", _nikonDirectory.getString(0x0e00)); |
assertEquals(1394, _nikonDirectory.getInt(0x0e10)); |
} |
/* |
[Exif] Image Description = |
[Exif] Make = NIKON |
[Exif] Model = E995 |
[Exif] X Resolution = 72 dots per inch |
[Exif] Y Resolution = 72 dots per inch |
[Exif] Resolution Unit = Inch |
[Exif] Software = E995v1.6 |
[Exif] Date/Time = 2002:08:29 17:31:40 |
[Exif] YCbCr Positioning = Center of pixel array |
[Exif] Exposure Time = 2439024/100000000 sec |
[Exif] F-Number = F2.6 |
[Exif] Exposure Program = Program normal |
[Exif] ISO Speed Ratings = 100 |
[Exif] Exif Version = 2.10 |
[Exif] Date/Time Original = 2002:08:29 17:31:40 |
[Exif] Date/Time Digitized = 2002:08:29 17:31:40 |
[Exif] Components Configuration = YCbCr |
[Exif] Exposure Bias Value = 0 |
[Exif] Max Aperture Value = F1 |
[Exif] Metering Mode = Multi-segment |
[Exif] Light Source = Unknown |
[Exif] Flash = Flash fired |
[Exif] Focal Length = 8.2 mm |
[Exif] User Comment = |
[Exif] FlashPix Version = 1.00 |
[Exif] Color Space = sRGB |
[Exif] Exif Image Width = 2048 pixels |
[Exif] Exif Image Height = 1536 pixels |
[Exif] File Source = Digital Still Camera (DSC) |
[Exif] Scene Type = Directly photographed image |
[Exif] Compression = JPEG compression |
[Exif] Thumbnail Offset = 1494 bytes |
[Exif] Thumbnail Length = 6077 bytes |
[Exif] Thumbnail Data = [6077 bytes of thumbnail data] |
*/ |
public void testExifDirectory_MatchesKnownValues() throws Exception |
{ |
assertEquals(" ", _exifDirectory.getString(ExifDirectory.TAG_IMAGE_DESCRIPTION)); |
assertEquals("NIKON", _exifDirectory.getString(ExifDirectory.TAG_MAKE)); |
assertEquals("E995", _exifDirectory.getString(ExifDirectory.TAG_MODEL)); |
assertEquals(72, _exifDirectory.getDouble(ExifDirectory.TAG_X_RESOLUTION), 0.001); |
assertEquals(72, _exifDirectory.getDouble(ExifDirectory.TAG_Y_RESOLUTION), 0.001); |
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT)); |
assertEquals("E995v1.6", _exifDirectory.getString(ExifDirectory.TAG_SOFTWARE)); |
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING)); |
assertEquals(new Rational(2439024, 100000000), _exifDirectory.getRational(ExifDirectory.TAG_EXPOSURE_TIME)); |
assertEquals(2.6, _exifDirectory.getDouble(ExifDirectory.TAG_FNUMBER), 0.001); |
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM)); |
assertEquals(100, _exifDirectory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT)); |
assertEquals("48 50 49 48", _exifDirectory.getString(ExifDirectory.TAG_EXIF_VERSION)); |
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED)); |
assertEquals("2002:08:29 17:31:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL)); |
assertEquals("1 2 3 0", _exifDirectory.getString(ExifDirectory.TAG_COMPONENTS_CONFIGURATION)); |
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_BIAS)); |
assertEquals("0", _exifDirectory.getString(ExifDirectory.TAG_MAX_APERTURE)); |
assertEquals(5, _exifDirectory.getInt(ExifDirectory.TAG_METERING_MODE)); |
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_WHITE_BALANCE)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_FLASH)); |
assertEquals(8.2, _exifDirectory.getDouble(ExifDirectory.TAG_FOCAL_LENGTH), 0.001); |
assertEquals("0 0 0 0 0 0 0 0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32", _exifDirectory.getString(ExifDirectory.TAG_USER_COMMENT)); |
assertEquals("48 49 48 48", _exifDirectory.getString(ExifDirectory.TAG_FLASHPIX_VERSION)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_COLOR_SPACE)); |
assertEquals(2048, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)); |
assertEquals(1536, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)); |
assertEquals(3, _exifDirectory.getInt(ExifDirectory.TAG_FILE_SOURCE)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_SCENE_TYPE)); |
assertEquals(6, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION)); |
assertEquals(1494, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET)); |
assertEquals(6077, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifDescriptorTest.java |
---|
0,0 → 1,150 |
/* |
* ExifReaderTest.java |
* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Oct-2002 19:15:16 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDescriptor; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.ExifReader; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* JUnit test case for class ExifDescriptor. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class ExifDescriptorTest extends TestCase |
{ |
public ExifDescriptorTest(String s) |
{ |
super(s); |
} |
public void testXResolutionDescription() throws Exception |
{ |
ExifDirectory directory = new ExifDirectory(); |
directory.setRational(ExifDirectory.TAG_X_RESOLUTION, new Rational(72, 1)); |
// 2 is for 'Inch' |
directory.setInt(ExifDirectory.TAG_RESOLUTION_UNIT, 2); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("72 dots per inch", descriptor.getDescription(ExifDirectory.TAG_X_RESOLUTION)); |
} |
public void testYResolutionDescription() throws Exception |
{ |
ExifDirectory directory = new ExifDirectory(); |
directory.setRational(ExifDirectory.TAG_Y_RESOLUTION, new Rational(50, 1)); |
// 3 is for 'cm' |
directory.setInt(ExifDirectory.TAG_RESOLUTION_UNIT, 3); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("50 dots per cm", descriptor.getDescription(ExifDirectory.TAG_Y_RESOLUTION)); |
} |
public void testUserCommentDescription_EmptyEncoding() throws Exception |
{ |
byte[] commentBytes = "\0\0\0\0\0\0\0\0This is a comment".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("This is a comment", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUserCommentDescription_AsciiHeaderExtendedAsciiEncoding() throws Exception |
{ |
byte[] commentBytes = "ASCII\0\0This is a comment with extended characters æøå ÆØÅ".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("This is a comment with extended characters æøå ÆØÅ", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUserCommentDescription_AsciiHeaderAsciiEncoding() throws Exception |
{ |
byte[] commentBytes = "ASCII\0\0This is a comment".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("This is a comment", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUserCommentDescription_BlankAscii() throws Exception |
{ |
byte[] commentBytes = "ASCII\0\0\0 ".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUserCommentDescription_ZeroLengthAscii1() throws Exception |
{ |
// the 10-byte encoding region is only partially full |
byte[] commentBytes = "ASCII\0\0\0".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("ASCII", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUserCommentDescription_ZeroLengthAscii2() throws Exception |
{ |
// fill the 10-byte encoding region |
byte[] commentBytes = "ASCII\0\0\0\0\0".getBytes(); |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUnicodeComment_ActualBytes() throws Exception |
{ |
byte[] commentBytes = new byte[] { 85, 78, 73, 67, 79, 68, 69, 0, 84, 0, 104, 0, 105, 0, 115, 0, 32, 0, 109, 0, 97, 0, 114, 0, 109, 0, 111, 0, 116, 0, 32, 0, 105, 0, 115, 0, 32, 0, 103, 0, 101, 0, 116, 0, 116, 0, 105, 0, 110, 0, 103, 0, 32, 0, 99, 0, 108, 0, 111, 0, 115, 0, 101, 0, 46, 0, 46, 0, 46, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0 }; |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("This marmot is getting close...", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testUnicodeComment_Ascii() throws Exception |
{ |
byte[] commentBytes = new byte[] { 65, 83, 67, 73, 73, 0, 0, 0, 73, 32, 97, 109, 32, 97, 32, 99, 111, 109, 109, 101, 110, 116, 46, 32, 89, 101, 121, 46, 0 }; |
ExifDirectory directory = new ExifDirectory(); |
directory.setByteArray(ExifDirectory.TAG_USER_COMMENT, commentBytes); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("I am a comment. Yey.", descriptor.getDescription(ExifDirectory.TAG_USER_COMMENT)); |
} |
public void testWindowsXpFields() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/windowsXpFields.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
ExifDescriptor descriptor = new ExifDescriptor(directory); |
assertEquals("Testing artist", descriptor.getDescription(ExifDirectory.TAG_WIN_AUTHOR)); |
assertEquals("Testing comments", descriptor.getDescription(ExifDirectory.TAG_WIN_COMMENT)); |
assertEquals("Testing keywords", descriptor.getDescription(ExifDirectory.TAG_WIN_KEYWORDS)); |
assertEquals("Testing subject", descriptor.getDescription(ExifDirectory.TAG_WIN_SUBJECT)); |
assertEquals("Testing title", descriptor.getDescription(ExifDirectory.TAG_WIN_TITLE)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/crash01.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/badExif.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/CanonMakernoteDescriptorTest.java |
---|
0,0 → 1,65 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.metadata.exif.CanonMakernoteDescriptor; |
import com.drew.metadata.exif.CanonMakernoteDirectory; |
import junit.framework.TestCase; |
public class CanonMakernoteDescriptorTest extends TestCase |
{ |
public CanonMakernoteDescriptorTest(String name) |
{ |
super(name); |
} |
public void testGetFlashBiasDescription() throws Exception |
{ |
CanonMakernoteDirectory directory = new CanonMakernoteDirectory(); |
CanonMakernoteDescriptor descriptor = new CanonMakernoteDescriptor(directory); |
// set and check values |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0xFFC0); |
assertEquals("-2.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0xffd4); |
assertEquals("-1.375 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0000); |
assertEquals("0.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x000c); |
assertEquals("0.375 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0010); |
assertEquals("0.5 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0014); |
assertEquals("0.625 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0020); |
assertEquals("1.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0030); |
assertEquals("1.5 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0034); |
assertEquals("1.625 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
directory.setInt(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS, 0x0040); |
assertEquals("2.0 EV", descriptor.getDescription(CanonMakernoteDirectory.TAG_CANON_STATE2_FLASH_BIAS)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/recursiveDirectories.metadata |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType1.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/NikonType1MakernoteTest.java |
---|
0,0 → 1,172 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.lang.Rational; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.NikonType1MakernoteDirectory; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class NikonType1MakernoteTest extends TestCase |
{ |
private NikonType1MakernoteDirectory _nikonDirectory; |
private ExifDirectory _exifDirectory; |
public NikonType1MakernoteTest(String s) |
{ |
super(s); |
} |
/* |
[Interoperability] Interoperability Index = Recommended Exif Interoperability Rules (ExifR98) |
[Interoperability] Interoperability Version = 1.00 |
[Jpeg] Data Precision = 8 bits |
[Jpeg] Image Width = 600 pixels |
[Jpeg] Image Height = 800 pixels |
[Jpeg] Number of Components = 3 |
[Jpeg] Component 1 = Y component: Quantization table 0, Sampling factors 1 horiz/1 vert |
[Jpeg] Component 2 = Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert |
[Jpeg] Component 3 = Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert |
*/ |
protected void setUp() throws Exception |
{ |
File nikonJpeg = new File("src/com/drew/metadata/exif/test/nikonMakernoteType1.jpg"); |
Metadata metadata = JpegMetadataReader.readMetadata(nikonJpeg); |
_nikonDirectory = (NikonType1MakernoteDirectory)metadata.getDirectory(NikonType1MakernoteDirectory.class); |
_exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
} |
/* |
[Nikon Makernote] Makernote Unknown 1 = 08.00 |
[Nikon Makernote] Quality = Unknown (12) |
[Nikon Makernote] Color Mode = Color |
[Nikon Makernote] Image Adjustment = Contrast + |
[Nikon Makernote] CCD Sensitivity = ISO80 |
[Nikon Makernote] White Balance = Auto |
[Nikon Makernote] Focus = 0 |
[Nikon Makernote] Makernote Unknown 2 = |
[Nikon Makernote] Digital Zoom = No digital zoom |
[Nikon Makernote] Fisheye Converter = None |
[Nikon Makernote] Makernote Unknown 3 = 0 0 16777216 0 -1609193200 0 34833 6931 16178 4372 4372 -972290529 -921882880 15112 0 0 1151495 252903424 17 0 0 844038208 55184128 218129428 1476410198 370540566 -250604010 16711749 204629079 1729 |
*/ |
public void testNikonMakernote_MatchesKnownValues() throws Exception |
{ |
assertTrue(_nikonDirectory.getTagCount() > 0); |
assertEquals(8, _nikonDirectory.getDouble(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_1), 0.0001); |
assertEquals(12, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY)); |
assertEquals(1, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE)); |
assertEquals(3, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT)); |
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY)); |
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE)); |
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS)); |
assertEquals("", _nikonDirectory.getString(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_2)); |
assertEquals(0, _nikonDirectory.getDouble(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM), 0.0001); |
assertEquals(0, _nikonDirectory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER)); |
int[] unknown3 = _nikonDirectory.getIntArray(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_UNKNOWN_3); |
int[] expected = new int[] { 0, 0, 16777216, 0, -1609193200, 0, 34833, 6931, 16178, 4372, 4372, -972290529, -921882880, 15112, 0, 0, 1151495, 252903424, 17, 0, 0, 844038208, 55184128, 218129428, 1476410198, 370540566, -250604010, 16711749, 204629079, 1729 }; |
assertEquals(expected.length, unknown3.length); |
for (int i = 0; i<expected.length; i++) { |
assertEquals(expected[i], unknown3[i]); |
} |
} |
/* |
[Exif] Image Description = |
[Exif] Make = NIKON |
[Exif] Model = E950 |
[Exif] Orientation = top, left side |
[Exif] X Resolution = 300 dots per inch |
[Exif] Y Resolution = 300 dots per inch |
[Exif] Resolution Unit = Inch |
[Exif] Software = v981-79 |
[Exif] Date/Time = 2001:04:06 11:51:40 |
[Exif] YCbCr Positioning = Datum point |
[Exif] Exposure Time = 1/77 sec |
[Exif] F-Number = F5.5 |
[Exif] Exposure Program = Program normal |
[Exif] ISO Speed Ratings = 80 |
[Exif] Exif Version = 2.10 |
[Exif] Date/Time Original = 2001:04:06 11:51:40 |
[Exif] Date/Time Digitized = 2001:04:06 11:51:40 |
[Exif] Components Configuration = YCbCr |
[Exif] Compressed Bits Per Pixel = 4 bits/pixel |
[Exif] Exposure Bias Value = 0 |
[Exif] Max Aperture Value = F2.5 |
[Exif] Metering Mode = Multi-segment |
[Exif] Light Source = Unknown |
[Exif] Flash = No flash fired |
[Exif] Focal Length = 12.8 mm |
[Exif] User Comment = |
[Exif] FlashPix Version = 1.00 |
[Exif] Color Space = sRGB |
[Exif] Exif Image Width = 1600 pixels |
[Exif] Exif Image Height = 1200 pixels |
[Exif] File Source = Digital Still Camera (DSC) |
[Exif] Scene Type = Directly photographed image |
[Exif] Compression = JPEG compression |
[Exif] Thumbnail Offset = 2036 bytes |
[Exif] Thumbnail Length = 4662 bytes |
[Exif] Thumbnail Data = [4662 bytes of thumbnail data] |
*/ |
public void testExifDirectory_MatchesKnownValues() throws Exception |
{ |
assertEquals(" ", _exifDirectory.getString(ExifDirectory.TAG_IMAGE_DESCRIPTION)); |
assertEquals("NIKON", _exifDirectory.getString(ExifDirectory.TAG_MAKE)); |
assertEquals("E950", _exifDirectory.getString(ExifDirectory.TAG_MODEL)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_ORIENTATION)); |
assertEquals(300, _exifDirectory.getDouble(ExifDirectory.TAG_X_RESOLUTION), 0.001); |
assertEquals(300, _exifDirectory.getDouble(ExifDirectory.TAG_Y_RESOLUTION), 0.001); |
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_RESOLUTION_UNIT)); |
assertEquals("v981-79", _exifDirectory.getString(ExifDirectory.TAG_SOFTWARE)); |
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME)); |
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_YCBCR_POSITIONING)); |
assertEquals(new Rational(1, 77), _exifDirectory.getRational(ExifDirectory.TAG_EXPOSURE_TIME)); |
assertEquals(5.5, _exifDirectory.getDouble(ExifDirectory.TAG_FNUMBER), 0.001); |
assertEquals(2, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_PROGRAM)); |
assertEquals(80, _exifDirectory.getInt(ExifDirectory.TAG_ISO_EQUIVALENT)); |
assertEquals("48 50 49 48", _exifDirectory.getString(ExifDirectory.TAG_EXIF_VERSION)); |
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_DIGITIZED)); |
assertEquals("2001:04:06 11:51:40", _exifDirectory.getString(ExifDirectory.TAG_DATETIME_ORIGINAL)); |
assertEquals("1 2 3 0", _exifDirectory.getString(ExifDirectory.TAG_COMPONENTS_CONFIGURATION)); |
assertEquals(4, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION_LEVEL)); |
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_EXPOSURE_BIAS)); |
// this 2.6 *apex*, which is F2.5 |
assertEquals(2.6, _exifDirectory.getDouble(ExifDirectory.TAG_MAX_APERTURE), 0.001); |
assertEquals(5, _exifDirectory.getInt(ExifDirectory.TAG_METERING_MODE)); |
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_WHITE_BALANCE)); |
assertEquals(0, _exifDirectory.getInt(ExifDirectory.TAG_FLASH)); |
assertEquals(12.8, _exifDirectory.getDouble(ExifDirectory.TAG_FOCAL_LENGTH), 0.001); |
assertEquals("0 0 0 0 0 0 0 0 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32", _exifDirectory.getString(ExifDirectory.TAG_USER_COMMENT)); |
assertEquals("48 49 48 48", _exifDirectory.getString(ExifDirectory.TAG_FLASHPIX_VERSION)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_COLOR_SPACE)); |
assertEquals(1600, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_WIDTH)); |
assertEquals(1200, _exifDirectory.getInt(ExifDirectory.TAG_EXIF_IMAGE_HEIGHT)); |
assertEquals(3, _exifDirectory.getInt(ExifDirectory.TAG_FILE_SOURCE)); |
assertEquals(1, _exifDirectory.getInt(ExifDirectory.TAG_SCENE_TYPE)); |
assertEquals(6, _exifDirectory.getInt(ExifDirectory.TAG_COMPRESSION)); |
assertEquals(2036, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET)); |
assertEquals(4662, _exifDirectory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType2a.metadata |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/nikonMakernoteType2b.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifReaderTest.java |
---|
0,0 → 1,183 |
/* |
* ExifReaderTest.java |
* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Oct-2002 19:15:16 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.imaging.jpeg.JpegSegmentData; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.ExifReader; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* JUnit test case for class ExifReader. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class ExifReaderTest extends TestCase |
{ |
public ExifReaderTest(String s) |
{ |
super(s); |
} |
public void testLoadFujiFilmJpeg() throws Exception |
{ |
String jpegWithExif = "src/com/drew/metadata/exif/test/withExif.jpg"; |
Metadata metadata = new ExifReader(new File(jpegWithExif)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals("80", directory.getDescription(ExifDirectory.TAG_ISO_EQUIVALENT)); |
// TODO decide if this should still be returned -- it was being calculated upon setting of a related tag |
// assertEquals("F9", directory.getDescription(ExifDirectory.TAG_APERTURE)); |
} |
public void testLoadJpegWithoutExifData() throws Exception |
{ |
String jpegNoExif = "src/com/drew/metadata/exif/test/noExif.jpg"; |
Metadata metadata = new ExifReader(new File(jpegNoExif)).extract(); |
assertTrue(!metadata.containsDirectory(ExifDirectory.class)); |
} |
public void testLoadJpegWithBadExifData() throws Exception |
{ |
// This test used to ensure an exception was thrown when loading a particular jpeg |
// The intention has since changed, and the API should only throw exceptions in completely |
// fatal situations. Now, the Metadata object returned has no new tags. |
String jpegBadExif = "src/com/drew/metadata/exif/test/badExif.jpg"; // Exif data segment doesn't begin with 'Exif' |
Metadata metadata = new ExifReader(new File(jpegBadExif)).extract(); |
assertEquals(0, metadata.getDirectory(ExifDirectory.class).getTagCount()); |
} |
public void testCrashRegressionTest() throws Exception |
{ |
// this image was created via a resize in ACDSee |
// it seems to have a reference to an IFD starting outside the data segment |
// i've noticed that ACDSee reports a Comment for this image, yet ExifReader doesn't report one |
String fileName = "src/com/drew/metadata/exif/test/crash01.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
assertTrue(metadata.getDirectory(ExifDirectory.class).getTagCount() > 0); |
} |
public void testThumbnailOffset() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals(192, directory.getInt(ExifDirectory.TAG_THUMBNAIL_OFFSET)); |
} |
public void testThumbnailLength() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals(2970, directory.getInt(ExifDirectory.TAG_THUMBNAIL_LENGTH)); |
} |
public void testDateTime() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals("2002:11:27 18:00:35", directory.getString(ExifDirectory.TAG_DATETIME)); |
} |
public void testXResolution() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
Rational rational = directory.getRational(ExifDirectory.TAG_X_RESOLUTION); |
assertEquals(72, rational.getNumerator()); |
assertEquals(1, rational.getDenominator()); |
} |
public void testYResolution() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
Rational rational = directory.getRational(ExifDirectory.TAG_Y_RESOLUTION); |
assertEquals(72, rational.getNumerator()); |
assertEquals(1, rational.getDenominator()); |
} |
public void testCompression() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
// 6 means JPEG compression |
assertEquals(6, directory.getInt(ExifDirectory.TAG_COMPRESSION)); |
} |
public void testStackOverflowOnRevisitationOfSameDirectory() throws Exception |
{ |
// an error has been discovered in Exif data segments where a directory is referenced |
// repeatedly. thanks to Alistair Dickie for providing the sample image used in this |
// unit test. |
File metadataFile = new File("src/com/drew/metadata/exif/test/recursiveDirectories.metadata"); |
Metadata metadata = new ExifReader(JpegSegmentData.FromFile(metadataFile)).extract(); |
metadata.getDirectory(ExifDirectory.class); |
// String fileName = "src/com/drew/metadata/exif/test/recursiveDirectories.jpg"; |
// Metadata metadata = new ExifReader(new File(fileName)).extract(); |
// metadata.getDirectory(ExifDirectory.class); |
} |
/* |
public void testUncompressedYCbCrThumbnail() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.jpg"; |
String thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail.bmp"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
directory.writeThumbnail(thumnailFileName); |
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.jpg"; |
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail2.bmp"; |
metadata = new ExifReader(new File(fileName)).extract(); |
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
directory.writeThumbnail(thumnailFileName); |
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.jpg"; |
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail3.bmp"; |
metadata = new ExifReader(new File(fileName)).extract(); |
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
directory.writeThumbnail(thumnailFileName); |
fileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.jpg"; |
thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedYCbCrThumbnail4.bmp"; |
metadata = new ExifReader(new File(fileName)).extract(); |
directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
directory.writeThumbnail(thumnailFileName); |
} |
public void testUncompressedRGBThumbnail() throws Exception |
{ |
String fileName = "src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.jpg"; |
String thumnailFileName = "src/com/drew/metadata/exif/test/withUncompressedRGBThumbnail.bmp"; |
Metadata metadata = new ExifReader(new File(fileName)).extract(); |
ExifDirectory directory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
directory.writeThumbnail(thumnailFileName); |
} |
*/ |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/test/ExifDirectoryTest.java |
---|
0,0 → 1,87 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 25-Nov-2002 20:47:31 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class ExifDirectoryTest extends TestCase |
{ |
public ExifDirectoryTest(String s) |
{ |
super(s); |
} |
public void testGetDirectoryName() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
assertEquals("Exif", directory.getName()); |
} |
public void testGetThumbnailData() throws Exception |
{ |
File file = new File("src/com/drew/metadata/exif/test/withExif.jpg"); |
Metadata metadata = JpegMetadataReader.readMetadata(file); |
ExifDirectory exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
assertTrue(exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA)); |
byte[] thumbData = exifDirectory.getThumbnailData(); |
try { |
// attempt to read the thumbnail -- it should be a legal Jpeg file |
new JpegSegmentReader(thumbData); |
} catch (JpegProcessingException e) { |
fail("Unable to construct JpegSegmentReader from thumbnail data"); |
} |
} |
public void testWriteThumbnail() throws Exception |
{ |
File file = new File("src/com/drew/metadata/exif/test/manuallyAddedThumbnail.jpg"); |
Metadata metadata = JpegMetadataReader.readMetadata(file); |
ExifDirectory exifDirectory = (ExifDirectory)metadata.getDirectory(ExifDirectory.class); |
assertTrue(exifDirectory.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA)); |
File thumbnailFile = File.createTempFile("thumbnail", ".jpg"); |
try { |
exifDirectory.writeThumbnail(thumbnailFile.getAbsolutePath()); |
assertTrue(new File(thumbnailFile.getAbsolutePath()).exists()); |
} finally { |
thumbnailFile.delete(); |
} |
} |
public void testContainsThumbnail() |
{ |
ExifDirectory exifDirectory = new ExifDirectory(); |
assertTrue(!exifDirectory.containsThumbnail()); |
exifDirectory.setObject(ExifDirectory.TAG_THUMBNAIL_DATA, "foo"); |
assertTrue(exifDirectory.containsThumbnail()); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/FujifilmMakernoteDirectory.java |
---|
0,0 → 1,85 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class FujifilmMakernoteDirectory extends Directory |
{ |
public static final int TAG_FUJIFILM_MAKERNOTE_VERSION = 0x0000; |
public static final int TAG_FUJIFILM_QUALITY = 0x1000; |
public static final int TAG_FUJIFILM_SHARPNESS = 0x1001; |
public static final int TAG_FUJIFILM_WHITE_BALANCE = 0x1002; |
public static final int TAG_FUJIFILM_COLOR = 0x1003; |
public static final int TAG_FUJIFILM_TONE = 0x1004; |
public static final int TAG_FUJIFILM_FLASH_MODE = 0x1010; |
public static final int TAG_FUJIFILM_FLASH_STRENGTH = 0x1011; |
public static final int TAG_FUJIFILM_MACRO = 0x1020; |
public static final int TAG_FUJIFILM_FOCUS_MODE = 0x1021; |
public static final int TAG_FUJIFILM_SLOW_SYNCHRO = 0x1030; |
public static final int TAG_FUJIFILM_PICTURE_MODE = 0x1031; |
public static final int TAG_FUJIFILM_UNKNOWN_1 = 0x1032; |
public static final int TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING = 0x1100; |
public static final int TAG_FUJIFILM_UNKNOWN_2 = 0x1200; |
public static final int TAG_FUJIFILM_BLUR_WARNING = 0x1300; |
public static final int TAG_FUJIFILM_FOCUS_WARNING = 0x1301; |
public static final int TAG_FUJIFILM_AE_WARNING = 0x1302; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_FUJIFILM_AE_WARNING), "AE Warning"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_BLUR_WARNING), "Blur Warning"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_COLOR), "Color"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_CONTINUOUS_TAKING_OR_AUTO_BRACKETTING), "Continuous Taking Or Auto Bracketting"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_FLASH_MODE), "Flash Mode"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_FLASH_STRENGTH), "Flash Strength"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_FOCUS_MODE), "Focus Mode"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_FOCUS_WARNING), "Focus Warning"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_MACRO), "Macro"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_MAKERNOTE_VERSION), "Makernote Version"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_PICTURE_MODE), "Picture Mode"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_QUALITY), "Quality"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_SLOW_SYNCHRO), "Slow Synchro"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_TONE), "Tone"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_UNKNOWN_1), "Makernote Unknown 1"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_UNKNOWN_2), "Makernote Unknown 2"); |
tagNameMap.put(new Integer(TAG_FUJIFILM_WHITE_BALANCE), "White Balance"); |
} |
public FujifilmMakernoteDirectory() |
{ |
this.setDescriptor(new FujifilmMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "FujiFilm Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/KyoceraMakernoteDescriptor.java |
---|
0,0 → 1,63 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a KyoceraMakernoteDirectory. |
* |
* Some information about this makernote taken from here: |
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/kyocera_mn.html |
* |
* Most manufacturer's MakerNote counts the "offset to data" from the first byte |
* of TIFF header (same as the other IFD), but Kyocera (along with Fujifilm) counts |
* it from the first byte of MakerNote itself. |
*/ |
public class KyoceraMakernoteDescriptor extends TagDescriptor |
{ |
public KyoceraMakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO: |
return getPrintImageMatchingInfoDescription(); |
case KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL: |
return getProprietaryThumbnailDataDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getPrintImageMatchingInfoDescription() throws MetadataException |
{ |
if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO)) return null; |
byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PRINT_IMAGE_MATCHING_INFO); |
return "(" + bytes.length + " bytes)"; |
} |
public String getProprietaryThumbnailDataDescription() throws MetadataException |
{ |
if (!_directory.containsTag(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL)) return null; |
byte[] bytes = _directory.getByteArray(KyoceraMakernoteDirectory.TAG_KYOCERA_PROPRIETARY_THUMBNAIL); |
return "(" + bytes.length + " bytes)"; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/OlympusMakernoteDirectory.java |
---|
0,0 → 1,360 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* The Olympus makernote is used by many manufacturers, and as such contains some tags that appear specific to |
* those manufacturers. Other users include Konica, Minolta and Epson. |
*/ |
public class OlympusMakernoteDirectory extends Directory |
{ |
/** |
* Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_MAKERNOTE_VERSION = 0x0000; |
/** |
* Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_CAMERA_SETTINGS_1 = 0x0001; |
/** |
* Alternate Camera Settings Tag. Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_CAMERA_SETTINGS_2 = 0x0003; |
/** |
* Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE = 0x0040; |
/** |
* Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1 = 0x0081; |
/** |
* Alternate Thumbnail Offset. Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2 = 0x0088; |
/** |
* Length of thumbnail in bytes. Used by Konica / Minolta cameras. |
*/ |
public static final int TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH = 0x0089; |
/** |
* Used by Konica / Minolta cameras |
* 0 = Natural Colour |
* 1 = Black & White |
* 2 = Vivid colour |
* 3 = Solarization |
* 4 = AdobeRGB |
*/ |
public static final int TAG_OLYMPUS_COLOUR_MODE = 0x0101; |
/** |
* Used by Konica / Minolta cameras. |
* 0 = Raw |
* 1 = Super Fine |
* 2 = Fine |
* 3 = Standard |
* 4 = Extra Fine |
*/ |
public static final int TAG_OLYMPUS_IMAGE_QUALITY_1 = 0x0102; |
/** |
* Not 100% sure about this tag. |
* |
* Used by Konica / Minolta cameras. |
* 0 = Raw |
* 1 = Super Fine |
* 2 = Fine |
* 3 = Standard |
* 4 = Extra Fine |
*/ |
public static final int TAG_OLYMPUS_IMAGE_QUALITY_2 = 0x0103; |
/** |
* Three values: |
* Value 1: 0=Normal, 2=Fast, 3=Panorama |
* Value 2: Sequence Number Value 3: |
* 1 = Panorama Direction: Left to Right |
* 2 = Panorama Direction: Right to Left |
* 3 = Panorama Direction: Bottom to Top |
* 4 = Panorama Direction: Top to Bottom |
*/ |
public static final int TAG_OLYMPUS_SPECIAL_MODE = 0x0200; |
/** |
* 1 = Standard Quality |
* 2 = High Quality |
* 3 = Super High Quality |
*/ |
public static final int TAG_OLYMPUS_JPEG_QUALITY = 0x0201; |
/** |
* 0 = Normal (Not Macro) |
* 1 = Macro |
*/ |
public static final int TAG_OLYMPUS_MACRO_MODE = 0x0202; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_UNKNOWN_1 = 0x0203; |
/** |
* Zoom Factor (0 or 1 = normal) |
*/ |
public static final int TAG_OLYMPUS_DIGI_ZOOM_RATIO = 0x0204; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_UNKNOWN_2 = 0x0205; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_UNKNOWN_3 = 0x0206; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FIRMWARE_VERSION = 0x0207; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_PICT_INFO = 0x0208; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_CAMERA_ID = 0x0209; |
/** |
* Used by Epson cameras |
* Units = pixels |
*/ |
public static final int TAG_OLYMPUS_IMAGE_WIDTH = 0x020B; |
/** |
* Used by Epson cameras |
* Units = pixels |
*/ |
public static final int TAG_OLYMPUS_IMAGE_HEIGHT = 0x020C; |
/** |
* A string. Used by Epson cameras. |
*/ |
public static final int TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL = 0x020D; |
/** |
* See the PIM specification here: |
* http://www.ozhiker.com/electronics/pjmt/jpeg_info/pim.html |
*/ |
public static final int TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO = 0x0E00; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_DATA_DUMP = 0x0F00; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FLASH_MODE = 0x1004; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_BRACKET = 0x1006; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FOCUS_MODE = 0x100B; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FOCUS_DISTANCE = 0x100C; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_ZOOM = 0x100D; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_MACRO_FOCUS = 0x100E; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_SHARPNESS = 0x100F; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_COLOUR_MATRIX = 0x1011; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_BLACK_LEVEL = 0x1012; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_WHITE_BALANCE = 0x1015; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_RED_BIAS = 0x1017; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_BLUE_BIAS = 0x1018; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_SERIAL_NUMBER = 0x101A; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FLASH_BIAS = 0x1023; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_CONTRAST = 0x1029; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_SHARPNESS_FACTOR = 0x102A; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_COLOUR_CONTROL = 0x102B; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_VALID_BITS = 0x102C; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_CORING_FILTER = 0x102D; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FINAL_WIDTH = 0x102E; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_FINAL_HEIGHT = 0x102F; |
/** |
* |
*/ |
public static final int TAG_OLYMPUS_COMPRESSION_RATIO = 0x1034; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_OLYMPUS_SPECIAL_MODE), "Special Mode"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_JPEG_QUALITY), "Jpeg Quality"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_MODE), "Macro"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_1), "Makernote Unknown 1"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_DIGI_ZOOM_RATIO), "DigiZoom Ratio"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_2), "Makernote Unknown 2"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_UNKNOWN_3), "Makernote Unknown 3"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FIRMWARE_VERSION), "Firmware Version"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_PICT_INFO), "Pict Info"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_ID), "Camera Id"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_DATA_DUMP), "Data Dump"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MAKERNOTE_VERSION), "Makernote Version"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_1), "Camera Settings"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_CAMERA_SETTINGS_2), "Camera Settings"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSED_IMAGE_SIZE), "Compressed Image Size"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_1), "Thumbnail Offset"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_OFFSET_2), "Thumbnail Offset"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MINOLTA_THUMBNAIL_LENGTH), "Thumbnail Length"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MODE), "Colour Mode"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_1), "Image Quality"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_QUALITY_2), "Image Quality"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_IMAGE_HEIGHT), "Image Height"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_ORIGINAL_MANUFACTURER_MODEL), "Original Manufacturer Model"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_MODE), "Flash Mode"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_BRACKET), "Bracket"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_MODE), "Focus Mode"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FOCUS_DISTANCE), "Focus Distance"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_ZOOM), "Zoom"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_MACRO_FOCUS), "Macro Focus"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS), "Sharpness"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_MATRIX), "Colour Matrix"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_BLACK_LEVEL), "Black Level"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_WHITE_BALANCE), "White Balance"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_RED_BIAS), "Red Bias"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_BLUE_BIAS), "Blue Bias"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_SERIAL_NUMBER), "Serial Number"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FLASH_BIAS), "Flash Bias"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_CONTRAST), "Contrast"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_SHARPNESS_FACTOR), "Sharpness Factor"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_COLOUR_CONTROL), "Colour Control"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_VALID_BITS), "Valid Bits"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_CORING_FILTER), "Coring Filter"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_WIDTH), "Final Width"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_FINAL_HEIGHT), "Final Height"); |
tagNameMap.put(new Integer(TAG_OLYMPUS_COMPRESSION_RATIO), "Compression Ratio"); |
} |
public OlympusMakernoteDirectory() |
{ |
this.setDescriptor(new OlympusMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Olympus Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/PanasonicMakernoteDirectory.java |
---|
0,0 → 1,68 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 27-Nov-2002 10:10:47 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class PanasonicMakernoteDirectory extends Directory |
{ |
public static final int TAG_PANASONIC_QUALITY_MODE = 0x0001; |
public static final int TAG_PANASONIC_VERSION = 0x0002; |
/** |
* 1 = On |
* 2 = Off |
*/ |
public static final int TAG_PANASONIC_MACRO_MODE = 0x001C; |
/** |
* 1 = Normal |
* 2 = Portrait |
* 9 = Macro |
*/ |
public static final int TAG_PANASONIC_RECORD_MODE = 0x001F; |
public static final int TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO = 0x0E00; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_PANASONIC_QUALITY_MODE), "Quality Mode"); |
tagNameMap.put(new Integer(TAG_PANASONIC_VERSION), "Version"); |
tagNameMap.put(new Integer(TAG_PANASONIC_MACRO_MODE), "Macro Mode"); |
tagNameMap.put(new Integer(TAG_PANASONIC_RECORD_MODE), "Record Mode"); |
tagNameMap.put(new Integer(TAG_PANASONIC_PRINT_IMAGE_MATCHING_INFO), "Print Image Matching (PIM) Info"); |
} |
public PanasonicMakernoteDirectory() |
{ |
this.setDescriptor(new PanasonicMakernoteDescriptor(this)); |
} |
public String getName() |
{ |
return "Panasonic Makernote"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType1MakernoteDescriptor.java |
---|
0,0 → 1,197 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a NikonType1MakernoteDirectory. |
* Type-1 is for E-Series cameras prior to (not including) E990. For example: E700, E800, E900, |
* E900S, E910, E950. |
* |
* MakerNote starts from ASCII string "Nikon". Data format is the same as IFD, but it starts from |
* offset 0x08. This is the same as Olympus except start string. Example of actual data |
* structure is shown below. |
* <pre><code> |
* :0000: 4E 69 6B 6F 6E 00 01 00-05 00 02 00 02 00 06 00 Nikon........... |
* :0010: 00 00 EC 02 00 00 03 00-03 00 01 00 00 00 06 00 ................ |
* </code></pre> |
*/ |
public class NikonType1MakernoteDescriptor extends TagDescriptor |
{ |
public NikonType1MakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) { |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY: |
return getQualityDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE: |
return getColorModeDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT: |
return getImageAdjustmentDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY: |
return getCcdSensitivityDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE: |
return getWhiteBalanceDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS: |
return getFocusDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM: |
return getDigitalZoomDescription(); |
case NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER: |
return getConverterDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getConverterDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CONVERTER); |
switch (value) { |
case 0: |
return "None"; |
case 1: |
return "Fisheye converter"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getDigitalZoomDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM)) return null; |
Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_DIGITAL_ZOOM); |
if (value.getNumerator() == 0) { |
return "No digital zoom"; |
} |
return value.toSimpleString(true) + "x digital zoom"; |
} |
public String getFocusDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS)) return null; |
Rational value = _directory.getRational(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_FOCUS); |
if (value.getNumerator() == 1 && value.getDenominator() == 0) { |
return "Infinite"; |
} |
return value.toSimpleString(true); |
} |
public String getWhiteBalanceDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_WHITE_BALANCE); |
switch (value) { |
case 0: |
return "Auto"; |
case 1: |
return "Preset"; |
case 2: |
return "Daylight"; |
case 3: |
return "Incandescense"; |
case 4: |
return "Flourescence"; |
case 5: |
return "Cloudy"; |
case 6: |
return "SpeedLight"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getCcdSensitivityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_CCD_SENSITIVITY); |
switch (value) { |
case 0: |
return "ISO80"; |
case 2: |
return "ISO160"; |
case 4: |
return "ISO320"; |
case 5: |
return "ISO100"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getImageAdjustmentDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_IMAGE_ADJUSTMENT); |
switch (value) { |
case 0: |
return "Normal"; |
case 1: |
return "Bright +"; |
case 2: |
return "Bright -"; |
case 3: |
return "Contrast +"; |
case 4: |
return "Contrast -"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getColorModeDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_COLOR_MODE); |
switch (value) { |
case 1: |
return "Color"; |
case 2: |
return "Monochrome"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
public String getQualityDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY)) return null; |
int value = _directory.getInt(NikonType1MakernoteDirectory.TAG_NIKON_TYPE1_QUALITY); |
switch (value) { |
case 1: |
return "VGA Basic"; |
case 2: |
return "VGA Normal"; |
case 3: |
return "VGA Fine"; |
case 4: |
return "SXGA Basic"; |
case 5: |
return "SXGA Normal"; |
case 6: |
return "SXGA Fine"; |
default: |
return "Unknown (" + value + ")"; |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/NikonType2MakernoteDescriptor.java |
---|
0,0 → 1,169 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.exif; |
import com.drew.lang.Rational; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
import java.text.DecimalFormat; |
/** |
* Provides human-readable string versions of the tags stored in a NikonType2MakernoteDirectory. |
* Type-2 applies to the E990 and D-series cameras such as the D1, D70 and D100. |
*/ |
public class NikonType2MakernoteDescriptor extends TagDescriptor |
{ |
public NikonType2MakernoteDescriptor(Directory directory) |
{ |
super(directory); |
} |
private NikonType2MakernoteDirectory getMakernoteDirectory() |
{ |
return (NikonType2MakernoteDirectory)_directory; |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) |
{ |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS: |
return getLensDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT: |
return getHueAdjustmentDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE: |
return getColorModeDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AUTO_FLASH_COMPENSATION: |
return getAutoFlashCompensationDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1: |
return getIsoSettingDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM: |
return getDigitalZoomDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION: |
return getAutoFocusPositionDescription(); |
case NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION: |
return getAutoFirmwareVersionDescription(); |
default: |
return _directory.getString(tagType); |
} |
} |
public String getAutoFocusPositionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION)) return null; |
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION); |
if (values.length != 4 || values[0] != 0 || values[2] != 0 || values[3] != 0) { |
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_AF_FOCUS_POSITION) + ")"; |
} |
switch (values[1]) { |
case 0: |
return "Centre"; |
case 1: |
return "Top"; |
case 2: |
return "Bottom"; |
case 3: |
return "Left"; |
case 4: |
return "Right"; |
default: |
return "Unknown (" + values[1] + ")"; |
} |
} |
public String getDigitalZoomDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM)) return null; |
Rational rational = _directory.getRational(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_DIGITAL_ZOOM); |
if (rational.intValue() == 1) { |
return "No digital zoom"; |
} |
return rational.toSimpleString(true) + "x digital zoom"; |
} |
public String getIsoSettingDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1)) return null; |
int[] values = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1); |
if (values[0] != 0 || values[1] == 0) { |
return "Unknown (" + _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_ISO_1) + ")"; |
} |
return "ISO " + values[1]; |
} |
public String getAutoFlashCompensationDescription() throws MetadataException |
{ |
Rational ev = getMakernoteDirectory().getAutoFlashCompensation(); |
if (ev==null) |
return "Unknown"; |
DecimalFormat decimalFormat = new DecimalFormat("0.##"); |
return decimalFormat.format(ev.floatValue()) + " EV"; |
} |
public String getLensDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS)) |
return null; |
Rational[] lensValues = _directory.getRationalArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS); |
if (lensValues.length!=4) |
return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_LENS); |
StringBuffer description = new StringBuffer(); |
description.append(lensValues[0].intValue()); |
description.append('-'); |
description.append(lensValues[1].intValue()); |
description.append("mm f/"); |
description.append(lensValues[2].floatValue()); |
description.append('-'); |
description.append(lensValues[3].floatValue()); |
return description.toString(); |
} |
public String getHueAdjustmentDescription() |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT)) |
return null; |
return _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_HUE_ADJUSTMENT) + " degrees"; |
} |
public String getColorModeDescription() |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE)) |
return null; |
String raw = _directory.getString(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_CAMERA_COLOR_MODE); |
if (raw.startsWith("MODE1")) |
return "Mode I (sRGB)"; |
return raw; |
} |
public String getAutoFirmwareVersionDescription() throws MetadataException |
{ |
if (!_directory.containsTag(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION)) |
return null; |
int[] ints = _directory.getIntArray(NikonType2MakernoteDirectory.TAG_NIKON_TYPE2_FIRMWARE_VERSION); |
return ExifDescriptor.convertBytesToVersionString(ints); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/exif/ExifProcessingException.java |
---|
0,0 → 1,50 |
/* |
* ExifProcessingException.java |
* |
* This class is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on 29 April 2002, 00:33 |
*/ |
package com.drew.metadata.exif; |
import com.drew.metadata.MetadataException; |
/** |
* The exception type raised during reading of Exif data in the instance of |
* unexpected data conditions. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class ExifProcessingException extends MetadataException |
{ |
/** |
* Constructs an instance of <code>ExifProcessingException</code> with the |
* specified detail message. |
* @param message the detail message |
*/ |
public ExifProcessingException(String message) |
{ |
super(message); |
} |
/** |
* Constructs an instance of <code>ExifProcessingException</code> with the |
* specified detail message and inner exception. |
* @param message the detail message |
* @param cause an inner exception |
*/ |
public ExifProcessingException(String message, Throwable cause) |
{ |
super(message, cause); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/DefaultTagDescriptor.java |
---|
0,0 → 1,40 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 22-Nov-2002 16:45:19 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
/** |
* |
*/ |
public class DefaultTagDescriptor extends TagDescriptor |
{ |
public DefaultTagDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getTagName(int tagType) |
{ |
String hex = Integer.toHexString(tagType).toUpperCase(); |
while (hex.length() < 4) hex = "0" + hex; |
return "Unknown tag 0x" + hex; |
} |
public String getDescription(int tagType) |
{ |
return _directory.getString(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/MetadataException.java |
---|
0,0 → 1,40 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 13-Nov-2002 18:10:23 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
import com.drew.lang.CompoundException; |
/** |
* |
*/ |
public class MetadataException extends CompoundException |
{ |
public MetadataException(String msg) |
{ |
super(msg); |
} |
public MetadataException(Throwable exception) |
{ |
super(exception); |
} |
public MetadataException(String msg, Throwable innerException) |
{ |
super(msg, innerException); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/id3/test/TestTrack01-Artwork.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcDirectory.java |
---|
0,0 → 1,97 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Nov-2002 01:26:39 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.iptc; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
*/ |
public class IptcDirectory extends Directory |
{ |
public static final int TAG_RECORD_VERSION = 0x0200; |
public static final int TAG_CAPTION = 0x0278; |
public static final int TAG_WRITER = 0x027a; |
public static final int TAG_HEADLINE = 0x0269; |
public static final int TAG_SPECIAL_INSTRUCTIONS = 0x0228; |
public static final int TAG_BY_LINE = 0x0250; |
public static final int TAG_BY_LINE_TITLE = 0x0255; |
public static final int TAG_CREDIT = 0x026e; |
public static final int TAG_SOURCE = 0x0273; |
public static final int TAG_OBJECT_NAME = 0x0205; |
public static final int TAG_DATE_CREATED = 0x0237; |
public static final int TAG_CITY = 0x025a; |
public static final int TAG_PROVINCE_OR_STATE = 0x025f; |
public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION = 0x0265; |
public static final int TAG_ORIGINAL_TRANSMISSION_REFERENCE = 0x0267; |
public static final int TAG_CATEGORY = 0x020f; |
public static final int TAG_SUPPLEMENTAL_CATEGORIES = 0x0214; |
public static final int TAG_URGENCY = 0x0200 | 10; |
public static final int TAG_KEYWORDS = 0x0200 | 25; |
public static final int TAG_COPYRIGHT_NOTICE = 0x0274; |
public static final int TAG_RELEASE_DATE = 0x0200 | 30; |
public static final int TAG_RELEASE_TIME = 0x0200 | 35; |
public static final int TAG_TIME_CREATED = 0x0200 | 60; |
public static final int TAG_ORIGINATING_PROGRAM = 0x0200 | 65; |
protected static final HashMap tagNameMap = new HashMap(); |
static |
{ |
tagNameMap.put(new Integer(TAG_RECORD_VERSION), "Directory Version"); |
tagNameMap.put(new Integer(TAG_CAPTION), "Caption/Abstract"); |
tagNameMap.put(new Integer(TAG_WRITER), "Writer/Editor"); |
tagNameMap.put(new Integer(TAG_HEADLINE), "Headline"); |
tagNameMap.put(new Integer(TAG_SPECIAL_INSTRUCTIONS), "Special Instructions"); |
tagNameMap.put(new Integer(TAG_BY_LINE), "By-line"); |
tagNameMap.put(new Integer(TAG_BY_LINE_TITLE), "By-line Title"); |
tagNameMap.put(new Integer(TAG_CREDIT), "Credit"); |
tagNameMap.put(new Integer(TAG_SOURCE), "Source"); |
tagNameMap.put(new Integer(TAG_OBJECT_NAME), "Object Name"); |
tagNameMap.put(new Integer(TAG_DATE_CREATED), "Date Created"); |
tagNameMap.put(new Integer(TAG_CITY), "City"); |
tagNameMap.put(new Integer(TAG_PROVINCE_OR_STATE), "Province/State"); |
tagNameMap.put(new Integer(TAG_COUNTRY_OR_PRIMARY_LOCATION), "Country/Primary Location"); |
tagNameMap.put(new Integer(TAG_ORIGINAL_TRANSMISSION_REFERENCE), "Original Transmission Reference"); |
tagNameMap.put(new Integer(TAG_CATEGORY), "Category"); |
tagNameMap.put(new Integer(TAG_SUPPLEMENTAL_CATEGORIES), "Supplemental Category(s)"); |
tagNameMap.put(new Integer(TAG_URGENCY), "Urgency"); |
tagNameMap.put(new Integer(TAG_KEYWORDS), "Keywords"); |
tagNameMap.put(new Integer(TAG_COPYRIGHT_NOTICE), "Copyright Notice"); |
tagNameMap.put(new Integer(TAG_RELEASE_DATE), "Release Date"); |
tagNameMap.put(new Integer(TAG_RELEASE_TIME), "Release Time"); |
tagNameMap.put(new Integer(TAG_TIME_CREATED), "Time Created"); |
tagNameMap.put(new Integer(TAG_ORIGINATING_PROGRAM), "Originating Program"); |
} |
public IptcDirectory() |
{ |
this.setDescriptor(new IptcDescriptor(this)); |
} |
public String getName() |
{ |
return "Iptc"; |
} |
protected HashMap getTagNameMap() |
{ |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcProcessingException.java |
---|
0,0 → 1,51 |
/* |
* ExifProcessingException.java |
* |
* This class is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on 29 April 2002, 00:33 |
*/ |
package com.drew.metadata.iptc; |
import com.drew.metadata.MetadataException; |
/** |
* The exception type raised during reading of Iptc data in the instance of |
* unexpected data conditions. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class IptcProcessingException extends MetadataException |
{ |
/** |
* Constructs an instance of <code>ExifProcessingException</code> with the |
* specified detail message. |
* @param message the detail message |
*/ |
public IptcProcessingException(String message) |
{ |
super(message); |
} |
/** |
* Constructs an instance of <code>IptcProcessingException</code> with the |
* specified detail message and inner exception. |
* @param message the detail message |
* @param cause an inner exception |
*/ |
public IptcProcessingException(String message, Throwable cause) |
{ |
super(message, cause); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcDescriptor.java |
---|
0,0 → 1,36 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 21-Nov-2002 17:58:19 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.iptc; |
import com.drew.metadata.Directory; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
*/ |
public class IptcDescriptor extends TagDescriptor |
{ |
public IptcDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) |
{ |
return _directory.getString(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/withIptc.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/IptcReaderTest.java |
---|
0,0 → 1,69 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 22-Nov-2002 08:26:26 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.iptc.test; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataReader; |
import com.drew.metadata.iptc.IptcDirectory; |
import com.drew.metadata.iptc.IptcReader; |
import junit.framework.TestCase; |
import java.io.File; |
/** |
* |
*/ |
public class IptcReaderTest extends TestCase |
{ |
public IptcReaderTest(String s) |
{ |
super(s); |
} |
public void testDescription_City() throws Exception |
{ |
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg"); |
MetadataReader reader = new IptcReader(iptcFile); |
Metadata metadata = reader.extract(); |
assertTrue(metadata.containsDirectory(IptcDirectory.class)); |
Directory directory = metadata.getDirectory(IptcDirectory.class); |
assertEquals("City", directory.getDescription(IptcDirectory.TAG_CITY)); |
} |
public void testDescription_Caption() throws Exception |
{ |
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg"); |
MetadataReader reader = new IptcReader(iptcFile); |
Metadata metadata = reader.extract(); |
assertTrue(metadata.containsDirectory(IptcDirectory.class)); |
Directory directory = metadata.getDirectory(IptcDirectory.class); |
assertEquals("Caption", directory.getDescription(IptcDirectory.TAG_CAPTION)); |
} |
public void testDescription_Category() throws Exception |
{ |
File iptcFile = new File("src/com/drew/metadata/iptc/test/withIptc.jpg"); |
MetadataReader reader = new IptcReader(iptcFile); |
Metadata metadata = reader.extract(); |
assertTrue(metadata.containsDirectory(IptcDirectory.class)); |
Directory directory = metadata.getDirectory(IptcDirectory.class); |
assertEquals("Supl. Category2 Supl. Category1 Cat", directory.getDescription(IptcDirectory.TAG_CATEGORY)); |
} |
// TODO Wrap more tests around the Iptc reader |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/test/withIptcPhotoshop6.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/iptc/IptcReader.java |
---|
0,0 → 1,225 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 12-Nov-2002 19:00:03 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.iptc; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.MetadataReader; |
import java.io.File; |
import java.io.InputStream; |
import java.util.Date; |
/** |
* |
*/ |
public class IptcReader implements MetadataReader |
{ |
/* |
public static final int DIRECTORY_IPTC = 2; |
public static final int ENVELOPE_RECORD = 1; |
public static final int APPLICATION_RECORD_2 = 2; |
public static final int APPLICATION_RECORD_3 = 3; |
public static final int APPLICATION_RECORD_4 = 4; |
public static final int APPLICATION_RECORD_5 = 5; |
public static final int APPLICATION_RECORD_6 = 6; |
public static final int PRE_DATA_RECORD = 7; |
public static final int DATA_RECORD = 8; |
public static final int POST_DATA_RECORD = 9; |
*/ |
/** |
* The Iptc data segment. |
*/ |
private final byte[] _data; |
/** |
* Creates a new IptcReader for the specified Jpeg jpegFile. |
*/ |
public IptcReader(File jpegFile) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_APPD)); |
} |
/** Creates an IptcReader for a JPEG stream. |
* |
* @param is JPEG stream. Stream will be closed. |
*/ |
public IptcReader(InputStream is) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD)); |
} |
public IptcReader(byte[] data) |
{ |
_data = data; |
} |
/** |
* Performs the Exif data extraction, returning a new instance of <code>Metadata</code>. |
*/ |
public Metadata extract() |
{ |
return extract(new Metadata()); |
} |
/** |
* Performs the Exif data extraction, adding found values to the specified |
* instance of <code>Metadata</code>. |
*/ |
public Metadata extract(Metadata metadata) |
{ |
if (_data == null) { |
return metadata; |
} |
Directory directory = metadata.getDirectory(IptcDirectory.class); |
// find start of data |
int offset = 0; |
try { |
while (offset < _data.length - 1 && get32Bits(offset) != 0x1c02) { |
offset++; |
} |
} catch (MetadataException e) { |
directory.addError("Couldn't find start of Iptc data (invalid segment)"); |
return metadata; |
} |
// for each tag |
while (offset < _data.length) { |
// identifies start of a tag |
if (_data[offset] != 0x1c) { |
break; |
} |
// we need at least five bytes left to read a tag |
if ((offset + 5) >= _data.length) { |
break; |
} |
offset++; |
int directoryType; |
int tagType; |
int tagByteCount; |
try { |
directoryType = _data[offset++]; |
tagType = _data[offset++]; |
tagByteCount = get32Bits(offset); |
} catch (MetadataException e) { |
directory.addError("Iptc data segment ended mid-way through tag descriptor"); |
return metadata; |
} |
offset += 2; |
if ((offset + tagByteCount) > _data.length) { |
directory.addError("data for tag extends beyond end of iptc segment"); |
break; |
} |
processTag(directory, directoryType, tagType, offset, tagByteCount); |
offset += tagByteCount; |
} |
return metadata; |
} |
/** |
* Returns an int calculated from two bytes of data at the specified offset (MSB, LSB). |
* @param offset position within the data buffer to read first byte |
* @return the 32 bit int value, between 0x0000 and 0xFFFF |
*/ |
private int get32Bits(int offset) throws MetadataException |
{ |
if (offset >= _data.length) { |
throw new MetadataException("Attempt to read bytes from outside Iptc data buffer"); |
} |
return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255); |
} |
/** |
* This method serves as marsheller of objects for dataset. It converts from IPTC |
* octets to relevant java object. |
*/ |
private void processTag(Directory directory, int directoryType, int tagType, int offset, int tagByteCount) |
{ |
int tagIdentifier = tagType | (directoryType << 8); |
switch (tagIdentifier) { |
case IptcDirectory.TAG_RECORD_VERSION: |
// short |
short shortValue = (short)((_data[offset] << 8) | _data[offset + 1]); |
directory.setInt(tagIdentifier, shortValue); |
return; |
case IptcDirectory.TAG_URGENCY: |
// byte |
directory.setInt(tagIdentifier, _data[offset]); |
return; |
case IptcDirectory.TAG_RELEASE_DATE: |
case IptcDirectory.TAG_DATE_CREATED: |
// Date object |
if (tagByteCount >= 8) { |
String dateStr = new String(_data, offset, tagByteCount); |
try { |
int year = Integer.parseInt(dateStr.substring(0, 4)); |
int month = Integer.parseInt(dateStr.substring(4, 6)) - 1; |
int day = Integer.parseInt(dateStr.substring(6, 8)); |
Date date = (new java.util.GregorianCalendar(year, month, day)).getTime(); |
directory.setDate(tagIdentifier, date); |
return; |
} catch (NumberFormatException e) { |
// fall through and we'll store whatever was there as a String |
} |
} |
case IptcDirectory.TAG_RELEASE_TIME: |
case IptcDirectory.TAG_TIME_CREATED: |
// time... |
default: |
// fall through |
} |
// If no special handling by now, treat it as a string |
String str; |
if (tagByteCount < 1) { |
str = ""; |
} else { |
str = new String(_data, offset, tagByteCount); |
} |
if (directory.containsTag(tagIdentifier)) { |
String[] oldStrings; |
String[] newStrings; |
try { |
oldStrings = directory.getStringArray(tagIdentifier); |
} catch (MetadataException e) { |
oldStrings = null; |
} |
if (oldStrings == null) { |
newStrings = new String[1]; |
} else { |
newStrings = new String[oldStrings.length + 1]; |
for (int i = 0; i < oldStrings.length; i++) { |
newStrings[i] = oldStrings[i]; |
} |
} |
newStrings[newStrings.length - 1] = str; |
directory.setStringArray(tagIdentifier, newStrings); |
} else { |
directory.setString(tagIdentifier, str); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/MetadataTest.java |
---|
0,0 → 1,176 |
/* |
* MetadataTest.java |
* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Oct-2002 18:35:12 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.lang.NullOutputStream; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.exif.ExifDirectory; |
import com.drew.metadata.exif.GpsDirectory; |
import com.drew.metadata.iptc.IptcDirectory; |
import junit.framework.TestCase; |
import java.io.*; |
import java.util.Iterator; |
/** |
* JUnit test case for class Metadata. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class MetadataTest extends TestCase |
{ |
public MetadataTest(String s) |
{ |
super(s); |
} |
public void testSetAndGetSingleTag() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
directory.setInt(ExifDirectory.TAG_APERTURE, 1); |
assertEquals(1, directory.getInt(ExifDirectory.TAG_APERTURE)); |
} |
public void testSetSameTagMultpleTimes() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(ExifDirectory.class); |
directory.setInt(ExifDirectory.TAG_APERTURE, 1); |
directory.setInt(ExifDirectory.TAG_APERTURE, 2); |
assertEquals("setting the tag with a different value should override old value", |
2, directory.getInt(ExifDirectory.TAG_APERTURE)); |
} |
public void testGetDirectory() throws Exception |
{ |
Metadata metadata = new Metadata(); |
assertTrue(metadata.getDirectory(ExifDirectory.class) instanceof ExifDirectory); |
} |
public void testSetAndGetMultipleTagsInSingleDirectory() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory exifDir = metadata.getDirectory(ExifDirectory.class); |
exifDir.setString(ExifDirectory.TAG_APERTURE, "Tag Value"); |
exifDir.setString(ExifDirectory.TAG_BATTERY_LEVEL, "Another tag"); |
assertEquals("Tag Value", exifDir.getString(ExifDirectory.TAG_APERTURE)); |
assertEquals("Another tag", exifDir.getString(ExifDirectory.TAG_BATTERY_LEVEL)); |
} |
public void testSetAndGetMultipleTagsInMultilpeDirectories() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory exifDir = metadata.getDirectory(ExifDirectory.class); |
Directory gpsDir = metadata.getDirectory(GpsDirectory.class); |
exifDir.setString(ExifDirectory.TAG_APERTURE, "ExifAperture"); |
exifDir.setString(ExifDirectory.TAG_BATTERY_LEVEL, "ExifBatteryLevel"); |
gpsDir.setString(GpsDirectory.TAG_GPS_ALTITUDE, "GpsAltitude"); |
gpsDir.setString(GpsDirectory.TAG_GPS_DEST_BEARING, "GpsDestBearing"); |
assertEquals("ExifAperture", exifDir.getString(ExifDirectory.TAG_APERTURE)); |
assertEquals("ExifBatteryLevel", exifDir.getString(ExifDirectory.TAG_BATTERY_LEVEL)); |
assertEquals("GpsAltitude", gpsDir.getString(GpsDirectory.TAG_GPS_ALTITUDE)); |
assertEquals("GpsDestBearing", gpsDir.getString(GpsDirectory.TAG_GPS_DEST_BEARING)); |
} |
/* |
public void testCountTags() throws Exception |
{ |
Metadata info = new Metadata(); |
assertEquals(0, info.countTags()); |
info.setString(ExifReader.DIRECTORY_EXIF_EXIF, ExifDirectory.TAG_APERTURE, "ExifAperture"); |
assertEquals(1, info.countTags()); |
info.setString(ExifReader.DIRECTORY_EXIF_EXIF, ExifDirectory.TAG_BATTERY_LEVEL, "ExifBatteryLevel"); |
assertEquals(2, info.countTags()); |
info.setString(ExifReader.DIRECTORY_EXIF_GPS, GpsDirectory.TAG_GPS_ALTITUDE, "GpsAltitude"); |
assertEquals(3, info.countTags()); |
info.setString(ExifReader.DIRECTORY_EXIF_GPS, GpsDirectory.TAG_GPS_DEST_BEARING, "GpsDestBearing"); |
assertEquals(4, info.countTags()); |
} |
*/ |
public void testContainsTag() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory exifDir = metadata.getDirectory(ExifDirectory.class); |
assertTrue(!exifDir.containsTag(ExifDirectory.TAG_APERTURE)); |
exifDir.setString(ExifDirectory.TAG_APERTURE, "Tag Value"); |
assertTrue(exifDir.containsTag(ExifDirectory.TAG_APERTURE)); |
} |
public void testGetNonExistantTag() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory exifDir = metadata.getDirectory(ExifDirectory.class); |
assertEquals(null, exifDir.getString(ExifDirectory.TAG_APERTURE)); |
} |
public void testHasErrors() throws Exception |
{ |
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg")); |
assertTrue("exif error", metadata.getDirectory(ExifDirectory.class).hasErrors()); |
metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/withExif.jpg")); |
assertTrue("no errors", !metadata.getDirectory(ExifDirectory.class).hasErrors()); |
} |
public void testGetErrors() throws Exception |
{ |
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg")); |
Iterator errors = metadata.getDirectory(ExifDirectory.class).getErrors(); |
assertTrue(errors.hasNext()); |
String error = (String) errors.next(); |
assertEquals("Exif data segment must contain at least 14 bytes", error); |
assertTrue(!errors.hasNext()); |
} |
public void testGetErrorCount() throws Exception |
{ |
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/exif/test/badExif.jpg")); |
assertEquals(1, metadata.getDirectory(ExifDirectory.class).getErrorCount()); |
} |
public void testMetadataSerializable() throws Exception |
{ |
Metadata metadata = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/test/withIptcExifGps.jpg")); |
new ObjectOutputStream(new NullOutputStream()).writeObject(metadata); |
} |
public void testSerializeAndRestore() throws Exception |
{ |
Metadata metadataWrite = JpegMetadataReader.readMetadata(new File("src/com/drew/metadata/test/withIptcExifGps.jpg")); |
Metadata metadataRead; |
File ser = File.createTempFile("test", "ser"); |
try { |
// write the ser object |
new ObjectOutputStream(new FileOutputStream(ser)).writeObject(metadataWrite); |
// read the ser object |
metadataRead = (Metadata)new ObjectInputStream(new FileInputStream(ser)).readObject(); |
// make sure they're equivalent |
// TODO should compare the two objects via iteration of directories and tags |
assertTrue(metadataRead.containsDirectory(ExifDirectory.class)); |
assertTrue(metadataRead.containsDirectory(IptcDirectory.class)); |
} finally { |
ser.delete(); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/withIptcExifGps.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/SpecialTests.java |
---|
0,0 → 1,121 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 07-May-2005 12:38:18 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.test; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentData; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import junit.framework.TestCase; |
import java.io.File; |
import java.io.FileOutputStream; |
import java.io.ObjectOutputStream; |
/** |
* |
*/ |
public class SpecialTests extends TestCase |
{ |
public void testExtractMetadataToASeparateFile() throws Exception |
{ |
String filename = "src/com/drew/metadata/exif/test/nikonMakernoteType2"; |
JpegSegmentData segmentData = new JpegSegmentReader(new File(filename + ".jpg")).getSegmentData(); |
segmentData.removeSegment(JpegSegmentReader.SEGMENT_DHT); |
segmentData.removeSegment(JpegSegmentReader.SEGMENT_DQT); |
segmentData.removeSegment(JpegSegmentReader.SEGMENT_SOF0); |
segmentData.removeSegment(JpegSegmentReader.SEGMENT_SOI); |
ObjectOutputStream outputStream = null; |
try |
{ |
outputStream = new ObjectOutputStream(new FileOutputStream(new File(filename + ".metadata"))); |
outputStream.writeObject(segmentData); |
} |
finally |
{ |
if (outputStream!=null) |
outputStream.close(); |
} |
} |
public void testScanFoldersForImagesThatCauseFailures() throws Exception |
{ |
// String directory = "G:/Recovered Images/AquariumC"; // 1446 files 883 MB (done) |
// String directory = "G:/Recovered Images/AquariumF"; // 25,378 files 34.4 GB |
// String directory = "G:/Recovered Images/DesktopC"; // 41,518 files 8.73 GB |
// String directory = "G:/Recovered Images/DesktopF"; // 8,016 files 5.11 GB (done) |
// String directory = "C:/Documents and Settings/Drew/My Documents/IntelliJ Projects/MetadataExtractor/src/"; |
// String directory = "C:/Documents and Settings/Drew/My Documents/IntelliJ Projects/MetadataExtractor/Sample Images"; |
String directory = "\\\\annie\\htdocs\\drewnoakes.com\\code\\exif\\exifImages"; |
processDirectory(directory); |
System.out.println("Complete test successfully."); |
} |
private void processDirectory(String pathName) |
{ |
File directory = new File(pathName); |
String[] directoryItems = directory.list(); |
if (directoryItems==null) |
return; |
for (int i=0; i<directoryItems.length; i++) { |
String subItem = directoryItems[i].toLowerCase(); |
File file = new File(directory, subItem); |
if (!file.exists()) |
throw new RuntimeException("World gone nuts."); |
if (file.isDirectory()) |
{ |
processDirectory(file.getAbsolutePath()); |
} |
else if (subItem.endsWith(".jpg") || subItem.endsWith(".jpeg")) |
{ |
// process this item |
try |
{ |
JpegSegmentReader segmentReader = new JpegSegmentReader(file); |
try |
{ |
JpegMetadataReader.extractMetadataFromJpegSegmentReader(segmentReader); |
} |
catch (Throwable t) |
{ |
// general, uncaught exception during processing of metadata |
System.err.println(file + "[BadMetadata]"); |
System.err.println(t); |
System.err.println(t.getMessage()); |
t.printStackTrace(System.err); |
} |
} |
catch (JpegProcessingException e) |
{ |
System.err.println(file + "[BadSegments]"); |
// this is an error in the Jpeg segment structure. we're looking for bad handling of |
// metadata segments. in this case, we didn't even get a segment. |
} |
catch (Throwable t) |
{ |
// general, uncaught exception during processing of jpeg segments |
System.err.println(file + "[FAILURE]"); |
System.err.println(t); |
System.err.println(t.getMessage()); |
t.printStackTrace(System.err); |
} |
} |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/DirectoryTest.java |
---|
0,0 → 1,109 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 29-Nov-2002 08:40:07 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.test; |
import com.drew.metadata.Directory; |
import com.drew.metadata.Metadata; |
import junit.framework.TestCase; |
import java.util.GregorianCalendar; |
/** |
* |
*/ |
public class DirectoryTest extends TestCase |
{ |
public DirectoryTest(String s) |
{ |
super(s); |
} |
public void testSetAndGetInt() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(MockDirectory.class); |
int value = 321; |
int tagType = 123; |
directory.setInt(tagType, value); |
assertEquals(value, directory.getInt(tagType)); |
assertEquals(Integer.toString(value), directory.getString(tagType)); |
} |
public void testSetAndGetIntArray() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(MockDirectory.class); |
int[] inputValues = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
int tagType = 123; |
directory.setIntArray(tagType, inputValues); |
int[] outputValues = directory.getIntArray(tagType); |
assertEquals(inputValues.length, outputValues.length); |
for (int i = 0; i < inputValues.length; i++) { |
int inputValue = inputValues[i]; |
int outputValue = outputValues[i]; |
assertEquals(inputValue, outputValue); |
} |
assertEquals(inputValues, directory.getIntArray(tagType)); |
StringBuffer outputString = new StringBuffer(); |
for (int i = 0; i < inputValues.length; i++) { |
int inputValue = inputValues[i]; |
if (i > 0) { |
outputString.append(' '); |
} |
outputString.append(inputValue); |
} |
assertEquals(outputString.toString(), directory.getString(tagType)); |
} |
public void testSetStringAndGetDate() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(MockDirectory.class); |
String date1 = "2002:01:30 24:59:59"; |
String date2 = "2002:01:30 24:59"; |
String date3 = "2002-01-30 24:59:59"; |
String date4 = "2002-01-30 24:59"; |
directory.setString(1, date1); |
directory.setString(2, date2); |
directory.setString(3, date3); |
directory.setString(4, date4); |
assertEquals(date1, directory.getString(1)); |
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 59).getTime(), directory.getDate(1)); |
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 0).getTime(), directory.getDate(2)); |
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 59).getTime(), directory.getDate(3)); |
assertEquals(new GregorianCalendar(2002, GregorianCalendar.JANUARY, 30, 24, 59, 0).getTime(), directory.getDate(4)); |
} |
public void testSetIntArrayGetByteArray() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(MockDirectory.class); |
int[] ints = {1, 2, 3, 4, 5}; |
directory.setIntArray(1, ints); |
assertEquals(ints.length, directory.getByteArray(1).length); |
assertEquals(1, directory.getByteArray(1)[0]); |
} |
public void testSetStringGetInt() throws Exception |
{ |
Metadata metadata = new Metadata(); |
Directory directory = metadata.getDirectory(MockDirectory.class); |
byte[] bytes = { 0x01, 0x02, 0x03 }; |
directory.setString(1, new String(bytes)); |
assertEquals(0x010203, directory.getInt(1)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/AllTests.java |
---|
0,0 → 1,75 |
/* |
* AllTests.java |
* |
* Test suite class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Oct-2002 16:29:44 using IntelliJ IDEA. |
* - First collection of basic unit tests, to compile against JUnit |
* - Doesn't yet cover all classes |
*/ |
package com.drew.metadata.test; |
import com.drew.imaging.jpeg.test.JpegMetadataReaderTest; |
import com.drew.imaging.jpeg.test.JpegSegmentDataTest; |
import com.drew.imaging.jpeg.test.JpegSegmentReaderTest; |
import com.drew.lang.test.CompoundExceptionTest; |
import com.drew.lang.test.NullOutputStreamTest; |
import com.drew.lang.test.RationalTest; |
import com.drew.metadata.exif.test.*; |
import com.drew.metadata.iptc.test.IptcReaderTest; |
import com.drew.metadata.jpeg.test.JpegComponentTest; |
import com.drew.metadata.jpeg.test.JpegDescriptorTest; |
import com.drew.metadata.jpeg.test.JpegDirectoryTest; |
import com.drew.metadata.jpeg.test.JpegReaderTest; |
import junit.framework.Test; |
import junit.framework.TestSuite; |
/** |
* The complete test suite for the metadata-extractor library. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class AllTests extends TestSuite |
{ |
public static Test suite() |
{ |
TestSuite suite = new TestSuite(); |
suite.addTestSuite(DirectoryTest.class); |
suite.addTestSuite(ExifDirectoryTest.class); |
suite.addTestSuite(ExifReaderTest.class); |
suite.addTestSuite(ExifDescriptorTest.class); |
suite.addTestSuite(IptcReaderTest.class); |
suite.addTestSuite(MetadataTest.class); |
suite.addTestSuite(JpegReaderTest.class); |
suite.addTestSuite(JpegSegmentDataTest.class); |
suite.addTestSuite(JpegDirectoryTest.class); |
suite.addTestSuite(JpegComponentTest.class); |
suite.addTestSuite(JpegDescriptorTest.class); |
suite.addTestSuite(NikonType1MakernoteTest.class); |
suite.addTestSuite(NikonType2MakernoteTest1.class); |
suite.addTestSuite(NikonType2MakernoteTest2.class); |
suite.addTestSuite(CanonMakernoteDescriptorTest.class); |
suite.addTestSuite(CompoundExceptionTest.class); |
suite.addTestSuite(NullOutputStreamTest.class); |
suite.addTestSuite(RationalTest.class); |
suite.addTestSuite(JpegMetadataReaderTest.class); |
suite.addTestSuite(JpegSegmentReaderTest.class); |
return suite; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/test/MockDirectory.java |
---|
0,0 → 1,41 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 29-Nov-2002 09:07:43 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.test; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
public class MockDirectory extends Directory |
{ |
private final HashMap _tagNameMap; |
public MockDirectory() |
{ |
this._tagNameMap = new HashMap(); |
} |
public String getName() |
{ |
return ""; |
} |
protected HashMap getTagNameMap() |
{ |
return _tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/Metadata.java |
---|
0,0 → 1,124 |
/* |
* Metadata.java |
* |
* This class is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. Similarly, I release this Java version under the |
* same license, though I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew.noakes@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on 28 April 2002, 17:40 |
* Modified 04 Aug 2002 |
* - Adjusted javadoc |
* - Added |
* Modified 29 Oct 2002 (v1.2) |
* - Stored IFD directories in separate tag-spaces |
* - iterator() now returns an Iterator over a list of TagValue objects |
* - More get*Description() methods to detail GPS tags, among others |
* - Put spaces between words of tag name for presentation reasons (they had no |
* significance in compound form) |
*/ |
package com.drew.metadata; |
import java.io.Serializable; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.Iterator; |
/** |
* Result from an exif extraction operation, containing all tags, their |
* values and support for retrieving them. |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public final class Metadata implements Serializable |
{ |
/** |
* |
*/ |
private final HashMap directoryMap; |
/** |
* List of Directory objects set against this object. Keeping a list handy makes |
* creation of an Iterator and counting tags simple. |
*/ |
private final ArrayList directoryList; |
/** |
* Creates a new instance of Metadata. Package private. |
*/ |
public Metadata() |
{ |
directoryMap = new HashMap(); |
directoryList = new ArrayList(); |
} |
// OTHER METHODS |
/** |
* Creates an Iterator over the tag types set against this image, preserving the order |
* in which they were set. Should the same tag have been set more than once, it's first |
* position is maintained, even though the final value is used. |
* @return an Iterator of tag types set for this image |
*/ |
public Iterator getDirectoryIterator() |
{ |
return directoryList.iterator(); |
} |
/** |
* Returns a count of unique directories in this metadata collection. |
* @return the number of unique directory types set for this metadata collection |
*/ |
public int getDirectoryCount() |
{ |
return directoryList.size(); |
} |
/** |
* Returns a <code>Directory</code> of specified type. If this <code>Metadata</code> object already contains |
* such a directory, it is returned. Otherwise a new instance of this directory will be created and stored within |
* this Metadata object. |
* @param type the type of the Directory implementation required. |
* @return a directory of the specified type. |
*/ |
public Directory getDirectory(Class type) |
{ |
if (!Directory.class.isAssignableFrom(type)) { |
throw new RuntimeException("Class type passed to getDirectory must be an implementation of com.drew.metadata.Directory"); |
} |
// check if we've already issued this type of directory |
if (directoryMap.containsKey(type)) { |
return (Directory)directoryMap.get(type); |
} |
Object directory; |
try { |
directory = type.newInstance(); |
} catch (Exception e) { |
throw new RuntimeException("Cannot instantiate provided Directory type: " + type.toString()); |
} |
// store the directory in case it's requested later |
directoryMap.put(type, directory); |
directoryList.add(directory); |
return (Directory)directory; |
} |
/** |
* Indicates whether a given directory type has been created in this metadata |
* repository. Directories are created by calling getDirectory(Class). |
* @param type the Directory type |
* @return true if the metadata directory has been created |
*/ |
public boolean containsDirectory(Class type) |
{ |
return directoryMap.containsKey(type); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/MetadataReader.java |
---|
0,0 → 1,27 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Nov-2002 11:21:43 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
/** |
* |
*/ |
public interface MetadataReader |
{ |
public Metadata extract(); |
public Metadata extract(Metadata metadata); |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/Directory.java |
---|
0,0 → 1,689 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 25-Nov-2002 20:30:39 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
import com.drew.lang.Rational; |
import java.io.Serializable; |
import java.lang.reflect.Array; |
import java.text.DateFormat; |
import java.util.ArrayList; |
import java.util.HashMap; |
import java.util.Iterator; |
import java.util.List; |
/** |
* Base class for all Metadata directory types with supporting methods for setting and |
* getting tag values. |
*/ |
public abstract class Directory implements Serializable |
{ |
/** |
* Map of values hashed by type identifiers. |
*/ |
protected final HashMap _tagMap; |
/** |
* The descriptor used to interperet tag values. |
*/ |
protected TagDescriptor _descriptor; |
/** |
* A convenient list holding tag values in the order in which they were stored. |
* This is used for creation of an iterator, and for counting the number of |
* defined tags. |
*/ |
protected final List _definedTagList; |
private List _errorList; |
// ABSTRACT METHODS |
/** |
* Provides the name of the directory, for display purposes. E.g. <code>Exif</code> |
* @return the name of the directory |
*/ |
public abstract String getName(); |
/** |
* Provides the map of tag names, hashed by tag type identifier. |
* @return the map of tag names |
*/ |
protected abstract HashMap getTagNameMap(); |
// CONSTRUCTORS |
/** |
* Creates a new Directory. |
*/ |
public Directory() |
{ |
_tagMap = new HashMap(); |
_definedTagList = new ArrayList(); |
} |
// VARIOUS METHODS |
/** |
* Indicates whether the specified tag type has been set. |
* @param tagType the tag type to check for |
* @return true if a value exists for the specified tag type, false if not |
*/ |
public boolean containsTag(int tagType) |
{ |
return _tagMap.containsKey(new Integer(tagType)); |
} |
/** |
* Returns an Iterator of Tag instances that have been set in this Directory. |
* @return an Iterator of Tag instances |
*/ |
public Iterator getTagIterator() |
{ |
return _definedTagList.iterator(); |
} |
/** |
* Returns the number of tags set in this Directory. |
* @return the number of tags set in this Directory |
*/ |
public int getTagCount() |
{ |
return _definedTagList.size(); |
} |
/** |
* Sets the descriptor used to interperet tag values. |
* @param descriptor the descriptor used to interperet tag values |
*/ |
public void setDescriptor(TagDescriptor descriptor) |
{ |
if (descriptor==null) { |
throw new NullPointerException("cannot set a null descriptor"); |
} |
_descriptor = descriptor; |
} |
public void addError(String message) |
{ |
if (_errorList==null) { |
_errorList = new ArrayList(); |
} |
_errorList.add(message); |
} |
public boolean hasErrors() |
{ |
return (_errorList!=null && _errorList.size()>0); |
} |
public Iterator getErrors() |
{ |
return _errorList.iterator(); |
} |
public int getErrorCount() |
{ |
return _errorList.size(); |
} |
// TAG SETTERS |
/** |
* Sets an int value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as an int |
*/ |
public void setInt(int tagType, int value) |
{ |
setObject(tagType, new Integer(value)); |
} |
/** |
* Sets a double value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a double |
*/ |
public void setDouble(int tagType, double value) |
{ |
setObject(tagType, new Double(value)); |
} |
/** |
* Sets a float value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a float |
*/ |
public void setFloat(int tagType, float value) |
{ |
setObject(tagType, new Float(value)); |
} |
/** |
* Sets an int value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a String |
*/ |
public void setString(int tagType, String value) |
{ |
setObject(tagType, value); |
} |
/** |
* Sets an int value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a boolean |
*/ |
public void setBoolean(int tagType, boolean value) |
{ |
setObject(tagType, new Boolean(value)); |
} |
/** |
* Sets a long value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a long |
*/ |
public void setLong(int tagType, long value) |
{ |
setObject(tagType, new Long(value)); |
} |
/** |
* Sets a java.util.Date value for the specified tag. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag as a java.util.Date |
*/ |
public void setDate(int tagType, java.util.Date value) |
{ |
setObject(tagType, value); |
} |
/** |
* Sets a Rational value for the specified tag. |
* @param tagType the tag's value as an int |
* @param rational rational number |
*/ |
public void setRational(int tagType, Rational rational) |
{ |
setObject(tagType, rational); |
} |
/** |
* Sets a Rational array for the specified tag. |
* @param tagType the tag identifier |
* @param rationals the Rational array to store |
*/ |
public void setRationalArray(int tagType, Rational[] rationals) |
{ |
setObjectArray(tagType, rationals); |
} |
/** |
* Sets an int array for the specified tag. |
* @param tagType the tag identifier |
* @param ints the int array to store |
*/ |
public void setIntArray(int tagType, int[] ints) |
{ |
setObjectArray(tagType, ints); |
} |
/** |
* Sets a byte array for the specified tag. |
* @param tagType the tag identifier |
* @param bytes the byte array to store |
*/ |
public void setByteArray(int tagType, byte[] bytes) |
{ |
setObjectArray(tagType, bytes); |
} |
/** |
* Sets a String array for the specified tag. |
* @param tagType the tag identifier |
* @param strings the String array to store |
*/ |
public void setStringArray(int tagType, String[] strings) |
{ |
setObjectArray(tagType, strings); |
} |
/** |
* Private helper method, containing common functionality for all 'add' |
* methods. |
* @param tagType the tag's value as an int |
* @param value the value for the specified tag |
* @throws NullPointerException if value is <code>null</code> |
*/ |
public void setObject(int tagType, Object value) |
{ |
if (value==null) { |
throw new NullPointerException("cannot set a null object"); |
} |
Integer key = new Integer(tagType); |
if (!_tagMap.containsKey(key)) { |
_definedTagList.add(new Tag(tagType, this)); |
} |
_tagMap.put(key, value); |
} |
/** |
* Private helper method, containing common functionality for all 'add...Array' |
* methods. |
* @param tagType the tag's value as an int |
* @param array the array of values for the specified tag |
*/ |
public void setObjectArray(int tagType, Object array) |
{ |
// for now, we don't do anything special -- this method might be a candidate for removal once the dust settles |
setObject(tagType, array); |
} |
// TAG GETTERS |
/** |
* Returns the specified tag's value as an int, if possible. |
*/ |
public int getInt(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof String) { |
try { |
return Integer.parseInt((String)o); |
} catch (NumberFormatException nfe) { |
// convert the char array to an int |
String s = (String)o; |
byte[] bytes = s.getBytes(); |
long val = 0; |
for (int i = 0; i < bytes.length; i++) { |
val = val << 8; |
val += bytes[i]; |
} |
return (int)val; |
} |
} else if (o instanceof Number) { |
return ((Number)o).intValue(); |
} else if (o instanceof Rational[]) { |
Rational[] rationals = (Rational[])o; |
if (rationals.length==1) |
return rationals[0].intValue(); |
} else if (o instanceof byte[]) { |
byte[] bytes = (byte[])o; |
if (bytes.length==1) |
return bytes[0]; |
} else if (o instanceof int[]) { |
int[] ints = (int[])o; |
if (ints.length==1) |
return ints[0]; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to int. It is of type '" + o.getClass() + "'."); |
} |
// TODO get Array methods need to return cloned data, to maintain this directory's integrity |
/** |
* Gets the specified tag's value as a String array, if possible. Only supported |
* where the tag is set as String[], String, int[], byte[] or Rational[]. |
* @param tagType the tag identifier |
* @return the tag's value as an array of Strings |
* @throws MetadataException if the tag has not been set or cannot be represented |
* as a String[] |
*/ |
public String[] getStringArray(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof String[]) { |
return (String[])o; |
} else if (o instanceof String) { |
String[] strings = {(String)o}; |
return strings; |
} else if (o instanceof int[]) { |
int[] ints = (int[])o; |
String[] strings = new String[ints.length]; |
for (int i = 0; i<strings.length; i++) { |
strings[i] = Integer.toString(ints[i]); |
} |
return strings; |
} else if (o instanceof byte[]) { |
byte[] bytes = (byte[])o; |
String[] strings = new String[bytes.length]; |
for (int i = 0; i<strings.length; i++) { |
strings[i] = Byte.toString(bytes[i]); |
} |
return strings; |
} else if (o instanceof Rational[]) { |
Rational[] rationals = (Rational[])o; |
String[] strings = new String[rationals.length]; |
for (int i = 0; i<strings.length; i++) { |
strings[i] = rationals[i].toSimpleString(false); |
} |
return strings; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to an String array. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Gets the specified tag's value as an int array, if possible. Only supported |
* where the tag is set as String, int[], byte[] or Rational[]. |
* @param tagType the tag identifier |
* @return the tag's value as an int array |
* @throws MetadataException if the tag has not been set, or cannot be converted to |
* an int array |
*/ |
public int[] getIntArray(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof Rational[]) { |
Rational[] rationals = (Rational[])o; |
int[] ints = new int[rationals.length]; |
for (int i = 0; i<ints.length; i++) { |
ints[i] = rationals[i].intValue(); |
} |
return ints; |
} else if (o instanceof int[]) { |
return (int[])o; |
} else if (o instanceof byte[]) { |
byte[] bytes = (byte[])o; |
int[] ints = new int[bytes.length]; |
for (int i = 0; i<bytes.length; i++) { |
byte b = bytes[i]; |
ints[i] = b; |
} |
return ints; |
} else if (o instanceof String) { |
String str = (String)o; |
int[] ints = new int[str.length()]; |
for (int i = 0; i<str.length(); i++) { |
ints[i] = str.charAt(i); |
} |
return ints; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to an int array. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Gets the specified tag's value as an byte array, if possible. Only supported |
* where the tag is set as String, int[], byte[] or Rational[]. |
* @param tagType the tag identifier |
* @return the tag's value as a byte array |
* @throws MetadataException if the tag has not been set, or cannot be converted to |
* a byte array |
*/ |
public byte[] getByteArray(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof Rational[]) { |
Rational[] rationals = (Rational[])o; |
byte[] bytes = new byte[rationals.length]; |
for (int i = 0; i<bytes.length; i++) { |
bytes[i] = rationals[i].byteValue(); |
} |
return bytes; |
} else if (o instanceof byte[]) { |
return (byte[])o; |
} else if (o instanceof int[]) { |
int[] ints = (int[])o; |
byte[] bytes = new byte[ints.length]; |
for (int i = 0; i<ints.length; i++) { |
bytes[i] = (byte)ints[i]; |
} |
return bytes; |
} else if (o instanceof String) { |
String str = (String)o; |
byte[] bytes = new byte[str.length()]; |
for (int i = 0; i<str.length(); i++) { |
bytes[i] = (byte)str.charAt(i); |
} |
return bytes; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a byte array. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a double, if possible. |
*/ |
public double getDouble(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof String) { |
try { |
return Double.parseDouble((String)o); |
} catch (NumberFormatException nfe) { |
throw new MetadataException("unable to parse string " + o + " as a double", nfe); |
} |
} else if (o instanceof Number) { |
return ((Number)o).doubleValue(); |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a double. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a float, if possible. |
*/ |
public float getFloat(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof String) { |
try { |
return Float.parseFloat((String)o); |
} catch (NumberFormatException nfe) { |
throw new MetadataException("unable to parse string " + o + " as a float", nfe); |
} |
} else if (o instanceof Number) { |
return ((Number)o).floatValue(); |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a float. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a long, if possible. |
*/ |
public long getLong(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof String) { |
try { |
return Long.parseLong((String)o); |
} catch (NumberFormatException nfe) { |
throw new MetadataException("unable to parse string " + o + " as a long", nfe); |
} |
} else if (o instanceof Number) { |
return ((Number)o).longValue(); |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a long. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a boolean, if possible. |
*/ |
public boolean getBoolean(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof Boolean) { |
return ((Boolean)o).booleanValue(); |
} else if (o instanceof String) { |
try { |
return Boolean.getBoolean((String)o); |
} catch (NumberFormatException nfe) { |
throw new MetadataException("unable to parse string " + o + " as a boolean", nfe); |
} |
} else if (o instanceof Number) { |
return (((Number)o).doubleValue()!=0); |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a boolean. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a java.util.Date, if possible. |
*/ |
public java.util.Date getDate(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof java.util.Date) { |
return (java.util.Date)o; |
} else if (o instanceof String) { |
// add new dateformat strings to make this method even smarter |
// so far, this seems to cover all known date strings |
// (for example, AM and PM strings are not supported...) |
String datePatterns[] = { |
"yyyy:MM:dd HH:mm:ss", |
"yyyy:MM:dd HH:mm", |
"yyyy-MM-dd HH:mm:ss", |
"yyyy-MM-dd HH:mm"}; |
String dateString = (String)o; |
for (int i = 0; i<datePatterns.length; i++) { |
try { |
DateFormat parser = new java.text.SimpleDateFormat(datePatterns[i]); |
return parser.parse(dateString); |
} catch (java.text.ParseException ex) { |
// simply try the next pattern |
} |
} |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a java.util.Date. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a Rational, if possible. |
*/ |
public Rational getRational(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof Rational) { |
return (Rational)o; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational. It is of type '" + o.getClass() + "'."); |
} |
public Rational[] getRationalArray(int tagType) throws MetadataException |
{ |
Object o = getObject(tagType); |
if (o==null) { |
throw new MetadataException("Tag " + getTagName(tagType) + " has not been set -- check using containsTag() first"); |
} else if (o instanceof Rational[]) { |
return (Rational[])o; |
} |
throw new MetadataException("Tag '" + tagType + "' cannot be cast to a Rational array. It is of type '" + o.getClass() + "'."); |
} |
/** |
* Returns the specified tag's value as a String. This value is the 'raw' value. A more presentable decoding |
* of this value may be obtained from the corresponding Descriptor. |
* @return the String reprensentation of the tag's value, or |
* <code>null</code> if the tag hasn't been defined. |
*/ |
public String getString(int tagType) |
{ |
Object o = getObject(tagType); |
if (o==null) |
return null; |
if (o instanceof Rational) |
return ((Rational)o).toSimpleString(true); |
if (o.getClass().isArray()) |
{ |
// handle arrays of objects and primitives |
int arrayLength = Array.getLength(o); |
// determine if this is an array of objects i.e. [Lcom.drew.blah |
boolean isObjectArray = o.getClass().toString().startsWith("class [L"); |
StringBuffer sbuffer = new StringBuffer(); |
for (int i = 0; i<arrayLength; i++) |
{ |
if (i!=0) |
sbuffer.append(' '); |
if (isObjectArray) |
sbuffer.append(Array.get(o, i).toString()); |
else |
sbuffer.append(Array.getInt(o, i)); |
} |
return sbuffer.toString(); |
} |
return o.toString(); |
} |
/** |
* Returns the object hashed for the particular tag type specified, if available. |
* @param tagType the tag type identifier |
* @return the tag's value as an Object if available, else null |
*/ |
public Object getObject(int tagType) |
{ |
return _tagMap.get(new Integer(tagType)); |
} |
// OTHER METHODS |
/** |
* Returns the name of a specified tag as a String. |
* @param tagType the tag type identifier |
* @return the tag's name as a String |
*/ |
public String getTagName(int tagType) |
{ |
Integer key = new Integer(tagType); |
HashMap nameMap = getTagNameMap(); |
if (!nameMap.containsKey(key)) { |
String hex = Integer.toHexString(tagType); |
while (hex.length()<4) { |
hex = "0" + hex; |
} |
return "Unknown tag (0x" + hex + ")"; |
} |
return (String)nameMap.get(key); |
} |
/** |
* Provides a description of a tag's value using the descriptor set by |
* <code>setDescriptor(Descriptor)</code>. |
* @param tagType the tag type identifier |
* @return the tag value's description as a String |
* @throws MetadataException if a descriptor hasn't been set, or if an error |
* occurs during calculation of the description within the Descriptor |
*/ |
public String getDescription(int tagType) throws MetadataException |
{ |
if (_descriptor==null) { |
throw new MetadataException("a descriptor must be set using setDescriptor(...) before descriptions can be provided"); |
} |
return _descriptor.getDescription(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegComponent.java |
---|
0,0 → 1,81 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Oct 9, 17:04:07 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.metadata.MetadataException; |
import java.io.Serializable; |
/** |
* Created by IntelliJ IDEA. |
* User: dnoakes |
* Date: 09-Oct-2003 |
* Time: 17:04:07 |
* To change this template use Options | File Templates. |
*/ |
public class JpegComponent implements Serializable |
{ |
private final int _componentId; |
private final int _samplingFactorByte; |
private final int _quantizationTableNumber; |
public JpegComponent(int componentId, int samplingFactorByte, int quantizationTableNumber) |
{ |
_componentId = componentId; |
_samplingFactorByte = samplingFactorByte; |
_quantizationTableNumber = quantizationTableNumber; |
} |
public int getComponentId() |
{ |
return _componentId; |
} |
public String getComponentName() throws MetadataException |
{ |
switch (_componentId) |
{ |
case 1: |
return "Y"; |
case 2: |
return "Cb"; |
case 3: |
return "Cr"; |
case 4: |
return "I"; |
case 5: |
return "Q"; |
} |
throw new MetadataException("Unsupported component id: " + _componentId); |
} |
public int getQuantizationTableNumber() |
{ |
return _quantizationTableNumber; |
} |
public int getHorizontalSamplingFactor() |
{ |
return _samplingFactorByte & 0x0F; |
} |
public int getVerticalSamplingFactor() |
{ |
return (_samplingFactorByte>>4) & 0x0F; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegReader.java |
---|
0,0 → 1,146 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Aug 2, 2003 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.MetadataReader; |
import java.io.File; |
import java.io.InputStream; |
/** |
* |
* @author Darrell Silver http://www.darrellsilver.com and Drew Noakes |
*/ |
public class JpegReader implements MetadataReader |
{ |
/** |
* The SOF0 data segment. |
*/ |
private final byte[] _data; |
/** |
* Creates a new JpegReader for the specified Jpeg jpegFile. |
*/ |
public JpegReader(File jpegFile) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_SOF0)); |
} |
/** Creates a JpegReader for a JPEG stream. |
* |
* @param is JPEG stream. Stream will be closed. |
*/ |
public JpegReader(InputStream is) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD)); |
} |
public JpegReader(byte[] data) |
{ |
_data = data; |
} |
/** |
* Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>. |
*/ |
public Metadata extract() |
{ |
return extract(new Metadata()); |
} |
/** |
* Performs the Jpeg data extraction, adding found values to the specified |
* instance of <code>Metadata</code>. |
*/ |
public Metadata extract(Metadata metadata) |
{ |
if (_data==null) { |
return metadata; |
} |
JpegDirectory directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class); |
try { |
// data precision |
int dataPrecision = get16Bits(JpegDirectory.TAG_JPEG_DATA_PRECISION); |
directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, dataPrecision); |
// process height |
int height = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT); |
directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, height); |
// process width |
int width = get32Bits(JpegDirectory.TAG_JPEG_IMAGE_WIDTH); |
directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, width); |
// number of components |
int numberOfComponents = get16Bits(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS); |
directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, numberOfComponents); |
// for each component, there are three bytes of data: |
// 1 - Component ID: 1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q |
// 2 - Sampling factors: bit 0-3 vertical, 4-7 horizontal |
// 3 - Quantization table number |
int offset = 6; |
for (int i=0; i<numberOfComponents; i++) |
{ |
int componentId = get16Bits(offset++); |
int samplingFactorByte = get16Bits(offset++); |
int quantizationTableNumber = get16Bits(offset++); |
JpegComponent component = new JpegComponent(componentId, samplingFactorByte, quantizationTableNumber); |
directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + i, component); |
} |
} catch (MetadataException me) { |
directory.addError("MetadataException: " + me); |
} |
return metadata; |
} |
/** |
* Returns an int calculated from two bytes of data at the specified offset (MSB, LSB). |
* @param offset position within the data buffer to read first byte |
* @return the 32 bit int value, between 0x0000 and 0xFFFF |
*/ |
private int get32Bits(int offset) throws MetadataException |
{ |
if (offset+1>=_data.length) { |
throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer"); |
} |
return ((_data[offset] & 255) << 8) | (_data[offset + 1] & 255); |
} |
/** |
* Returns an int calculated from one byte of data at the specified offset. |
* @param offset position within the data buffer to read byte |
* @return the 16 bit int value, between 0x00 and 0xFF |
*/ |
private int get16Bits(int offset) throws MetadataException |
{ |
if (offset>=_data.length) { |
throw new MetadataException("Attempt to read bytes from outside Jpeg segment data buffer"); |
} |
return (_data[offset] & 255); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegDirectory.java |
---|
0,0 → 1,111 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on Aug 2, 2003. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import java.util.HashMap; |
/** |
* Directory of tags and values for the SOF0 Jpeg segment. This segment holds basic metadata about the image. |
* @author Darrell Silver http://www.darrellsilver.com and Drew Noakes |
*/ |
public class JpegDirectory extends Directory { |
/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */ |
public static final int TAG_JPEG_DATA_PRECISION = 0; |
/** The image's height. Necessary for decoding the image, so it should always be there. */ |
public static final int TAG_JPEG_IMAGE_HEIGHT = 1; |
/** The image's width. Necessary for decoding the image, so it should always be there. */ |
public static final int TAG_JPEG_IMAGE_WIDTH = 3; |
/** Usually 1 = grey scaled, 3 = color YcbCr or YIQ, 4 = color CMYK |
* Each component TAG_COMPONENT_DATA_[1-4], has the following meaning: |
* component Id(1byte)(1 = Y, 2 = Cb, 3 = Cr, 4 = I, 5 = Q), |
* sampling factors (1byte) (bit 0-3 vertical., 4-7 horizontal.), |
* quantization table number (1 byte). |
* <p> |
* This info is from http://www.funducode.com/freec/Fileformats/format3/format3b.htm |
*/ |
public static final int TAG_JPEG_NUMBER_OF_COMPONENTS = 5; |
// NOTE! Component tag type int values must increment in steps of 1 |
/** the first of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/ |
public static final int TAG_JPEG_COMPONENT_DATA_1 = 6; |
/** the second of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/ |
public static final int TAG_JPEG_COMPONENT_DATA_2 = 7; |
/** the third of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/ |
public static final int TAG_JPEG_COMPONENT_DATA_3 = 8; |
/** the fourth of a possible 4 color components. Number of components specified in TAG_JPEG_NUMBER_OF_COMPONENTS.*/ |
public static final int TAG_JPEG_COMPONENT_DATA_4 = 9; |
protected static final HashMap tagNameMap = new HashMap(); |
static { |
tagNameMap.put(new Integer(TAG_JPEG_DATA_PRECISION), "Data Precision"); |
tagNameMap.put(new Integer(TAG_JPEG_IMAGE_WIDTH), "Image Width"); |
tagNameMap.put(new Integer(TAG_JPEG_IMAGE_HEIGHT), "Image Height"); |
tagNameMap.put(new Integer(TAG_JPEG_NUMBER_OF_COMPONENTS), "Number of Components"); |
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_1), "Component 1"); |
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_2), "Component 2"); |
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_3), "Component 3"); |
tagNameMap.put(new Integer(TAG_JPEG_COMPONENT_DATA_4), "Component 4"); |
} |
public JpegDirectory() { |
this.setDescriptor(new JpegDescriptor(this)); |
} |
public String getName() { |
return "Jpeg"; |
} |
protected HashMap getTagNameMap() { |
return tagNameMap; |
} |
/** |
* |
* @param componentNumber The zero-based index of the component. This number is normally between 0 and 3. |
* Use getNumberOfComponents for bounds-checking. |
* @return |
*/ |
public JpegComponent getComponent(int componentNumber) |
{ |
int tagType = JpegDirectory.TAG_JPEG_COMPONENT_DATA_1 + componentNumber; |
JpegComponent component = (JpegComponent)getObject(tagType); |
return component; |
} |
public int getImageWidth() throws MetadataException |
{ |
return getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH); |
} |
public int getImageHeight() throws MetadataException |
{ |
return getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT); |
} |
public int getNumberOfComponents() throws MetadataException |
{ |
return getInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentReader.java |
---|
0,0 → 1,84 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.MetadataReader; |
import java.io.File; |
import java.io.InputStream; |
/** |
* |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class JpegCommentReader implements MetadataReader |
{ |
/** |
* The COM data segment. |
*/ |
private final byte[] _data; |
/** |
* Creates a new JpegReader for the specified Jpeg jpegFile. |
*/ |
public JpegCommentReader(File jpegFile) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(jpegFile).readSegment(JpegSegmentReader.SEGMENT_COM)); |
} |
/** Creates a JpegCommentReader for a JPEG stream. |
* |
* @param is JPEG stream. Stream will be closed. |
*/ |
public JpegCommentReader(InputStream is) throws JpegProcessingException |
{ |
this(new JpegSegmentReader(is).readSegment(JpegSegmentReader.SEGMENT_APPD)); |
} |
public JpegCommentReader(byte[] data) |
{ |
_data = data; |
} |
/** |
* Performs the Jpeg data extraction, returning a new instance of <code>Metadata</code>. |
*/ |
public Metadata extract() |
{ |
return extract(new Metadata()); |
} |
/** |
* Performs the Jpeg data extraction, adding found values to the specified |
* instance of <code>Metadata</code>. |
*/ |
public Metadata extract(Metadata metadata) |
{ |
if (_data==null) { |
return metadata; |
} |
JpegCommentDirectory directory = (JpegCommentDirectory)metadata.getDirectory(JpegCommentDirectory.class); |
directory.setString(JpegCommentDirectory.TAG_JPEG_COMMENT, new String(_data)); |
return metadata; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentDirectory.java |
---|
0,0 → 1,49 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.metadata.Directory; |
import java.util.HashMap; |
/** |
* |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class JpegCommentDirectory extends Directory { |
/** This is in bits/sample, usually 8 (12 and 16 not supported by most software). */ |
public static final int TAG_JPEG_COMMENT = 0; |
protected static final HashMap tagNameMap = new HashMap(); |
static { |
tagNameMap.put(new Integer(TAG_JPEG_COMMENT), "Jpeg Comment"); |
} |
public JpegCommentDirectory() { |
this.setDescriptor(new JpegCommentDescriptor(this)); |
} |
public String getName() { |
return "JpegComment"; |
} |
protected HashMap getTagNameMap() { |
return tagNameMap; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegDescriptorTest.java |
---|
0,0 → 1,82 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes 09-Oct-2003 15:22:23 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg.test; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.jpeg.JpegComponent; |
import com.drew.metadata.jpeg.JpegDescriptor; |
import com.drew.metadata.jpeg.JpegDirectory; |
import junit.framework.TestCase; |
/** |
* |
*/ |
public class JpegDescriptorTest extends TestCase |
{ |
private JpegDirectory _directory; |
private JpegDescriptor _descriptor; |
public JpegDescriptorTest(String s) |
{ |
super(s); |
} |
public void setUp() throws Exception |
{ |
_directory = new JpegDirectory(); |
_descriptor = new JpegDescriptor(_directory); |
} |
public void testGetComponentDataDescription_InvalidComponentNumber() throws Exception |
{ |
try { |
_descriptor.getComponentDataDescription(1); |
fail("Excepted exception"); |
} catch (MetadataException e) { |
// expect exception |
} |
} |
public void testGetImageWidthDescription() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, 123); |
assertEquals("123 pixels", _descriptor.getImageWidthDescription()); |
assertEquals("123 pixels", _directory.getDescription(JpegDirectory.TAG_JPEG_IMAGE_WIDTH)); |
} |
public void testGetImageHeightDescription() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, 123); |
assertEquals("123 pixels", _descriptor.getImageHeightDescription()); |
assertEquals("123 pixels", _directory.getDescription(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT)); |
} |
public void testGetDataPrecisionDescription() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_DATA_PRECISION, 8); |
assertEquals("8 bits", _descriptor.getDataPrecisionDescription()); |
assertEquals("8 bits", _directory.getDescription(JpegDirectory.TAG_JPEG_DATA_PRECISION)); |
} |
public void testGetComponentDescription() throws MetadataException |
{ |
JpegComponent component1 = new JpegComponent(1, 0x22, 0); |
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1, component1); |
assertEquals("Y component: Quantization table 0, Sampling factors 2 horiz/2 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1)); |
assertEquals("Y component: Quantization table 0, Sampling factors 2 horiz/2 vert", _descriptor.getComponentDataDescription(0)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegComponentTest.java |
---|
0,0 → 1,51 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg.test; |
import com.drew.metadata.jpeg.JpegComponent; |
import junit.framework.TestCase; |
/** |
* |
*/ |
public class JpegComponentTest extends TestCase |
{ |
public JpegComponentTest(String s) |
{ |
super(s); |
} |
public void testGetComponentCharacter() throws Exception |
{ |
JpegComponent component; |
component = new JpegComponent(1,2,3); |
assertEquals("Y", component.getComponentName()); |
component = new JpegComponent(2,2,3); |
assertEquals("Cb", component.getComponentName()); |
component = new JpegComponent(3,2,3); |
assertEquals("Cr", component.getComponentName()); |
component = new JpegComponent(4,2,3); |
assertEquals("I", component.getComponentName()); |
component = new JpegComponent(5,2,3); |
assertEquals("Q", component.getComponentName()); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegReaderTest.java |
---|
0,0 → 1,150 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg.test; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.metadata.Metadata; |
import com.drew.metadata.jpeg.JpegComponent; |
import com.drew.metadata.jpeg.JpegDirectory; |
import com.drew.metadata.jpeg.JpegReader; |
import junit.framework.TestCase; |
import java.io.File; |
import java.io.FileNotFoundException; |
/** |
* |
*/ |
public class JpegReaderTest extends TestCase |
{ |
private JpegDirectory _directory; |
public JpegReaderTest(String s) |
{ |
super(s); |
} |
public void setUp() throws JpegProcessingException, FileNotFoundException |
{ |
// use a known testing image |
File jpegFile = new File("src/com/drew/metadata/jpeg/test/simple.jpg"); |
JpegReader reader = new JpegReader(jpegFile); |
Metadata metadata = reader.extract(); |
assertTrue(metadata.containsDirectory(JpegDirectory.class)); |
_directory = (JpegDirectory)metadata.getDirectory(JpegDirectory.class); |
} |
public void testExtract_Width() throws Exception |
{ |
assertEquals(800, _directory.getInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH)); |
} |
public void testExtract_Height() throws Exception |
{ |
assertEquals(600, _directory.getInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT)); |
} |
public void testExtract_DataPrecision() throws Exception |
{ |
assertEquals(8, _directory.getInt(JpegDirectory.TAG_JPEG_DATA_PRECISION)); |
} |
public void testExtract_NumberOfComponents() throws Exception |
{ |
assertEquals(3, _directory.getInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS)); |
} |
public void testComponentData1() throws Exception |
{ |
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1); |
assertEquals("Y", component.getComponentName()); |
assertEquals(1, component.getComponentId()); |
assertEquals(0, component.getQuantizationTableNumber()); |
assertEquals(2, component.getHorizontalSamplingFactor()); |
assertEquals(2, component.getVerticalSamplingFactor()); |
} |
public void testComponentData2() throws Exception |
{ |
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2); |
assertEquals("Cb", component.getComponentName()); |
assertEquals(2, component.getComponentId()); |
assertEquals(1, component.getQuantizationTableNumber()); |
assertEquals(1, component.getHorizontalSamplingFactor()); |
assertEquals(1, component.getVerticalSamplingFactor()); |
assertEquals("Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2)); |
} |
public void testComponentData3() throws Exception |
{ |
JpegComponent component = (JpegComponent)_directory.getObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3); |
assertEquals("Cr", component.getComponentName()); |
assertEquals(3, component.getComponentId()); |
assertEquals(1, component.getQuantizationTableNumber()); |
assertEquals(1, component.getHorizontalSamplingFactor()); |
assertEquals(1, component.getVerticalSamplingFactor()); |
assertEquals("Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert", _directory.getDescription(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3)); |
} |
/* |
// this test is part of an incomplete investigation into extracting audio from JPG files |
public void testJpegWithAudio() throws Exception |
{ |
// use a known testing image |
File jpegFile = new File("src/com/drew/metadata/jpeg/test/audioPresent.jpg"); |
JpegSegmentReader jpegSegmentReader = new JpegSegmentReader(jpegFile); |
byte[] segment1Bytes = jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP2); |
System.out.println(segment1Bytes.length); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1)); |
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP2).length); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP3)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP4)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP5)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP6)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP7)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP8)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APP9)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPA)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPB)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPC)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPE)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_APPF)); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_COM)); |
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_DHT).length); |
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_DQT).length); |
System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_SOF0).length); |
// System.out.println(jpegSegmentReader.readSegment(JpegSegmentReader.SEGMENT_SOI)); |
// write the segment's data out to a wav file... |
File audioFile = new File("src/com/drew/metadata/jpeg/test/audio.wav"); |
FileOutputStream os = null; |
try |
{ |
os = new FileOutputStream(audioFile); |
os.write(segment1Bytes); |
} |
finally |
{ |
if (os!=null) |
os.close(); |
} |
} |
*/ |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/simple.jpg |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/test/JpegDirectoryTest.java |
---|
0,0 → 1,91 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 09-Oct-2003 15:22:23 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg.test; |
import com.drew.metadata.jpeg.JpegComponent; |
import com.drew.metadata.jpeg.JpegDirectory; |
import junit.framework.TestCase; |
/** |
* |
*/ |
public class JpegDirectoryTest extends TestCase |
{ |
private JpegDirectory _directory; |
public JpegDirectoryTest(String s) |
{ |
super(s); |
} |
public void setUp() |
{ |
_directory = new JpegDirectory(); |
} |
public void testSetAndGetValue() throws Exception |
{ |
_directory.setInt(123, 8); |
assertEquals(8, _directory.getInt(123)); |
} |
public void testGetComponent_NotAdded() |
{ |
assertNull(_directory.getComponent(1)); |
} |
// NOTE tests for individual tag values exist in JpegReaderTest.java |
public void testGetImageWidth() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_WIDTH, 123); |
assertEquals(123, _directory.getImageWidth()); |
} |
public void testGetImageHeight() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT, 123); |
assertEquals(123, _directory.getImageHeight()); |
} |
public void testGetNumberOfComponents() throws Exception |
{ |
_directory.setInt(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS, 3); |
assertEquals(3, _directory.getNumberOfComponents()); |
assertEquals("3", _directory.getDescription(JpegDirectory.TAG_JPEG_NUMBER_OF_COMPONENTS)); |
} |
public void testGetComponent() throws Exception |
{ |
JpegComponent component1 = new JpegComponent(1, 2, 3); |
JpegComponent component2 = new JpegComponent(1, 2, 3); |
JpegComponent component3 = new JpegComponent(1, 2, 3); |
JpegComponent component4 = new JpegComponent(1, 2, 3); |
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_1, component1); |
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_2, component2); |
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_3, component3); |
_directory.setObject(JpegDirectory.TAG_JPEG_COMPONENT_DATA_4, component4); |
// component numbers are zero-indexed for this method |
assertSame(component1, _directory.getComponent(0)); |
assertSame(component2, _directory.getComponent(1)); |
assertSame(component3, _directory.getComponent(2)); |
assertSame(component4, _directory.getComponent(3)); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegDescriptor.java |
---|
0,0 → 1,88 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.metadata.Directory; |
import com.drew.metadata.MetadataException; |
import com.drew.metadata.TagDescriptor; |
/** |
* Provides human-readable string versions of the tags stored in a JpegDirectory. |
* Thanks to Darrell Silver (www.darrellsilver.com) for the initial version of this class. |
*/ |
public class JpegDescriptor extends TagDescriptor |
{ |
public JpegDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) throws MetadataException |
{ |
switch (tagType) |
{ |
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_1: |
return getComponentDataDescription(0); |
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_2: |
return getComponentDataDescription(1); |
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_3: |
return getComponentDataDescription(2); |
case JpegDirectory.TAG_JPEG_COMPONENT_DATA_4: |
return getComponentDataDescription(3); |
case JpegDirectory.TAG_JPEG_DATA_PRECISION: |
return getDataPrecisionDescription(); |
case JpegDirectory.TAG_JPEG_IMAGE_HEIGHT: |
return getImageHeightDescription(); |
case JpegDirectory.TAG_JPEG_IMAGE_WIDTH: |
return getImageWidthDescription(); |
} |
return _directory.getString(tagType); |
} |
public String getImageWidthDescription() |
{ |
return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_WIDTH) + " pixels"; |
} |
public String getImageHeightDescription() |
{ |
return _directory.getString(JpegDirectory.TAG_JPEG_IMAGE_HEIGHT) + " pixels"; |
} |
public String getDataPrecisionDescription() |
{ |
return _directory.getString(JpegDirectory.TAG_JPEG_DATA_PRECISION) + " bits"; |
} |
public String getComponentDataDescription(int componentNumber) throws MetadataException |
{ |
JpegComponent component = ((JpegDirectory)_directory).getComponent(componentNumber); |
if (component==null) |
throw new MetadataException("No Jpeg component exists with number " + componentNumber); |
StringBuffer sb = new StringBuffer(); |
sb.append(component.getComponentName()); |
sb.append(" component: Quantization table "); |
sb.append(component.getQuantizationTableNumber()); |
sb.append(", Sampling factors "); |
sb.append(component.getHorizontalSamplingFactor()); |
sb.append(" horiz/"); |
sb.append(component.getVerticalSamplingFactor()); |
sb.append(" vert"); |
return sb.toString(); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/jpeg/JpegCommentDescriptor.java |
---|
0,0 → 1,37 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Oct 10, 2003 using IntelliJ IDEA. |
*/ |
package com.drew.metadata.jpeg; |
import com.drew.metadata.Directory; |
import com.drew.metadata.TagDescriptor; |
/** |
* |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class JpegCommentDescriptor extends TagDescriptor |
{ |
public JpegCommentDescriptor(Directory directory) |
{ |
super(directory); |
} |
public String getDescription(int tagType) |
{ |
return _directory.getString(tagType); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/metadata/SampleUsage.java |
---|
0,0 → 1,140 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 05-Nov-2002 18:57:14 using IntelliJ IDEA. |
*/ |
package com.drew.metadata; |
import com.drew.imaging.jpeg.JpegMetadataReader; |
import com.drew.imaging.jpeg.JpegProcessingException; |
import com.drew.imaging.jpeg.JpegSegmentReader; |
import com.drew.metadata.exif.ExifReader; |
import com.drew.metadata.iptc.IptcReader; |
import com.sun.image.codec.jpeg.JPEGCodec; |
import com.sun.image.codec.jpeg.JPEGDecodeParam; |
import com.sun.image.codec.jpeg.JPEGImageDecoder; |
import java.awt.image.BufferedImage; |
import java.io.File; |
import java.io.FileInputStream; |
import java.io.FileNotFoundException; |
import java.io.IOException; |
import java.util.Iterator; |
/** |
* |
*/ |
public class SampleUsage |
{ |
/** |
* Constructor which executes multiple sample usages, each of which return the same output. This class showcases |
* multiple usages of this metadata class library. |
* @param fileName path to a jpeg file upon which to operate |
*/ |
public SampleUsage(String fileName) |
{ |
File jpegFile = new File(fileName); |
// There are multiple ways to get a Metadata object |
// Approach 1 |
// This approach reads all types of known Jpeg metadata (at present, |
// Exif and Iptc) in a single call. In most cases, this is the most |
// appropriate usage. |
try { |
Metadata metadata = JpegMetadataReader.readMetadata(jpegFile); |
printImageTags(1, metadata); |
} catch (JpegProcessingException e) { |
System.err.println("error 1a"); |
} |
// Approach 2 |
// This approach shows using individual MetadataReader implementations |
// to read a file. This is less efficient than approach 1, as the file |
// is opened and read twice. |
try { |
Metadata metadata = new Metadata(); |
new ExifReader(jpegFile).extract(metadata); |
new IptcReader(jpegFile).extract(metadata); |
printImageTags(2, metadata); |
} catch (JpegProcessingException jpe) { |
System.err.println("error 2a"); |
} |
// Approach 3 |
// As fast as approach 1 (this is what goes on inside the JpegMetadataReader's |
// readMetadata() method), this code is handy if you want to look into other |
// Jpeg segments too. |
try { |
JpegSegmentReader segmentReader = new JpegSegmentReader(jpegFile); |
byte[] exifSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APP1); |
byte[] iptcSegment = segmentReader.readSegment(JpegSegmentReader.SEGMENT_APPD); |
Metadata metadata = new Metadata(); |
new ExifReader(exifSegment).extract(metadata); |
new IptcReader(iptcSegment).extract(metadata); |
printImageTags(3, metadata); |
} catch (JpegProcessingException jpe) { |
System.err.println("error 3a"); |
} |
// Approach 4 |
// This approach is the slowest, because it decodes the Jpeg image. Of |
// course you now have a decoded image to play with. In some instances |
// this will be most appropriate. |
try { |
JPEGImageDecoder jpegDecoder = JPEGCodec.createJPEGDecoder(new FileInputStream(jpegFile)); |
BufferedImage image = jpegDecoder.decodeAsBufferedImage(); |
// now you can use the image |
JPEGDecodeParam decodeParam = jpegDecoder.getJPEGDecodeParam(); |
Metadata metadata = JpegMetadataReader.readMetadata(decodeParam); |
printImageTags(4, metadata); |
} catch (FileNotFoundException e) { |
System.err.println("error 4a"); |
} catch (IOException e) { |
System.err.println("error 4b"); |
} |
} |
private void printImageTags(int approachCount, Metadata metadata) |
{ |
System.out.println(); |
System.out.println("*** APPROACH " + approachCount + " ***"); |
System.out.println(); |
// iterate over the exif data and print to System.out |
Iterator directories = metadata.getDirectoryIterator(); |
while (directories.hasNext()) { |
Directory directory = (Directory)directories.next(); |
Iterator tags = directory.getTagIterator(); |
while (tags.hasNext()) { |
Tag tag = (Tag)tags.next(); |
System.out.println(tag); |
} |
if (directory.hasErrors()) { |
Iterator errors = directory.getErrors(); |
while (errors.hasNext()) { |
System.out.println("ERROR: " + errors.next()); |
} |
} |
} |
} |
/** |
* Executes the sample usage program. |
* @param args command line parameters |
*/ |
public static void main(String[] args) |
{ |
new SampleUsage("src/com/drew/metadata/test/withIptcExifGps.jpg"); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/CompoundException.java |
---|
0,0 → 1,89 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.lang; |
import java.io.PrintStream; |
import java.io.PrintWriter; |
/** |
* Represents a compound exception, as modelled in JDK 1.4, but |
* unavailable in previous versions. This class allows support |
* of these previous JDK versions. |
*/ |
public class CompoundException extends Exception |
{ |
private final Throwable _innnerException; |
public CompoundException(String msg) |
{ |
this(msg, null); |
} |
public CompoundException(Throwable exception) |
{ |
this(null, exception); |
} |
public CompoundException(String msg, Throwable innerException) |
{ |
super(msg); |
_innnerException = innerException; |
} |
public Throwable getInnerException() |
{ |
return _innnerException; |
} |
public String toString() |
{ |
StringBuffer sbuffer = new StringBuffer(); |
sbuffer.append(super.toString()); |
if (_innnerException != null) { |
sbuffer.append("\n"); |
sbuffer.append("--- inner exception ---"); |
sbuffer.append("\n"); |
sbuffer.append(_innnerException.toString()); |
} |
return sbuffer.toString(); |
} |
public void printStackTrace(PrintStream s) |
{ |
super.printStackTrace(s); |
if (_innnerException != null) { |
s.println("--- inner exception ---"); |
_innnerException.printStackTrace(s); |
} |
} |
public void printStackTrace(PrintWriter s) |
{ |
super.printStackTrace(s); |
if (_innnerException != null) { |
s.println("--- inner exception ---"); |
_innnerException.printStackTrace(s); |
} |
} |
public void printStackTrace() |
{ |
super.printStackTrace(); |
if (_innnerException != null) { |
System.err.println("--- inner exception ---"); |
_innnerException.printStackTrace(); |
} |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/NullOutputStream.java |
---|
0,0 → 1,33 |
/** |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Dec 15, 2002 3:30:59 PM using IntelliJ IDEA. |
*/ |
package com.drew.lang; |
import java.io.IOException; |
import java.io.OutputStream; |
public class NullOutputStream extends OutputStream |
{ |
public NullOutputStream() |
{ |
super(); |
} |
public void write(int b) throws IOException |
{ |
// do nothing |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/Rational.java |
---|
0,0 → 1,291 |
/* |
* Rational.java |
* |
* This class is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. Similarly, I release this Java version under the |
* same license, though I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew.noakes@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created on 6 May 2002, 18:06 |
* Updated 26 Aug 2002 by Drew |
* - Added toSimpleString() method, which returns a simplified and hopefully more |
* readable version of the Rational. i.e. 2/10 -> 1/5, and 10/2 -> 5 |
* Modified 29 Oct 2002 (v1.2) |
* - Improved toSimpleString() to factor more complex rational numbers into |
* a simpler form |
* i.e. |
* 10/15 -> 2/3 |
* - toSimpleString() now accepts a boolean flag, 'allowDecimals' which will |
* display the rational number in decimal form if it fits within 5 digits |
* i.e. |
* 3/4 -> 0.75 when allowDecimal == true |
*/ |
package com.drew.lang; |
import java.io.Serializable; |
/** |
* Immutable class for holding a rational number without loss of precision. Provides |
* a familiar representation via toString() in form <code>numerator/denominator</code>. |
* <p> |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class Rational extends java.lang.Number implements Serializable |
{ |
/** |
* Holds the numerator. |
*/ |
private final int numerator; |
/** |
* Holds the denominator. |
*/ |
private final int denominator; |
private int maxSimplificationCalculations = 1000; |
/** |
* Creates a new instance of Rational. Rational objects are immutable, so |
* once you've set your numerator and denominator values here, you're stuck |
* with them! |
*/ |
public Rational(int numerator, int denominator) |
{ |
this.numerator = numerator; |
this.denominator = denominator; |
} |
/** |
* Returns the value of the specified number as a <code>double</code>. |
* This may involve rounding. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>double</code>. |
*/ |
public double doubleValue() |
{ |
return (double)numerator / (double)denominator; |
} |
/** |
* Returns the value of the specified number as a <code>float</code>. |
* This may involve rounding. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>float</code>. |
*/ |
public float floatValue() |
{ |
return (float)numerator / (float)denominator; |
} |
/** |
* Returns the value of the specified number as a <code>byte</code>. |
* This may involve rounding or truncation. This implementation simply |
* casts the result of <code>doubleValue()</code> to <code>byte</code>. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>byte</code>. |
*/ |
public final byte byteValue() |
{ |
return (byte)doubleValue(); |
} |
/** |
* Returns the value of the specified number as an <code>int</code>. |
* This may involve rounding or truncation. This implementation simply |
* casts the result of <code>doubleValue()</code> to <code>int</code>. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>int</code>. |
*/ |
public final int intValue() |
{ |
return (int)doubleValue(); |
} |
/** |
* Returns the value of the specified number as a <code>long</code>. |
* This may involve rounding or truncation. This implementation simply |
* casts the result of <code>doubleValue()</code> to <code>long</code>. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>long</code>. |
*/ |
public final long longValue() |
{ |
return (long)doubleValue(); |
} |
/** |
* Returns the value of the specified number as a <code>short</code>. |
* This may involve rounding or truncation. This implementation simply |
* casts the result of <code>doubleValue()</code> to <code>short</code>. |
* |
* @return the numeric value represented by this object after conversion |
* to type <code>short</code>. |
*/ |
public final short shortValue() |
{ |
return (short)doubleValue(); |
} |
/** |
* Returns the denominator. |
*/ |
public final int getDenominator() |
{ |
return this.denominator; |
} |
/** |
* Returns the numerator. |
*/ |
public final int getNumerator() |
{ |
return this.numerator; |
} |
/** |
* Returns the reciprocal value of this obejct as a new Rational. |
* @return the reciprocal in a new object |
*/ |
public Rational getReciprocal() |
{ |
return new Rational(this.denominator, this.numerator); |
} |
/** |
* Checks if this rational number is an Integer, either positive or negative. |
*/ |
public boolean isInteger() |
{ |
if (denominator == 1 || |
(denominator != 0 && (numerator % denominator == 0)) || |
(denominator == 0 && numerator == 0) |
) { |
return true; |
} else { |
return false; |
} |
} |
/** |
* Returns a string representation of the object of form <code>numerator/denominator</code>. |
* @return a string representation of the object. |
*/ |
public String toString() |
{ |
return numerator + "/" + denominator; |
} |
/** |
* Returns the simplest represenation of this Rational's value possible. |
*/ |
public String toSimpleString(boolean allowDecimal) |
{ |
if (denominator == 0 && numerator != 0) { |
return toString(); |
} else if (isInteger()) { |
return Integer.toString(intValue()); |
} else if (numerator != 1 && denominator % numerator == 0) { |
// common factor between denominator and numerator |
int newDenominator = denominator / numerator; |
return new Rational(1, newDenominator).toSimpleString(allowDecimal); |
} else { |
Rational simplifiedInstance = getSimplifiedInstance(); |
if (allowDecimal) { |
String doubleString = Double.toString(simplifiedInstance.doubleValue()); |
if (doubleString.length() < 5) { |
return doubleString; |
} |
} |
return simplifiedInstance.toString(); |
} |
} |
/** |
* Decides whether a brute-force simplification calculation should be avoided |
* by comparing the maximum number of possible calculations with some threshold. |
* @return true if the simplification should be performed, otherwise false |
*/ |
private boolean tooComplexForSimplification() |
{ |
double maxPossibleCalculations = (((double)(Math.min(denominator, numerator) - 1) / 5d) + 2); |
return maxPossibleCalculations > maxSimplificationCalculations; |
} |
/** |
* Compares two <code>Rational</code> instances, returning true if they are mathematically |
* equivalent. |
* @param obj the Rational to compare this instance to. |
* @return true if instances are mathematically equivalent, otherwise false. Will also |
* return false if <code>obj</code> is not an instance of <code>Rational</code>. |
*/ |
public boolean equals(Object obj) |
{ |
if (!(obj instanceof Rational)) { |
return false; |
} |
Rational that = (Rational)obj; |
return this.doubleValue() == that.doubleValue(); |
} |
/** |
* <p> |
* Simplifies the Rational number.</p> |
* <p> |
* Prime number series: 1, 2, 3, 5, 7, 9, 11, 13, 17</p> |
* <p> |
* To reduce a rational, need to see if both numerator and denominator are divisible |
* by a common factor. Using the prime number series in ascending order guarantees |
* the minimun number of checks required.</p> |
* <p> |
* However, generating the prime number series seems to be a hefty task. Perhaps |
* it's simpler to check if both d & n are divisible by all numbers from 2 -> |
* (Math.min(denominator, numerator) / 2). In doing this, one can check for 2 |
* and 5 once, then ignore all even numbers, and all numbers ending in 0 or 5. |
* This leaves four numbers from every ten to check.</p> |
* <p> |
* Therefore, the max number of pairs of modulus divisions required will be:</p> |
* <code><pre> |
* 4 Math.min(denominator, numerator) - 1 |
* -- * ------------------------------------ + 2 |
* 10 2 |
* |
* Math.min(denominator, numerator) - 1 |
* = ------------------------------------ + 2 |
* 5 |
* </pre></code> |
* @return a simplified instance, or if the Rational could not be simpliffied, |
* returns itself (unchanged) |
*/ |
public Rational getSimplifiedInstance() |
{ |
if (tooComplexForSimplification()) { |
return this; |
} |
for (int factor = 2; factor <= Math.min(denominator, numerator); factor++) { |
if ((factor % 2 == 0 && factor > 2) || (factor % 5 == 0 && factor > 5)) { |
continue; |
} |
if (denominator % factor == 0 && numerator % factor == 0) { |
// found a common factor |
return new Rational(numerator / factor, denominator / factor); |
} |
} |
return this; |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/test/NullOutputStreamTest.java |
---|
0,0 → 1,36 |
/** |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on Dec 15, 2002 3:30:02 PM using IntelliJ IDEA. |
*/ |
package com.drew.lang.test; |
import com.drew.lang.NullOutputStream; |
import junit.framework.TestCase; |
import java.io.OutputStream; |
public class NullOutputStreamTest extends TestCase |
{ |
public NullOutputStreamTest(String s) |
{ |
super(s); |
} |
public void testCreateNullOutputStream() throws Exception |
{ |
OutputStream out = new NullOutputStream(); |
out.write(1); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/test/RationalTest.java |
---|
0,0 → 1,96 |
/* |
* RationalTest.java |
* |
* Test class written by Drew Noakes. |
* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 26-Oct-2002 16:24:43 using IntelliJ IDEA. |
*/ |
package com.drew.lang.test; |
import com.drew.lang.Rational; |
import junit.framework.TestCase; |
/** |
* |
* @author Drew Noakes http://drewnoakes.com |
*/ |
public class RationalTest extends TestCase |
{ |
public RationalTest(String s) |
{ |
super(s); |
} |
public void testCreateRational() throws Exception |
{ |
Rational rational = new Rational(1, 3); |
assertEquals(1, rational.getNumerator()); |
assertEquals(3, rational.getDenominator()); |
assertEquals(new Double(1d / 3d), new Double(rational.doubleValue())); |
} |
public void testToString() throws Exception |
{ |
Rational rational = new Rational(1, 3); |
assertEquals("1/3", rational.toString()); |
} |
public void testToSimpleString() throws Exception |
{ |
Rational third1 = new Rational(1, 3); |
Rational third2 = new Rational(2, 6); |
assertEquals("1/3", third1.toSimpleString(true)); |
assertEquals("1/3", third2.toSimpleString(true)); |
assertEquals(third1, third2); |
Rational twoThirds = new Rational(10, 15); |
assertEquals("2/3", twoThirds.toSimpleString(true)); |
Rational two = new Rational(10, 5); |
assertTrue(two.isInteger()); |
assertEquals("2", two.toSimpleString(true)); |
assertEquals("2", two.toSimpleString(false)); |
Rational twoFifths = new Rational(4, 10); |
assertEquals("0.4", twoFifths.toSimpleString(true)); |
assertEquals("2/5", twoFifths.toSimpleString(false)); |
Rational threeEigths = new Rational(3, 8); |
assertEquals("3/8", threeEigths.toSimpleString(true)); |
Rational zero = new Rational(0, 8); |
assertTrue(zero.isInteger()); |
assertEquals("0", zero.toSimpleString(true)); |
assertEquals("0", zero.toSimpleString(false)); |
zero = new Rational(0, 0); |
assertTrue(zero.isInteger()); |
assertEquals("0", zero.toSimpleString(true)); |
assertEquals("0", zero.toSimpleString(false)); |
// not sure this is a nice presentation of rationals. won't implement it for now. |
// Rational twoAndAHalf = new Rational(10,4); |
// assertEquals("2 1/2", twoAndAHalf.toSimpleString()); |
} |
public void testGetReciprocal() throws Exception |
{ |
Rational rational = new Rational(1, 3); |
Rational reciprocal = rational.getReciprocal(); |
assertEquals("new rational should be reciprocal", new Rational(3, 1), reciprocal); |
assertEquals("origianl reciprocal should remain unchanged", new Rational(1, 3), rational); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/test/TestHelper.java |
---|
0,0 → 1,31 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
*/ |
package com.drew.lang.test; |
import junit.framework.TestCase; |
/** |
* Created by dnoakes on 07-May-2005 11:13:18 using IntelliJ IDEA. |
*/ |
public class TestHelper |
{ |
public static void assertEqualArrays(byte[] array1, byte[] array2) |
{ |
TestCase.assertEquals("Equal array length", array1.length, array2.length); |
for (int i = 0; i<array1.length; i++) |
TestCase.assertEquals("Equal value at index " + i, array1[i], array2[i]); |
} |
} |
//contrib/metadata-extractor/trunk/src/com/drew/lang/test/CompoundExceptionTest.java |
---|
0,0 → 1,74 |
/* |
* This is public domain software - that is, you can do whatever you want |
* with it, and include it software that is licensed under the GNU or the |
* BSD license, or whatever other licence you choose, including proprietary |
* closed source licenses. I do ask that you leave this header in tact. |
* |
* If you make modifications to this code that you think would benefit the |
* wider community, please send me a copy and I'll post it on my site. |
* |
* If you make use of this code, I'd appreciate hearing about it. |
* drew@drewnoakes.com |
* Latest version of this software kept at |
* http://drewnoakes.com/ |
* |
* Created by dnoakes on 10-Dec-2002 12:22:38 using IntelliJ IDEA. |
*/ |
package com.drew.lang.test; |
import com.drew.lang.CompoundException; |
import com.drew.lang.NullOutputStream; |
import junit.framework.TestCase; |
import java.io.IOException; |
import java.io.PrintStream; |
import java.io.PrintWriter; |
/** |
* |
*/ |
public class CompoundExceptionTest extends TestCase |
{ |
public CompoundExceptionTest(String s) |
{ |
super(s); |
} |
public void testUnnestedGetMessage() throws Exception |
{ |
try { |
throw new CompoundException("message"); |
} catch (CompoundException e) { |
assertEquals("message", e.getMessage()); |
} |
} |
public void testNestedGetMessage() throws Exception |
{ |
try { |
try { |
throw new IOException("io"); |
} catch (IOException e) { |
throw new CompoundException("compound", e); |
} |
} catch (CompoundException e) { |
assertEquals("compound", e.getMessage()); |
assertEquals("io", e.getInnerException().getMessage()); |
} |
} |
public void testNoInnerException() throws Exception |
{ |
try { |
throw new CompoundException("message", null); |
} catch (CompoundException e) { |
try { |
PrintStream nullStream = new PrintStream(new NullOutputStream()); |
e.printStackTrace(nullStream); |
e.printStackTrace(new PrintWriter(nullStream)); |
} catch (Exception e1) { |
fail("Exception during printStackTrace for CompoundException with no inner exception"); |
} |
} |
} |
} |
//contrib/metadata-extractor/trunk/Libraries/junit.jar |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
//contrib/metadata-extractor/trunk/build.xml |
---|
0,0 → 1,81 |
<?xml version="1.0"?> |
<project name="metadata-extractor" default="test" basedir="."> |
<description>metadata-extractor for java build file</description> |
<property name="dist" location="Releases"/> |
<property name="build" value="Build"/> |
<property name="src" value="src"/> |
<property name="javadoc" value="javadoc"/> |
<property name="lib" value="Libraries"/> |
<property name="verbose" value="true"/> |
<property name="debug" value="off"/> |
<property name="version" value="2.3.1"/> |
<property name="classpath" value="${lib}/junit.jar"/> |
<target name="clean" description="deletes and recreates the destination directory"> |
<delete verbose="${verbose}" dir="${build}"/> |
<mkdir dir="${build}"/> |
<mkdir dir="${dist}"/> |
</target> |
<target name="compile" description="compile the source"> |
<javac classpath="${classpath}" |
srcdir="${src}" |
destdir="${build}" |
debug="${debug}" |
verbose="${verbose}"/> |
</target> |
<target name="dist-binaries" depends="clean, compile, test" description="generate binary distribution"> |
<jar destfile="${dist}/metadata-extractor-${version}.jar" update="false"> |
<manifest> |
<attribute name="Main-Class" value="com.drew.imaging.jpeg.JpegMetadataReader"/> |
</manifest> |
<fileset dir="${build}" excludes="**/test/*.class" /> |
</jar> |
</target> |
<target name="dist-source" depends="clean, compile, test" description="generate source distribution"> |
<jar destfile="${dist}/metadata-extractor-${version}-src.jar" update="false"> |
<fileset dir="." |
includes="${src}/**/*.java, ${src}/**/*.jpg, ${src}/**/*.metadata, ${lib}/junit.jar, build.xml, ChangeLog.txt"/> |
</jar> |
</target> |
<target name="test" depends="compile" description="run all junit tests"> |
<junit printsummary="yes" fork="yes" haltonfailure="yes"> |
<classpath> |
<pathelement location="${build}"/> |
<pathelement path="${java.class.path}"/> |
</classpath> |
<formatter type="plain"/> |
<test name="com.drew.metadata.test.AllTests"/> |
</junit> |
</target> |
<target name="javadoc" description="generate javadoc documentation"> |
<javadoc |
destdir="${javadoc}" |
defaultexcludes="yes" |
author="true" |
version="true" |
use="true" |
access="protected" |
windowtitle="metadata-extractor javadoc" |
failonerror="true"> |
<bottom><![CDATA[<i>Copyright © 2006 Drew Noakes. All Rights Reserved.</i>]]></bottom> |
<packageset dir="${src}" defaultexcludes="yes"> |
<include name="com/**"/> |
<exclude name="com/**/test"/> |
</packageset> |
</javadoc> |
</target> |
<target name="all" depends="dist-source, dist-binaries, javadoc" description="prepare source and binary distributions, and javadoc"/> |
</project> |
//contrib/metadata-extractor/trunk/META-INF/MANIFEST.MF |
---|
0,0 → 1,4 |
Manifest-Version: 1.0 |
Ant-Version: Apache Ant 1.5.4 |
Created-By: 1.4.2_03-b02 (Sun Microsystems Inc.) |