Subversion Repositories general

Compare Revisions

Ignore whitespace Rev 1267 → Rev 1268

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