Skip to content

Commit 370e6c6

Browse files
committed
Code cleanup and consolidation in the MetadataParser
git-svn-id: svn://192.168.0.80/JavaXT/javaxt-core@207 2c7b0aa6-e0b2-3c4e-bb4a-8b65b6c465ff
1 parent d42d1af commit 370e6c6

File tree

1 file changed

+77
-197
lines changed

1 file changed

+77
-197
lines changed

src/javaxt/io/Image.java

Lines changed: 77 additions & 197 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,34 +1640,29 @@ public IIOMetadataNode[] getMetadataByTagName(String tagName){
16401640
//** MetadataParser Class
16411641
//******************************************************************************
16421642
/**
1643-
* Class used to decode EXIF and IPTC metadata. The MetadataParser is based
1644-
* on two classes developed by Norman Walsh and released under the W3C open
1645-
* source license. The original classes can be found in the W3C Jigsaw
1646-
* project ("Exif.java" and "ExifData.java" in the "org.w3c.tools.jpeg"
1647-
* package).
1648-
* <br/>
1649-
* You may use this code in any open source or commercial project provided
1650-
* that you publish the standard W3C Software Notice and License Agreement.
1643+
* Used to decode EXIF and IPTC metadata. Adapted from 2 classes developed by
1644+
* Norman Walsh and released under the W3C open source license. The original
1645+
* exif classes can be found in the W3C Jigsaw project in the
1646+
* org.w3c.tools.jpeg package.
16511647
*
1652-
* @version $Revision: 1.1 $
1653-
* @author Norman Walsh
1654-
* @copyright Copyright (c) 2003 Norman Walsh
1648+
* @author Norman Walsh
1649+
* @copyright Copyright (c) 2003 Norman Walsh
16551650
******************************************************************************/
16561651

16571652
private class MetadataParser {
16581653

16591654
// Implementation notes:
1660-
// (1) Unknown/Undefined values are all Base64 encoded.
1661-
// (2) Unsigned integers are treated as signed ints (should be longs). Note
1662-
// that its pretty rare to see a EXIF unsigned value too large to represent
1663-
// in a Java int.
1664-
// (3) Added logic to parse GPS Info using the GPS IFD offset value (tag 34853,
1655+
// (1) Merged Version 1.1 of the "Exif.java" and "ExifData.java" classes.
1656+
// (2) Added new IPTC metadata parser.
1657+
// (3) All Unknown/Undefined EXIF fields are Base64 encoded. Need to do the
1658+
// same for unknown IPTC fields.
1659+
// (4) All unsigned integers are treated as signed ints (should be longs).
1660+
// (5) Added logic to parse GPS Info using the GPS IFD offset value (tag 34853,
16651661
// hex 0x8825).
1666-
// (4) Added logic to parse an array of rational numbers (e.g. GPS metadata).
1667-
// (5) Improved performance in the parseExif() method by serializing only the
1662+
// (6) Added logic to parse an array of rational numbers (e.g. GPS metadata).
1663+
// (7) Improved performance in the parseExif() method by serializing only the
16681664
// first 8 characters into a string (vs the entire EXIF byte array).
1669-
// (6) TODO: Need to come up with a clever scheme to parse MakerNotes.
1670-
1665+
// (8) TODO: Need to come up with a clever scheme to parse MakerNotes.
16711666

16721667
private final int bytesPerFormat[] = { 0, 1, 1, 2, 4, 8, 1,
16731668
1, 2, 4, 8, 4, 8 };
@@ -1699,8 +1694,8 @@ private class MetadataParser {
16991694

17001695
public MetadataParser(byte[] data, int marker) {
17011696
switch (marker) {
1702-
case 0xED: parseIptc(data);
1703-
case 0xE1: parseExif(data);
1697+
case 0xED: parseIptc(data); break;
1698+
case 0xE1: parseExif(data); break;
17041699
}
17051700

17061701
data = null;
@@ -1828,8 +1823,6 @@ private void processExifDir(int dirStart, int offsetBase, HashMap<Integer, Strin
18281823

18291824

18301825
int numEntries = get16u(dirStart);
1831-
//System.err.println("EXIF: numEntries: " + numEntries);
1832-
18331826
for (int de = 0; de < numEntries; de++) {
18341827
int dirOffset = dirStart + 2 + (12 * de);
18351828

@@ -1888,116 +1881,60 @@ private void processExifDir(int dirStart, int offsetBase, HashMap<Integer, Strin
18881881
//processExifDir(0, 6);
18891882

18901883
//}
1891-
1892-
1884+
18931885
else {
18941886

18951887
switch (format) {
1896-
case FMT_UNDEFINED:
1897-
assignUndefined(tag, tags, valueOffset, byteCount);
1898-
break;
18991888
case FMT_STRING:
1900-
assignString(tag, tags, valueOffset, byteCount);
1889+
String value = getString(valueOffset, byteCount);
1890+
if (value!=null) tags.put(tag, value);
19011891
break;
19021892
case FMT_SBYTE:
1903-
assignSByte(tag, tags, valueOffset);
1904-
break;
19051893
case FMT_BYTE:
1906-
assignByte(tag, tags, valueOffset);
1907-
break;
19081894
case FMT_USHORT:
1909-
assignUShort(tag, tags, valueOffset);
1910-
break;
19111895
case FMT_SSHORT:
1912-
assignSShort(tag, tags, valueOffset);
1913-
break;
19141896
case FMT_ULONG:
1915-
assignULong(tag, tags, valueOffset);
1916-
break;
19171897
case FMT_SLONG:
1918-
assignSLong(tag, tags, valueOffset);
1898+
tags.put(tag, "" + (int) getDouble(format, valueOffset));
19191899
break;
19201900
case FMT_URATIONAL:
19211901
case FMT_SRATIONAL:
19221902

19231903
if (components>1) {
19241904

19251905
//Create a string representing an array of rational numbers
1926-
StringBuffer rationals = new StringBuffer();
1927-
rationals.append("[");
1928-
for (int i = 0; i < components; i++){
1929-
assignRational(tag, tags, valueOffset + (8 * i));
1930-
rationals.append(tags.get(tag));
1931-
if (i < components-1) rationals.append(",");
1906+
StringBuffer str = new StringBuffer();
1907+
str.append("[");
1908+
for (int i=0; i<components; i++){
1909+
str.append( getRational(valueOffset + (8 * i)) );
1910+
if (i<components-1) str.append(",");
19321911
}
1933-
rationals.append("]");
1934-
tags.put(tag, rationals.toString());
1912+
str.append("]");
1913+
tags.put(tag, str.toString());
19351914
}
19361915
else{
1937-
assignRational(tag, tags, valueOffset);
1916+
tags.put(tag, getRational(valueOffset));
19381917
}
19391918
break;
19401919

1941-
1942-
1943-
default:
1944-
//System.err.println("Unknown format " + format +
1945-
// " for " + tagName);
1920+
1921+
default: //including FMT_UNDEFINED
1922+
String result = javaxt.utils.Base64.encodeBytes(getUndefined(valueOffset, byteCount));
1923+
if (result!=null && result.length()>0) tags.put(tag, result);
1924+
break;
19461925
}
19471926

19481927
}
19491928
}
19501929
}
19511930

1952-
1953-
1954-
private void assignUndefined(int tag, HashMap<Integer, String> tags, int offset, int length) {
1955-
//System.out.println("0x" + Integer.toHexString(tagName));
1956-
1957-
String result = getUndefined(offset, length);
1958-
if (!"".equals(result)) {
1959-
tags.put(tag, result);
1960-
}
1961-
}
1962-
1963-
private void assignString(int tag, HashMap<Integer, String> tags, int offset, int length) {
1964-
String result = getString(offset, length);
1965-
if (!"".equals(result)) {
1966-
tags.put(tag, result);
1967-
}
1968-
}
1969-
1970-
private void assignSByte(int tag, HashMap<Integer, String> tags, int offset) {
1971-
int result = (int) convertAnyValue(FMT_SBYTE, offset);
1972-
tags.put(tag, "" + result);
1973-
}
1974-
1975-
private void assignByte(int tag, HashMap<Integer, String> tags, int offset) {
1976-
int result = (int) convertAnyValue(FMT_BYTE, offset);
1977-
tags.put(tag, "" + result);
1978-
}
1979-
1980-
private void assignUShort(int tag, HashMap<Integer, String> tags, int offset) {
1981-
int result = (int) convertAnyValue(FMT_USHORT, offset);
1982-
tags.put(tag, "" + result);
1983-
}
1984-
1985-
private void assignSShort(int tag, HashMap<Integer, String> tags, int offset) {
1986-
int result = (int) convertAnyValue(FMT_SSHORT, offset);
1987-
tags.put(tag, "" + result);
1988-
}
1989-
1990-
private void assignULong(int tag, HashMap<Integer, String> tags, int offset) {
1991-
int result = (int) convertAnyValue(FMT_ULONG, offset);
1992-
tags.put(tag, "" + result);
1993-
}
1994-
1995-
private void assignSLong(int tag, HashMap<Integer, String> tags, int offset) {
1996-
int result = (int) convertAnyValue(FMT_SLONG, offset);
1997-
tags.put(tag, "" + result);
1998-
}
1999-
2000-
private void assignRational(int tag, HashMap<Integer, String> tags, int offset) {
1931+
//**************************************************************************
1932+
//** getRational
1933+
//**************************************************************************
1934+
/** Returns a string representation of a rational number (numerator and
1935+
* denominator separated with a "/" character).
1936+
*/
1937+
private String getRational(int offset) {
20011938
int num = get32s(offset);
20021939
int den = get32s(offset + 4);
20031940
String result = "";
@@ -2030,16 +1967,10 @@ private void assignRational(int tag, HashMap<Integer, String> tags, int offset)
20301967
} else {
20311968
result = "" + num + "/" + den;
20321969
}
2033-
2034-
2035-
tags.put(tag, "" + result);
1970+
return result;
20361971
}
20371972

20381973
private int get16s(int offset) {
2039-
if (data == null) {
2040-
return 0;
2041-
}
2042-
20431974
int hi, lo;
20441975

20451976
if (intelOrder) {
@@ -2057,20 +1988,11 @@ private int get16s(int offset) {
20571988
}
20581989

20591990
private int get16u(int offset) {
2060-
if (data == null) {
2061-
return 0;
2062-
}
2063-
20641991
int value = get16s(offset);
2065-
value = value & 0xFFFF;
2066-
return value;
1992+
return value & 0xFFFF;
20671993
}
20681994

20691995
private int get32s(int offset) {
2070-
if (data == null) {
2071-
return 0;
2072-
}
2073-
20741996
int n1, n2, n3, n4;
20751997

20761998
if (intelOrder) {
@@ -2085,98 +2007,56 @@ private int get32s(int offset) {
20852007
n4 = data[offset + 3] & 0xFF;
20862008
}
20872009

2088-
int value = (n1 << 24) + (n2 << 16) + (n3 << 8) + n4;
2089-
2090-
return value;
2010+
return (n1 << 24) + (n2 << 16) + (n3 << 8) + n4;
20912011
}
20922012

20932013
private int get32u(int offset) {
2094-
if (data == null) {
2095-
return 0;
2096-
}
2097-
2098-
// I don't know how to represent an unsigned in Java!
2099-
return get32s(offset);
2014+
return get32s(offset); //Should probably return a long instead...
21002015
}
21012016

2102-
/*
2103-
private byte[] getBytes(int offset, int length) {
2104-
if (data == null || length == 0) {
2105-
return null;
2106-
}
2107-
2108-
byte[] raw = new byte[length];
2109-
for (int count = offset; length > 0; count++, length--) {
2110-
raw[count - offset] = data[count];
2111-
}
2112-
2113-
return raw;
2114-
}
2115-
*/
2116-
2117-
2118-
private String getUndefined(int offset, int length) {
2119-
//return getString(offset, length, false);
2120-
return javaxt.utils.Base64.encodeBytes(data, offset, length);
2017+
private byte[] getUndefined(int offset, int length) {
2018+
return java.util.Arrays.copyOfRange(data, offset, offset+length);
21212019
}
21222020

21232021
private String getString(int offset, int length) {
2124-
if (data == null) {
2125-
return "";
2126-
}
2127-
21282022
try{
21292023
return new String(data, offset, length, "UTF-8").trim();
21302024
}
21312025
catch(Exception e){
2132-
return "";
2026+
return null;
21332027
}
21342028
}
21352029

2136-
private double convertAnyValue(int format, int offset) {
2137-
if (data == null) {
2138-
return 0.0;
2139-
}
2140-
2141-
double value = 0.0;
2142-
2030+
//**************************************************************************
2031+
//** getDouble
2032+
//**************************************************************************
2033+
/** Used convert a byte into a double. Note that this method used to be
2034+
* called convertAnyValue().
2035+
*/
2036+
private double getDouble(int format, int offset) {
21432037
switch (format) {
2144-
case FMT_SBYTE:
2145-
value = data[offset];
2146-
break;
2147-
case FMT_BYTE:
2148-
int iValue = data[offset];
2149-
iValue = iValue & 0xFF;
2150-
value = iValue;
2151-
break;
2152-
case FMT_USHORT:
2153-
value = get16u(offset);
2154-
break;
2155-
case FMT_ULONG:
2156-
value = get32u(offset);
2157-
break;
2158-
case FMT_URATIONAL:
2159-
case FMT_SRATIONAL:
2160-
int num = get32s(offset);
2161-
int den = get32s(offset + 4);
2162-
2163-
if (den == 0) {
2164-
value = 0;
2165-
} else {
2166-
value = (double) num / (double) den;
2167-
}
2168-
break;
2169-
case FMT_SSHORT:
2170-
value = get16s(offset);
2171-
break;
2172-
case FMT_SLONG:
2173-
value = get32s(offset);
2174-
break;
2175-
default:
2176-
//System.err.println("Unexpected number format: " + format);
2177-
}
2178-
2179-
return value;
2038+
case FMT_SBYTE:
2039+
return data[offset];
2040+
case FMT_BYTE:
2041+
int iValue = data[offset];
2042+
return iValue & 0xFF;
2043+
case FMT_USHORT:
2044+
return get16u(offset);
2045+
case FMT_ULONG:
2046+
return get32u(offset);
2047+
case FMT_URATIONAL:
2048+
case FMT_SRATIONAL:
2049+
int num = get32s(offset);
2050+
int den = get32s(offset + 4);
2051+
if (den == 0) return 0;
2052+
else return (double) num / (double) den;
2053+
case FMT_SSHORT:
2054+
return get16s(offset);
2055+
case FMT_SLONG:
2056+
return get32s(offset);
2057+
default:
2058+
return 0.0;
2059+
}
21802060
}
21812061
}
21822062

0 commit comments

Comments
 (0)